@copilotkit/aimock 1.44.0 → 1.45.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +42 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.cts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +312 -39
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +313 -40
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +1 -0
  25. package/dist/chaos.js +1 -1
  26. package/dist/cli.cjs +152 -5
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +155 -8
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +132 -71
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +133 -72
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.cjs +62 -4
  37. package/dist/config-loader.cjs.map +1 -1
  38. package/dist/config-loader.d.cts +37 -4
  39. package/dist/config-loader.d.cts.map +1 -1
  40. package/dist/config-loader.d.ts +37 -4
  41. package/dist/config-loader.d.ts.map +1 -1
  42. package/dist/config-loader.js +62 -4
  43. package/dist/config-loader.js.map +1 -1
  44. package/dist/fakes-plugin.cjs +131 -0
  45. package/dist/fakes-plugin.cjs.map +1 -0
  46. package/dist/fakes-plugin.d.cts +23 -0
  47. package/dist/fakes-plugin.d.cts.map +1 -0
  48. package/dist/fakes-plugin.d.ts +23 -0
  49. package/dist/fakes-plugin.d.ts.map +1 -0
  50. package/dist/fakes-plugin.js +127 -0
  51. package/dist/fakes-plugin.js.map +1 -0
  52. package/dist/fixture-loader-services.cjs +1 -1
  53. package/dist/fixture-loader-services.cjs.map +1 -1
  54. package/dist/fixture-loader-services.js +1 -1
  55. package/dist/fixture-loader-services.js.map +1 -1
  56. package/dist/fixture-loader.cjs +389 -27
  57. package/dist/fixture-loader.cjs.map +1 -1
  58. package/dist/fixture-loader.d.cts +47 -3
  59. package/dist/fixture-loader.d.cts.map +1 -1
  60. package/dist/fixture-loader.d.ts +47 -3
  61. package/dist/fixture-loader.d.ts.map +1 -1
  62. package/dist/fixture-loader.js +384 -29
  63. package/dist/fixture-loader.js.map +1 -1
  64. package/dist/gemini-interactions.cjs +250 -52
  65. package/dist/gemini-interactions.cjs.map +1 -1
  66. package/dist/gemini-interactions.d.cts.map +1 -1
  67. package/dist/gemini-interactions.d.ts.map +1 -1
  68. package/dist/gemini-interactions.js +251 -53
  69. package/dist/gemini-interactions.js.map +1 -1
  70. package/dist/gemini.cjs +226 -37
  71. package/dist/gemini.cjs.map +1 -1
  72. package/dist/gemini.d.cts.map +1 -1
  73. package/dist/gemini.d.ts.map +1 -1
  74. package/dist/gemini.js +227 -38
  75. package/dist/gemini.js.map +1 -1
  76. package/dist/helpers.cjs +881 -7
  77. package/dist/helpers.cjs.map +1 -1
  78. package/dist/helpers.d.cts +85 -4
  79. package/dist/helpers.d.cts.map +1 -1
  80. package/dist/helpers.d.ts +85 -4
  81. package/dist/helpers.d.ts.map +1 -1
  82. package/dist/helpers.js +839 -8
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/index.cjs +9 -0
  85. package/dist/index.d.cts +7 -5
  86. package/dist/index.d.ts +7 -5
  87. package/dist/index.js +4 -3
  88. package/dist/jest.cjs +31 -7
  89. package/dist/jest.cjs.map +1 -1
  90. package/dist/jest.d.cts +43 -3
  91. package/dist/jest.d.cts.map +1 -1
  92. package/dist/jest.d.ts +43 -3
  93. package/dist/jest.d.ts.map +1 -1
  94. package/dist/jest.js +33 -9
  95. package/dist/jest.js.map +1 -1
  96. package/dist/journal.cjs +135 -13
  97. package/dist/journal.cjs.map +1 -1
  98. package/dist/journal.d.cts +38 -4
  99. package/dist/journal.d.cts.map +1 -1
  100. package/dist/journal.d.ts +38 -4
  101. package/dist/journal.d.ts.map +1 -1
  102. package/dist/journal.js +135 -13
  103. package/dist/journal.js.map +1 -1
  104. package/dist/live-sanitize.cjs +4 -32
  105. package/dist/live-sanitize.cjs.map +1 -1
  106. package/dist/live-sanitize.js +4 -32
  107. package/dist/live-sanitize.js.map +1 -1
  108. package/dist/llmock.cjs +123 -30
  109. package/dist/llmock.cjs.map +1 -1
  110. package/dist/llmock.d.cts +16 -1
  111. package/dist/llmock.d.cts.map +1 -1
  112. package/dist/llmock.d.ts +16 -1
  113. package/dist/llmock.d.ts.map +1 -1
  114. package/dist/llmock.js +125 -32
  115. package/dist/llmock.js.map +1 -1
  116. package/dist/mcp-fakes-mount.cjs +1 -0
  117. package/dist/mcp-fakes-mount.cjs.map +1 -1
  118. package/dist/mcp-fakes-mount.js +1 -0
  119. package/dist/mcp-fakes-mount.js.map +1 -1
  120. package/dist/mcp-fakes-report.cjs +111 -0
  121. package/dist/mcp-fakes-report.cjs.map +1 -0
  122. package/dist/mcp-fakes-report.d.cts +40 -0
  123. package/dist/mcp-fakes-report.d.cts.map +1 -0
  124. package/dist/mcp-fakes-report.d.ts +40 -0
  125. package/dist/mcp-fakes-report.d.ts.map +1 -0
  126. package/dist/mcp-fakes-report.js +107 -0
  127. package/dist/mcp-fakes-report.js.map +1 -0
  128. package/dist/mcp-fakes.cjs +331 -8
  129. package/dist/mcp-fakes.cjs.map +1 -1
  130. package/dist/mcp-fakes.d.cts +406 -3
  131. package/dist/mcp-fakes.d.cts.map +1 -1
  132. package/dist/mcp-fakes.d.ts +406 -3
  133. package/dist/mcp-fakes.d.ts.map +1 -1
  134. package/dist/mcp-fakes.js +331 -8
  135. package/dist/mcp-fakes.js.map +1 -1
  136. package/dist/mcp-handler.cjs +216 -17
  137. package/dist/mcp-handler.cjs.map +1 -1
  138. package/dist/mcp-handler.d.cts +49 -0
  139. package/dist/mcp-handler.d.cts.map +1 -0
  140. package/dist/mcp-handler.d.ts +49 -0
  141. package/dist/mcp-handler.d.ts.map +1 -0
  142. package/dist/mcp-handler.js +214 -18
  143. package/dist/mcp-handler.js.map +1 -1
  144. package/dist/mcp-mock.cjs +112 -1
  145. package/dist/mcp-mock.cjs.map +1 -1
  146. package/dist/mcp-mock.d.cts +33 -2
  147. package/dist/mcp-mock.d.cts.map +1 -1
  148. package/dist/mcp-mock.d.ts +33 -2
  149. package/dist/mcp-mock.d.ts.map +1 -1
  150. package/dist/mcp-mock.js +112 -1
  151. package/dist/mcp-mock.js.map +1 -1
  152. package/dist/mcp-recorder.cjs +1224 -0
  153. package/dist/mcp-recorder.cjs.map +1 -0
  154. package/dist/mcp-recorder.d.cts +108 -0
  155. package/dist/mcp-recorder.d.cts.map +1 -0
  156. package/dist/mcp-recorder.d.ts +108 -0
  157. package/dist/mcp-recorder.d.ts.map +1 -0
  158. package/dist/mcp-recorder.js +1215 -0
  159. package/dist/mcp-recorder.js.map +1 -0
  160. package/dist/messages.cjs +362 -56
  161. package/dist/messages.cjs.map +1 -1
  162. package/dist/messages.d.cts.map +1 -1
  163. package/dist/messages.d.ts.map +1 -1
  164. package/dist/messages.js +363 -58
  165. package/dist/messages.js.map +1 -1
  166. package/dist/misbehavior.cjs +1523 -0
  167. package/dist/misbehavior.cjs.map +1 -0
  168. package/dist/misbehavior.d.cts +43 -0
  169. package/dist/misbehavior.d.cts.map +1 -0
  170. package/dist/misbehavior.d.ts +43 -0
  171. package/dist/misbehavior.d.ts.map +1 -0
  172. package/dist/misbehavior.js +1511 -0
  173. package/dist/misbehavior.js.map +1 -0
  174. package/dist/ollama.cjs +310 -112
  175. package/dist/ollama.cjs.map +1 -1
  176. package/dist/ollama.d.cts.map +1 -1
  177. package/dist/ollama.d.ts.map +1 -1
  178. package/dist/ollama.js +311 -113
  179. package/dist/ollama.js.map +1 -1
  180. package/dist/openrouter-video.cjs +30 -2
  181. package/dist/openrouter-video.cjs.map +1 -1
  182. package/dist/openrouter-video.d.cts.map +1 -1
  183. package/dist/openrouter-video.d.ts.map +1 -1
  184. package/dist/openrouter-video.js +30 -2
  185. package/dist/openrouter-video.js.map +1 -1
  186. package/dist/record-sanitize.cjs +231 -0
  187. package/dist/record-sanitize.cjs.map +1 -0
  188. package/dist/record-sanitize.js +224 -0
  189. package/dist/record-sanitize.js.map +1 -0
  190. package/dist/recorder.cjs +106 -5
  191. package/dist/recorder.cjs.map +1 -1
  192. package/dist/recorder.d.cts +2 -1
  193. package/dist/recorder.d.cts.map +1 -1
  194. package/dist/recorder.d.ts +2 -1
  195. package/dist/recorder.d.ts.map +1 -1
  196. package/dist/recorder.js +107 -7
  197. package/dist/recorder.js.map +1 -1
  198. package/dist/responses.cjs +667 -171
  199. package/dist/responses.cjs.map +1 -1
  200. package/dist/responses.d.cts +5 -13
  201. package/dist/responses.d.cts.map +1 -1
  202. package/dist/responses.d.ts +5 -13
  203. package/dist/responses.d.ts.map +1 -1
  204. package/dist/responses.js +665 -174
  205. package/dist/responses.js.map +1 -1
  206. package/dist/router.cjs +24 -2
  207. package/dist/router.cjs.map +1 -1
  208. package/dist/router.d.cts.map +1 -1
  209. package/dist/router.d.ts.map +1 -1
  210. package/dist/router.js +25 -4
  211. package/dist/router.js.map +1 -1
  212. package/dist/server.cjs +572 -76
  213. package/dist/server.cjs.map +1 -1
  214. package/dist/server.d.cts.map +1 -1
  215. package/dist/server.d.ts.map +1 -1
  216. package/dist/server.js +574 -78
  217. package/dist/server.js.map +1 -1
  218. package/dist/stream-collapse.cjs +236 -34
  219. package/dist/stream-collapse.cjs.map +1 -1
  220. package/dist/stream-collapse.d.cts +39 -4
  221. package/dist/stream-collapse.d.cts.map +1 -1
  222. package/dist/stream-collapse.d.ts +39 -4
  223. package/dist/stream-collapse.d.ts.map +1 -1
  224. package/dist/stream-collapse.js +235 -35
  225. package/dist/stream-collapse.js.map +1 -1
  226. package/dist/types.cjs.map +1 -1
  227. package/dist/types.d.cts +315 -4
  228. package/dist/types.d.cts.map +1 -1
  229. package/dist/types.d.ts +315 -4
  230. package/dist/types.d.ts.map +1 -1
  231. package/dist/types.js.map +1 -1
  232. package/dist/validate-cli.cjs +36 -4
  233. package/dist/validate-cli.cjs.map +1 -1
  234. package/dist/validate-cli.js +37 -5
  235. package/dist/validate-cli.js.map +1 -1
  236. package/dist/vector-types.d.ts.map +1 -1
  237. package/dist/version.cjs +45 -0
  238. package/dist/version.cjs.map +1 -0
  239. package/dist/version.js +44 -0
  240. package/dist/version.js.map +1 -0
  241. package/dist/vitest.cjs +66 -10
  242. package/dist/vitest.cjs.map +1 -1
  243. package/dist/vitest.d.cts +35 -4
  244. package/dist/vitest.d.cts.map +1 -1
  245. package/dist/vitest.d.ts +35 -4
  246. package/dist/vitest.d.ts.map +1 -1
  247. package/dist/vitest.js +67 -11
  248. package/dist/vitest.js.map +1 -1
  249. package/dist/watcher.cjs +6 -2
  250. package/dist/watcher.cjs.map +1 -1
  251. package/dist/watcher.js +6 -2
  252. package/dist/watcher.js.map +1 -1
  253. package/dist/ws-gemini-live.cjs +210 -101
  254. package/dist/ws-gemini-live.cjs.map +1 -1
  255. package/dist/ws-gemini-live.d.cts +9 -3
  256. package/dist/ws-gemini-live.d.cts.map +1 -1
  257. package/dist/ws-gemini-live.d.ts +9 -3
  258. package/dist/ws-gemini-live.d.ts.map +1 -1
  259. package/dist/ws-gemini-live.js +211 -102
  260. package/dist/ws-gemini-live.js.map +1 -1
  261. package/dist/ws-realtime.cjs +175 -62
  262. package/dist/ws-realtime.cjs.map +1 -1
  263. package/dist/ws-realtime.d.cts +8 -3
  264. package/dist/ws-realtime.d.cts.map +1 -1
  265. package/dist/ws-realtime.d.ts +8 -3
  266. package/dist/ws-realtime.d.ts.map +1 -1
  267. package/dist/ws-realtime.js +176 -63
  268. package/dist/ws-realtime.js.map +1 -1
  269. package/dist/ws-responses.cjs +109 -16
  270. package/dist/ws-responses.cjs.map +1 -1
  271. package/dist/ws-responses.d.cts +8 -12
  272. package/dist/ws-responses.d.cts.map +1 -1
  273. package/dist/ws-responses.d.ts +8 -12
  274. package/dist/ws-responses.d.ts.map +1 -1
  275. package/dist/ws-responses.js +111 -18
  276. package/dist/ws-responses.js.map +1 -1
  277. package/package.json +10 -2
  278. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1,6 +1,7 @@
1
- import { extractOverrides, flattenHeaders, generateToolUseId, getContext, getTestId, isContentWithToolCallsResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, resolveFixtureBlockOutcome, resolveReasoningForModel, resolveResponse, resolveStrictMode, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
1
+ import { InvalidToolArgumentsError, estimatePromptTokens, estimateTokens, extractOverrides, flattenHeaders, generateToolUseId, getContext, getTestId, isCombinedFixtureResponse, isErrorResponse, isJsonObject, isTextResponse, isToolCallResponse, requireEmittedFunctionToolCalls, resolveFixtureBlockOutcome, resolveReasoningForModel, resolveResponse, resolveStrictMode, servedToolArgs, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField, toolArgsForWire } from "./helpers.js";
2
2
  import { writeErrorResponse } from "./sse-writer.js";
3
3
  import { applyChaosAsync } from "./chaos.js";
4
+ import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
4
5
  import { matchFixtureDiagnostic, recordMatchOptions } from "./router.js";
5
6
  import { proxyAndRecord } from "./recorder.js";
6
7
  import { createInterruptionSignal } from "./interruption.js";
@@ -37,13 +38,7 @@ function converseUsage(overrides) {
37
38
  };
38
39
  }
39
40
  function parseConverseToolArgumentsForStream(toolCall, logger) {
40
- try {
41
- const parsed = JSON.parse(toolCall.arguments || "{}");
42
- return JSON.stringify(parsed);
43
- } catch {
44
- logger.warn(`Malformed JSON in fixture tool call arguments for "${toolCall.name}": ${toolCall.arguments}`);
45
- return "{}";
46
- }
41
+ return servedToolArgs(toolCall, "string", logger).text;
47
42
  }
48
43
  function buildBedrockStreamTextEvents(content, chunkSize, reasoning, overrides) {
49
44
  const events = [{
@@ -430,17 +425,11 @@ function buildConverseToolCallResponse(toolCalls, logger, reasoning, overrides)
430
425
  const contentBlocks = [];
431
426
  if (reasoning) contentBlocks.push({ reasoningContent: { reasoningText: { text: reasoning } } });
432
427
  for (const tc of toolCalls) {
433
- let argsObj;
434
- try {
435
- argsObj = JSON.parse(tc.arguments || "{}");
436
- } catch {
437
- logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
438
- argsObj = {};
439
- }
428
+ const args = servedToolArgs(tc, "object", logger);
440
429
  contentBlocks.push({ toolUse: {
441
430
  toolUseId: tc.id || generateToolUseId(),
442
431
  name: tc.name,
443
- input: argsObj
432
+ input: args.value
444
433
  } });
445
434
  }
446
435
  return {
@@ -457,17 +446,11 @@ function buildConverseContentWithToolCallsResponse(content, toolCalls, logger, r
457
446
  const contentBlocks = [];
458
447
  if (reasoning) contentBlocks.push({ reasoningContent: { reasoningText: { text: reasoning } } });
459
448
  const toolUseBlock = (tc) => {
460
- let argsObj;
461
- try {
462
- argsObj = JSON.parse(tc.arguments || "{}");
463
- } catch {
464
- logger.warn(`Malformed JSON in fixture tool call arguments for "${tc.name}": ${tc.arguments}`);
465
- argsObj = {};
466
- }
449
+ const args = servedToolArgs(tc, "object", logger);
467
450
  return { toolUse: {
468
451
  toolUseId: tc.id || generateToolUseId(),
469
452
  name: tc.name,
470
- input: argsObj
453
+ input: args.value
471
454
  } };
472
455
  };
473
456
  let blockHasTools;
@@ -495,6 +478,160 @@ function buildConverseContentWithToolCallsResponse(content, toolCalls, logger, r
495
478
  metrics: { latencyMs: 0 }
496
479
  };
497
480
  }
481
+ /** Prepare actual emitted calls and identities before journaling or writing bytes. */
482
+ function prepareConverseMisbehavior(plan, request, stream, defaults, headers) {
483
+ const response = plan.response;
484
+ const combined = isCombinedFixtureResponse(response);
485
+ let blocks = (combined && response.blocks?.length ? resolveFixtureBlockOutcome(response.blocks) : void 0)?.ordered.map((block) => ({ ...block })) ?? [..."content" in response && response.content ? [{
486
+ type: "text",
487
+ text: response.content
488
+ }] : [], ...(combined || isToolCallResponse(response) ? response.toolCalls ?? [] : []).map((call) => ({
489
+ type: "toolCall",
490
+ ...call
491
+ }))];
492
+ const calls = blocks.filter((block) => block.type === "toolCall");
493
+ const preparedCalls = calls.map((call, index) => {
494
+ const args = toolArgsForWire(call);
495
+ return {
496
+ ...call,
497
+ arguments: args.kind === "parsed" ? args.text : args.raw,
498
+ ...index === plan.duplicateId?.destinationIndex ? {} : { id: call.id || generateToolUseId() }
499
+ };
500
+ });
501
+ if (plan.duplicateId) preparedCalls[plan.duplicateId.destinationIndex].id = preparedCalls[plan.duplicateId.sourceIndex].id;
502
+ let callIndex = 0;
503
+ blocks = blocks.map((block) => block.type === "toolCall" ? preparedCalls[callIndex++] : block);
504
+ let stopReason = converseStopReason("finishReason" in response ? response.finishReason : void 0, calls.length ? "tool_use" : "end_turn");
505
+ if (plan.stop === "stop") stopReason = "end_turn";
506
+ if (plan.stop === "length") stopReason = "max_tokens";
507
+ if (plan.stop === "content_filter") stopReason = "content_filtered";
508
+ if (!stream && plan.summary.fault === "tool-args-invalid-json") {
509
+ blocks = blocks.filter((block) => block.type !== "toolCall");
510
+ stopReason = "malformed_tool_use";
511
+ }
512
+ if (!stream && plan.summary.fault === "stop-length-mid-tool") {
513
+ let index = 0;
514
+ blocks = blocks.map((block) => {
515
+ if (block.type !== "toolCall") return block;
516
+ return index++ === plan.target?.index ? {
517
+ ...block,
518
+ arguments: "{}"
519
+ } : block;
520
+ });
521
+ }
522
+ const reasoning = plan.reasoning ?? resolveReasoningForModel("reasoning" in response ? response.reasoning : void 0, request.model, resolveStrictMode(defaults.strict, headers), defaults.logger) ?? "";
523
+ const servedToolCalls = blocks.flatMap((block) => block.type === "toolCall" ? [{
524
+ name: block.name,
525
+ arguments: block.arguments,
526
+ id: block.id
527
+ }] : []);
528
+ const inputTokens = estimatePromptTokens(request.messages);
529
+ const outputTokens = estimateTokens(reasoning + blocks.map((block) => block.type === "text" ? block.text : block.name + block.arguments).join(""));
530
+ return {
531
+ plan: {
532
+ ...plan,
533
+ summary: {
534
+ ...plan.summary,
535
+ servedToolCalls
536
+ }
537
+ },
538
+ blocks,
539
+ reasoning,
540
+ stopReason,
541
+ usage: {
542
+ inputTokens,
543
+ outputTokens,
544
+ totalTokens: inputTokens + outputTokens
545
+ }
546
+ };
547
+ }
548
+ function buildConverseMisbehaviorResponse(prepared) {
549
+ const content = prepared.reasoning || prepared.plan.summary.fault === "reasoning-only" ? [{ reasoningContent: { reasoningText: { text: prepared.reasoning } } }] : [];
550
+ for (const block of prepared.blocks) if (block.type === "text") content.push({ text: block.text });
551
+ else {
552
+ const args = toolArgsForWire(block);
553
+ if (args.kind === "verbatim") throw new InvalidToolArgumentsError(block);
554
+ content.push({ toolUse: {
555
+ toolUseId: block.id,
556
+ name: block.name,
557
+ input: args.value
558
+ } });
559
+ }
560
+ return {
561
+ output: { message: {
562
+ role: "assistant",
563
+ content
564
+ } },
565
+ stopReason: prepared.stopReason,
566
+ usage: prepared.usage,
567
+ metrics: { latencyMs: 0 }
568
+ };
569
+ }
570
+ function buildConverseMisbehaviorEvents(prepared, chunkSize) {
571
+ const events = [{
572
+ eventType: "messageStart",
573
+ payload: { role: "assistant" }
574
+ }];
575
+ let index = 0;
576
+ if (prepared.reasoning || prepared.plan.summary.fault === "reasoning-only") {
577
+ events.push({
578
+ eventType: "contentBlockStart",
579
+ payload: {
580
+ contentBlockIndex: index,
581
+ start: { reasoningContent: {} }
582
+ }
583
+ });
584
+ for (let i = 0; i < prepared.reasoning.length; i += chunkSize) events.push({
585
+ eventType: "contentBlockDelta",
586
+ payload: {
587
+ contentBlockIndex: index,
588
+ delta: { reasoningContent: { text: prepared.reasoning.slice(i, i + chunkSize) } }
589
+ }
590
+ });
591
+ events.push({
592
+ eventType: "contentBlockStop",
593
+ payload: { contentBlockIndex: index++ }
594
+ });
595
+ }
596
+ for (const block of prepared.blocks) {
597
+ events.push({
598
+ eventType: "contentBlockStart",
599
+ payload: {
600
+ contentBlockIndex: index,
601
+ start: block.type === "toolCall" ? { toolUse: {
602
+ toolUseId: block.id,
603
+ name: block.name
604
+ } } : {}
605
+ }
606
+ });
607
+ const value = block.type === "text" ? block.text : block.arguments;
608
+ for (let i = 0; i < value.length; i += chunkSize) {
609
+ const part = value.slice(i, i + chunkSize);
610
+ events.push({
611
+ eventType: "contentBlockDelta",
612
+ payload: {
613
+ contentBlockIndex: index,
614
+ delta: block.type === "text" ? { text: part } : { toolUse: { input: part } }
615
+ }
616
+ });
617
+ }
618
+ events.push({
619
+ eventType: "contentBlockStop",
620
+ payload: { contentBlockIndex: index++ }
621
+ });
622
+ }
623
+ events.push({
624
+ eventType: "messageStop",
625
+ payload: { stopReason: prepared.stopReason }
626
+ }, {
627
+ eventType: "metadata",
628
+ payload: {
629
+ usage: prepared.usage,
630
+ metrics: { latencyMs: 0 }
631
+ }
632
+ });
633
+ return events;
634
+ }
498
635
  async function handleConverse(req, res, raw, modelId, fixtures, journal, defaults, setCorsHeaders) {
499
636
  const { logger } = defaults;
500
637
  setCorsHeaders(res);
@@ -627,9 +764,70 @@ async function handleConverse(req, res, raw, modelId, fixtures, journal, default
627
764
  return;
628
765
  }
629
766
  const response = await resolveResponse(fixture, completionReq);
767
+ let misbehavior = planMisbehavior({
768
+ wire: "bedrock-converse",
769
+ emitsToolCallIds: true,
770
+ fixture,
771
+ response,
772
+ request: completionReq,
773
+ stream: false,
774
+ defaults,
775
+ rawHeaders: req.headers,
776
+ url: req.url
777
+ });
778
+ const addResponseEntry = (input) => {
779
+ const entry = journal.add(input);
780
+ recordMisbehaviorOutcome({
781
+ entry,
782
+ summary: misbehavior.summary,
783
+ defaults,
784
+ testId
785
+ });
786
+ return entry;
787
+ };
788
+ if (misbehavior.kind === "error") {
789
+ if (!misbehavior.summary?.evaluations.length) logger.error(misbehavior.message);
790
+ addResponseEntry({
791
+ method: req.method ?? "POST",
792
+ path: urlPath,
793
+ headers: flattenHeaders(req.headers),
794
+ body: completionReq,
795
+ response: {
796
+ status: misbehavior.status,
797
+ fixture,
798
+ error: misbehavior.message
799
+ }
800
+ });
801
+ const type = misbehavior.status === 400 ? "ValidationException" : "InternalServerException";
802
+ res.setHeader("x-amzn-errortype", type);
803
+ writeErrorResponse(res, misbehavior.status, JSON.stringify({
804
+ __type: type,
805
+ message: misbehavior.message,
806
+ code: misbehavior.code
807
+ }));
808
+ return;
809
+ }
810
+ if (misbehavior.kind === "applied") {
811
+ const prepared = prepareConverseMisbehavior(misbehavior, completionReq, false, defaults, req.headers);
812
+ misbehavior = prepared.plan;
813
+ const body = buildConverseMisbehaviorResponse(prepared);
814
+ addResponseEntry({
815
+ method: req.method ?? "POST",
816
+ path: urlPath,
817
+ headers: flattenHeaders(req.headers),
818
+ body: completionReq,
819
+ response: {
820
+ status: 200,
821
+ fixture
822
+ }
823
+ });
824
+ res.writeHead(200, { "Content-Type": "application/json" });
825
+ res.end(JSON.stringify(body));
826
+ return;
827
+ }
630
828
  if (isErrorResponse(response)) {
631
829
  const status = response.status ?? 500;
632
- journal.add({
830
+ addResponseEntry({
633
831
  method: req.method ?? "POST",
634
832
  path: urlPath,
635
833
  headers: flattenHeaders(req.headers),
@@ -649,11 +847,11 @@ async function handleConverse(req, res, raw, modelId, fixtures, journal, default
649
847
  writeErrorResponse(res, status, JSON.stringify(errBody), { retryAfter: response.retryAfter });
650
848
  return;
651
849
  }
652
- if (isContentWithToolCallsResponse(response)) {
850
+ if (isCombinedFixtureResponse(response)) {
653
851
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock Converse API — ignoring");
654
852
  const overrides = extractOverrides(response);
655
853
  const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveStrictMode(defaults.strict, req.headers), logger);
656
- journal.add({
854
+ addResponseEntry({
657
855
  method: req.method ?? "POST",
658
856
  path: urlPath,
659
857
  headers: flattenHeaders(req.headers),
@@ -663,7 +861,8 @@ async function handleConverse(req, res, raw, modelId, fixtures, journal, default
663
861
  fixture
664
862
  }
665
863
  });
666
- const body = buildConverseContentWithToolCallsResponse(response.content ?? "", response.toolCalls ?? [], logger, effReasoning, overrides, response.blocks);
864
+ const functionToolCalls = requireEmittedFunctionToolCalls(response, "Bedrock Converse");
865
+ const body = buildConverseContentWithToolCallsResponse(response.content ?? "", functionToolCalls, logger, effReasoning, overrides, response.blocks);
667
866
  res.writeHead(200, { "Content-Type": "application/json" });
668
867
  res.end(JSON.stringify(body));
669
868
  return;
@@ -672,7 +871,7 @@ async function handleConverse(req, res, raw, modelId, fixtures, journal, default
672
871
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock Converse API — ignoring");
673
872
  const overrides = extractOverrides(response);
674
873
  const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveStrictMode(defaults.strict, req.headers), logger);
675
- journal.add({
874
+ addResponseEntry({
676
875
  method: req.method ?? "POST",
677
876
  path: urlPath,
678
877
  headers: flattenHeaders(req.headers),
@@ -691,7 +890,7 @@ async function handleConverse(req, res, raw, modelId, fixtures, journal, default
691
890
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock Converse API — ignoring");
692
891
  const overrides = extractOverrides(response);
693
892
  const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveStrictMode(defaults.strict, req.headers), logger);
694
- journal.add({
893
+ addResponseEntry({
695
894
  method: req.method ?? "POST",
696
895
  path: urlPath,
697
896
  headers: flattenHeaders(req.headers),
@@ -701,12 +900,12 @@ async function handleConverse(req, res, raw, modelId, fixtures, journal, default
701
900
  fixture
702
901
  }
703
902
  });
704
- const body = buildConverseToolCallResponse(response.toolCalls, logger, effReasoning, overrides);
903
+ const body = buildConverseToolCallResponse(requireEmittedFunctionToolCalls(response, "Bedrock Converse"), logger, effReasoning, overrides);
705
904
  res.writeHead(200, { "Content-Type": "application/json" });
706
905
  res.end(JSON.stringify(body));
707
906
  return;
708
907
  }
709
- journal.add({
908
+ addResponseEntry({
710
909
  method: req.method ?? "POST",
711
910
  path: urlPath,
712
911
  headers: flattenHeaders(req.headers),
@@ -854,11 +1053,84 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
854
1053
  return;
855
1054
  }
856
1055
  const response = await resolveResponse(fixture, completionReq);
1056
+ let misbehavior = planMisbehavior({
1057
+ wire: "bedrock-converse",
1058
+ emitsToolCallIds: true,
1059
+ fixture,
1060
+ response,
1061
+ request: completionReq,
1062
+ stream: true,
1063
+ defaults,
1064
+ rawHeaders: req.headers,
1065
+ url: req.url
1066
+ });
1067
+ const addResponseEntry = (input) => {
1068
+ const entry = journal.add(input);
1069
+ recordMisbehaviorOutcome({
1070
+ entry,
1071
+ summary: misbehavior.summary,
1072
+ defaults,
1073
+ testId
1074
+ });
1075
+ return entry;
1076
+ };
1077
+ if (misbehavior.kind === "error") {
1078
+ if (!misbehavior.summary?.evaluations.length) logger.error(misbehavior.message);
1079
+ addResponseEntry({
1080
+ method: req.method ?? "POST",
1081
+ path: urlPath,
1082
+ headers: flattenHeaders(req.headers),
1083
+ body: completionReq,
1084
+ response: {
1085
+ status: misbehavior.status,
1086
+ fixture,
1087
+ error: misbehavior.message
1088
+ }
1089
+ });
1090
+ const type = misbehavior.status === 400 ? "ValidationException" : "InternalServerException";
1091
+ res.setHeader("x-amzn-errortype", type);
1092
+ writeErrorResponse(res, misbehavior.status, JSON.stringify({
1093
+ __type: type,
1094
+ message: misbehavior.message,
1095
+ code: misbehavior.code
1096
+ }));
1097
+ return;
1098
+ }
857
1099
  const latency = fixture.latency ?? defaults.latency;
858
1100
  const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
1101
+ if (misbehavior.kind === "applied") {
1102
+ const prepared = prepareConverseMisbehavior(misbehavior, completionReq, true, defaults, req.headers);
1103
+ misbehavior = prepared.plan;
1104
+ const events = buildConverseMisbehaviorEvents(prepared, chunkSize);
1105
+ const entry = addResponseEntry({
1106
+ method: req.method ?? "POST",
1107
+ path: urlPath,
1108
+ headers: flattenHeaders(req.headers),
1109
+ body: completionReq,
1110
+ response: {
1111
+ status: 200,
1112
+ fixture
1113
+ }
1114
+ });
1115
+ const interruption = createInterruptionSignal(fixture);
1116
+ if (!await writeEventStream(res, events, {
1117
+ latency,
1118
+ streamingProfile: fixture.streamingProfile,
1119
+ recordedTimings: fixture.recordedTimings,
1120
+ replaySpeed: fixture.replaySpeed ?? defaults.replaySpeed,
1121
+ signal: interruption?.signal,
1122
+ onChunkSent: interruption?.tick
1123
+ })) {
1124
+ if (!res.writableEnded) res.destroy();
1125
+ entry.response.interrupted = true;
1126
+ entry.response.interruptReason = interruption?.reason();
1127
+ }
1128
+ interruption?.cleanup();
1129
+ return;
1130
+ }
859
1131
  if (isErrorResponse(response)) {
860
1132
  const status = response.status ?? 500;
861
- journal.add({
1133
+ addResponseEntry({
862
1134
  method: req.method ?? "POST",
863
1135
  path: urlPath,
864
1136
  headers: flattenHeaders(req.headers),
@@ -878,11 +1150,11 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
878
1150
  writeErrorResponse(res, status, JSON.stringify(errBody), { retryAfter: response.retryAfter });
879
1151
  return;
880
1152
  }
881
- if (isContentWithToolCallsResponse(response)) {
1153
+ if (isCombinedFixtureResponse(response)) {
882
1154
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock Converse API — ignoring");
883
1155
  const overrides = extractOverrides(response);
884
1156
  const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveStrictMode(defaults.strict, req.headers), logger);
885
- const journalEntry = journal.add({
1157
+ const journalEntry = addResponseEntry({
886
1158
  method: req.method ?? "POST",
887
1159
  path: urlPath,
888
1160
  headers: flattenHeaders(req.headers),
@@ -892,7 +1164,8 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
892
1164
  fixture
893
1165
  }
894
1166
  });
895
- const events = buildBedrockStreamContentWithToolCallsEvents(response.content ?? "", response.toolCalls ?? [], chunkSize, logger, effReasoning, overrides, response.blocks);
1167
+ const functionToolCalls = requireEmittedFunctionToolCalls(response, "Bedrock Converse");
1168
+ const events = buildBedrockStreamContentWithToolCallsEvents(response.content ?? "", functionToolCalls, chunkSize, logger, effReasoning, overrides, response.blocks);
896
1169
  const interruption = createInterruptionSignal(fixture);
897
1170
  if (!await writeEventStream(res, events, {
898
1171
  latency,
@@ -913,7 +1186,7 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
913
1186
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock Converse API — ignoring");
914
1187
  const overrides = extractOverrides(response);
915
1188
  const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveStrictMode(defaults.strict, req.headers), logger);
916
- const journalEntry = journal.add({
1189
+ const journalEntry = addResponseEntry({
917
1190
  method: req.method ?? "POST",
918
1191
  path: urlPath,
919
1192
  headers: flattenHeaders(req.headers),
@@ -944,7 +1217,7 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
944
1217
  if (response.webSearches?.length) logger.warn("webSearches in fixture response are not supported for Bedrock Converse API — ignoring");
945
1218
  const overrides = extractOverrides(response);
946
1219
  const effReasoning = resolveReasoningForModel(response.reasoning, completionReq.model, resolveStrictMode(defaults.strict, req.headers), logger);
947
- const journalEntry = journal.add({
1220
+ const journalEntry = addResponseEntry({
948
1221
  method: req.method ?? "POST",
949
1222
  path: urlPath,
950
1223
  headers: flattenHeaders(req.headers),
@@ -954,7 +1227,7 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
954
1227
  fixture
955
1228
  }
956
1229
  });
957
- const events = buildBedrockStreamToolCallEvents(response.toolCalls, chunkSize, logger, effReasoning, overrides);
1230
+ const events = buildBedrockStreamToolCallEvents(requireEmittedFunctionToolCalls(response, "Bedrock Converse"), chunkSize, logger, effReasoning, overrides);
958
1231
  const interruption = createInterruptionSignal(fixture);
959
1232
  if (!await writeEventStream(res, events, {
960
1233
  latency,
@@ -971,7 +1244,7 @@ async function handleConverseStream(req, res, raw, modelId, fixtures, journal, d
971
1244
  interruption?.cleanup();
972
1245
  return;
973
1246
  }
974
- journal.add({
1247
+ addResponseEntry({
975
1248
  method: req.method ?? "POST",
976
1249
  path: urlPath,
977
1250
  headers: flattenHeaders(req.headers),