@copilotkit/aimock 1.44.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +31 -0
  4. package/README.md +6 -0
  5. package/dist/agui-types.d.ts.map +1 -1
  6. package/dist/aimock-cli.cjs +31 -5
  7. package/dist/aimock-cli.cjs.map +1 -1
  8. package/dist/aimock-cli.d.cts.map +1 -1
  9. package/dist/aimock-cli.d.ts.map +1 -1
  10. package/dist/aimock-cli.js +31 -5
  11. package/dist/aimock-cli.js.map +1 -1
  12. package/dist/bedrock-converse.cjs +312 -39
  13. package/dist/bedrock-converse.cjs.map +1 -1
  14. package/dist/bedrock-converse.d.cts.map +1 -1
  15. package/dist/bedrock-converse.d.ts.map +1 -1
  16. package/dist/bedrock-converse.js +313 -40
  17. package/dist/bedrock-converse.js.map +1 -1
  18. package/dist/bedrock.cjs +195 -42
  19. package/dist/bedrock.cjs.map +1 -1
  20. package/dist/bedrock.d.cts.map +1 -1
  21. package/dist/bedrock.d.ts.map +1 -1
  22. package/dist/bedrock.js +196 -43
  23. package/dist/bedrock.js.map +1 -1
  24. package/dist/chaos.cjs +1 -0
  25. package/dist/chaos.js +1 -1
  26. package/dist/cli.cjs +152 -5
  27. package/dist/cli.cjs.map +1 -1
  28. package/dist/cli.js +155 -8
  29. package/dist/cli.js.map +1 -1
  30. package/dist/cohere.cjs +132 -71
  31. package/dist/cohere.cjs.map +1 -1
  32. package/dist/cohere.d.cts.map +1 -1
  33. package/dist/cohere.d.ts.map +1 -1
  34. package/dist/cohere.js +133 -72
  35. package/dist/cohere.js.map +1 -1
  36. package/dist/config-loader.cjs +62 -4
  37. package/dist/config-loader.cjs.map +1 -1
  38. package/dist/config-loader.d.cts +37 -4
  39. package/dist/config-loader.d.cts.map +1 -1
  40. package/dist/config-loader.d.ts +37 -4
  41. package/dist/config-loader.d.ts.map +1 -1
  42. package/dist/config-loader.js +62 -4
  43. package/dist/config-loader.js.map +1 -1
  44. package/dist/fakes-plugin.cjs +131 -0
  45. package/dist/fakes-plugin.cjs.map +1 -0
  46. package/dist/fakes-plugin.d.cts +23 -0
  47. package/dist/fakes-plugin.d.cts.map +1 -0
  48. package/dist/fakes-plugin.d.ts +23 -0
  49. package/dist/fakes-plugin.d.ts.map +1 -0
  50. package/dist/fakes-plugin.js +127 -0
  51. package/dist/fakes-plugin.js.map +1 -0
  52. package/dist/fixture-loader-services.cjs +1 -1
  53. package/dist/fixture-loader-services.cjs.map +1 -1
  54. package/dist/fixture-loader-services.js +1 -1
  55. package/dist/fixture-loader-services.js.map +1 -1
  56. package/dist/fixture-loader.cjs +389 -27
  57. package/dist/fixture-loader.cjs.map +1 -1
  58. package/dist/fixture-loader.d.cts +47 -3
  59. package/dist/fixture-loader.d.cts.map +1 -1
  60. package/dist/fixture-loader.d.ts +47 -3
  61. package/dist/fixture-loader.d.ts.map +1 -1
  62. package/dist/fixture-loader.js +384 -29
  63. package/dist/fixture-loader.js.map +1 -1
  64. package/dist/gemini-interactions.cjs +250 -52
  65. package/dist/gemini-interactions.cjs.map +1 -1
  66. package/dist/gemini-interactions.d.cts.map +1 -1
  67. package/dist/gemini-interactions.d.ts.map +1 -1
  68. package/dist/gemini-interactions.js +251 -53
  69. package/dist/gemini-interactions.js.map +1 -1
  70. package/dist/gemini.cjs +226 -37
  71. package/dist/gemini.cjs.map +1 -1
  72. package/dist/gemini.d.cts.map +1 -1
  73. package/dist/gemini.d.ts.map +1 -1
  74. package/dist/gemini.js +227 -38
  75. package/dist/gemini.js.map +1 -1
  76. package/dist/helpers.cjs +881 -7
  77. package/dist/helpers.cjs.map +1 -1
  78. package/dist/helpers.d.cts +85 -4
  79. package/dist/helpers.d.cts.map +1 -1
  80. package/dist/helpers.d.ts +85 -4
  81. package/dist/helpers.d.ts.map +1 -1
  82. package/dist/helpers.js +839 -8
  83. package/dist/helpers.js.map +1 -1
  84. package/dist/index.cjs +9 -0
  85. package/dist/index.d.cts +7 -5
  86. package/dist/index.d.ts +7 -5
  87. package/dist/index.js +4 -3
  88. package/dist/jest.cjs +31 -7
  89. package/dist/jest.cjs.map +1 -1
  90. package/dist/jest.d.cts +43 -3
  91. package/dist/jest.d.cts.map +1 -1
  92. package/dist/jest.d.ts +43 -3
  93. package/dist/jest.d.ts.map +1 -1
  94. package/dist/jest.js +33 -9
  95. package/dist/jest.js.map +1 -1
  96. package/dist/journal.cjs +135 -13
  97. package/dist/journal.cjs.map +1 -1
  98. package/dist/journal.d.cts +38 -4
  99. package/dist/journal.d.cts.map +1 -1
  100. package/dist/journal.d.ts +38 -4
  101. package/dist/journal.d.ts.map +1 -1
  102. package/dist/journal.js +135 -13
  103. package/dist/journal.js.map +1 -1
  104. package/dist/live-sanitize.cjs +4 -32
  105. package/dist/live-sanitize.cjs.map +1 -1
  106. package/dist/live-sanitize.js +4 -32
  107. package/dist/live-sanitize.js.map +1 -1
  108. package/dist/llmock.cjs +123 -30
  109. package/dist/llmock.cjs.map +1 -1
  110. package/dist/llmock.d.cts +16 -1
  111. package/dist/llmock.d.cts.map +1 -1
  112. package/dist/llmock.d.ts +16 -1
  113. package/dist/llmock.d.ts.map +1 -1
  114. package/dist/llmock.js +125 -32
  115. package/dist/llmock.js.map +1 -1
  116. package/dist/mcp-fakes-mount.cjs +1 -0
  117. package/dist/mcp-fakes-mount.cjs.map +1 -1
  118. package/dist/mcp-fakes-mount.js +1 -0
  119. package/dist/mcp-fakes-mount.js.map +1 -1
  120. package/dist/mcp-fakes-report.cjs +111 -0
  121. package/dist/mcp-fakes-report.cjs.map +1 -0
  122. package/dist/mcp-fakes-report.d.cts +40 -0
  123. package/dist/mcp-fakes-report.d.cts.map +1 -0
  124. package/dist/mcp-fakes-report.d.ts +40 -0
  125. package/dist/mcp-fakes-report.d.ts.map +1 -0
  126. package/dist/mcp-fakes-report.js +107 -0
  127. package/dist/mcp-fakes-report.js.map +1 -0
  128. package/dist/mcp-fakes.cjs +331 -8
  129. package/dist/mcp-fakes.cjs.map +1 -1
  130. package/dist/mcp-fakes.d.cts +406 -3
  131. package/dist/mcp-fakes.d.cts.map +1 -1
  132. package/dist/mcp-fakes.d.ts +406 -3
  133. package/dist/mcp-fakes.d.ts.map +1 -1
  134. package/dist/mcp-fakes.js +331 -8
  135. package/dist/mcp-fakes.js.map +1 -1
  136. package/dist/mcp-handler.cjs +209 -16
  137. package/dist/mcp-handler.cjs.map +1 -1
  138. package/dist/mcp-handler.d.cts +49 -0
  139. package/dist/mcp-handler.d.cts.map +1 -0
  140. package/dist/mcp-handler.d.ts +49 -0
  141. package/dist/mcp-handler.d.ts.map +1 -0
  142. package/dist/mcp-handler.js +207 -17
  143. package/dist/mcp-handler.js.map +1 -1
  144. package/dist/mcp-mock.cjs +112 -1
  145. package/dist/mcp-mock.cjs.map +1 -1
  146. package/dist/mcp-mock.d.cts +33 -2
  147. package/dist/mcp-mock.d.cts.map +1 -1
  148. package/dist/mcp-mock.d.ts +33 -2
  149. package/dist/mcp-mock.d.ts.map +1 -1
  150. package/dist/mcp-mock.js +112 -1
  151. package/dist/mcp-mock.js.map +1 -1
  152. package/dist/mcp-recorder.cjs +1224 -0
  153. package/dist/mcp-recorder.cjs.map +1 -0
  154. package/dist/mcp-recorder.d.cts +108 -0
  155. package/dist/mcp-recorder.d.cts.map +1 -0
  156. package/dist/mcp-recorder.d.ts +108 -0
  157. package/dist/mcp-recorder.d.ts.map +1 -0
  158. package/dist/mcp-recorder.js +1215 -0
  159. package/dist/mcp-recorder.js.map +1 -0
  160. package/dist/messages.cjs +362 -56
  161. package/dist/messages.cjs.map +1 -1
  162. package/dist/messages.d.cts.map +1 -1
  163. package/dist/messages.d.ts.map +1 -1
  164. package/dist/messages.js +363 -58
  165. package/dist/messages.js.map +1 -1
  166. package/dist/misbehavior.cjs +1523 -0
  167. package/dist/misbehavior.cjs.map +1 -0
  168. package/dist/misbehavior.d.cts +43 -0
  169. package/dist/misbehavior.d.cts.map +1 -0
  170. package/dist/misbehavior.d.ts +43 -0
  171. package/dist/misbehavior.d.ts.map +1 -0
  172. package/dist/misbehavior.js +1511 -0
  173. package/dist/misbehavior.js.map +1 -0
  174. package/dist/ollama.cjs +310 -112
  175. package/dist/ollama.cjs.map +1 -1
  176. package/dist/ollama.d.cts.map +1 -1
  177. package/dist/ollama.d.ts.map +1 -1
  178. package/dist/ollama.js +311 -113
  179. package/dist/ollama.js.map +1 -1
  180. package/dist/record-sanitize.cjs +231 -0
  181. package/dist/record-sanitize.cjs.map +1 -0
  182. package/dist/record-sanitize.js +224 -0
  183. package/dist/record-sanitize.js.map +1 -0
  184. package/dist/recorder.cjs +106 -5
  185. package/dist/recorder.cjs.map +1 -1
  186. package/dist/recorder.d.cts +2 -1
  187. package/dist/recorder.d.cts.map +1 -1
  188. package/dist/recorder.d.ts +2 -1
  189. package/dist/recorder.d.ts.map +1 -1
  190. package/dist/recorder.js +107 -7
  191. package/dist/recorder.js.map +1 -1
  192. package/dist/responses.cjs +667 -171
  193. package/dist/responses.cjs.map +1 -1
  194. package/dist/responses.d.cts +5 -13
  195. package/dist/responses.d.cts.map +1 -1
  196. package/dist/responses.d.ts +5 -13
  197. package/dist/responses.d.ts.map +1 -1
  198. package/dist/responses.js +665 -174
  199. package/dist/responses.js.map +1 -1
  200. package/dist/router.cjs +24 -2
  201. package/dist/router.cjs.map +1 -1
  202. package/dist/router.d.cts.map +1 -1
  203. package/dist/router.d.ts.map +1 -1
  204. package/dist/router.js +25 -4
  205. package/dist/router.js.map +1 -1
  206. package/dist/server.cjs +572 -76
  207. package/dist/server.cjs.map +1 -1
  208. package/dist/server.d.cts.map +1 -1
  209. package/dist/server.d.ts.map +1 -1
  210. package/dist/server.js +574 -78
  211. package/dist/server.js.map +1 -1
  212. package/dist/stream-collapse.cjs +236 -34
  213. package/dist/stream-collapse.cjs.map +1 -1
  214. package/dist/stream-collapse.d.cts +39 -4
  215. package/dist/stream-collapse.d.cts.map +1 -1
  216. package/dist/stream-collapse.d.ts +39 -4
  217. package/dist/stream-collapse.d.ts.map +1 -1
  218. package/dist/stream-collapse.js +235 -35
  219. package/dist/stream-collapse.js.map +1 -1
  220. package/dist/types.cjs.map +1 -1
  221. package/dist/types.d.cts +315 -4
  222. package/dist/types.d.cts.map +1 -1
  223. package/dist/types.d.ts +315 -4
  224. package/dist/types.d.ts.map +1 -1
  225. package/dist/types.js.map +1 -1
  226. package/dist/validate-cli.cjs +36 -4
  227. package/dist/validate-cli.cjs.map +1 -1
  228. package/dist/validate-cli.js +37 -5
  229. package/dist/validate-cli.js.map +1 -1
  230. package/dist/vector-types.d.ts.map +1 -1
  231. package/dist/version.cjs +45 -0
  232. package/dist/version.cjs.map +1 -0
  233. package/dist/version.js +44 -0
  234. package/dist/version.js.map +1 -0
  235. package/dist/vitest.cjs +66 -10
  236. package/dist/vitest.cjs.map +1 -1
  237. package/dist/vitest.d.cts +35 -4
  238. package/dist/vitest.d.cts.map +1 -1
  239. package/dist/vitest.d.ts +35 -4
  240. package/dist/vitest.d.ts.map +1 -1
  241. package/dist/vitest.js +67 -11
  242. package/dist/vitest.js.map +1 -1
  243. package/dist/watcher.cjs +6 -2
  244. package/dist/watcher.cjs.map +1 -1
  245. package/dist/watcher.js +6 -2
  246. package/dist/watcher.js.map +1 -1
  247. package/dist/ws-gemini-live.cjs +210 -101
  248. package/dist/ws-gemini-live.cjs.map +1 -1
  249. package/dist/ws-gemini-live.d.cts +9 -3
  250. package/dist/ws-gemini-live.d.cts.map +1 -1
  251. package/dist/ws-gemini-live.d.ts +9 -3
  252. package/dist/ws-gemini-live.d.ts.map +1 -1
  253. package/dist/ws-gemini-live.js +211 -102
  254. package/dist/ws-gemini-live.js.map +1 -1
  255. package/dist/ws-realtime.cjs +175 -62
  256. package/dist/ws-realtime.cjs.map +1 -1
  257. package/dist/ws-realtime.d.cts +8 -3
  258. package/dist/ws-realtime.d.cts.map +1 -1
  259. package/dist/ws-realtime.d.ts +8 -3
  260. package/dist/ws-realtime.d.ts.map +1 -1
  261. package/dist/ws-realtime.js +176 -63
  262. package/dist/ws-realtime.js.map +1 -1
  263. package/dist/ws-responses.cjs +109 -16
  264. package/dist/ws-responses.cjs.map +1 -1
  265. package/dist/ws-responses.d.cts +8 -12
  266. package/dist/ws-responses.d.cts.map +1 -1
  267. package/dist/ws-responses.d.ts +8 -12
  268. package/dist/ws-responses.d.ts.map +1 -1
  269. package/dist/ws-responses.js +111 -18
  270. package/dist/ws-responses.js.map +1 -1
  271. package/package.json +10 -2
  272. package/skills/write-fixtures/SKILL.md +179 -21
@@ -1,8 +1,8 @@
1
1
  import { Journal } from "./journal.js";
2
2
  import { Logger } from "./logger.js";
3
- import { ChatCompletionRequest, Fixture } from "./types.js";
3
+ import { ChatCompletionRequest, Fixture, HandlerDefaults } from "./types.js";
4
4
  import { WebSocketConnection } from "./ws-framing.js";
5
- import * as node_http0 from "node:http";
5
+ import * as node_http2 from "node:http";
6
6
 
7
7
  //#region src/ws-realtime.d.ts
8
8
 
@@ -11,12 +11,17 @@ declare function handleWebSocketRealtime(ws: WebSocketConnection, fixtures: Fixt
11
11
  chunkSize: number;
12
12
  replaySpeed?: number;
13
13
  model: string;
14
+ misbehavior?: HandlerDefaults["misbehavior"];
15
+ misbehaviorCounters?: HandlerDefaults["misbehaviorCounters"];
16
+ registry?: HandlerDefaults["registry"];
14
17
  logger: Logger;
15
18
  strict?: boolean;
16
19
  requestTransform?: (req: ChatCompletionRequest) => ChatCompletionRequest;
17
20
  testId?: string;
18
- upgradeHeaders?: node_http0.IncomingHttpHeaders;
21
+ upgradeHeaders?: node_http2.IncomingHttpHeaders;
19
22
  transcriptionIntent?: boolean;
23
+ /** @internal Called before each message is processed (the server assigns fixture positions). */
24
+ beforeProcessMessage?: () => void;
20
25
  }): void;
21
26
  //#endregion
22
27
  export { handleWebSocketRealtime };
@@ -1 +1 @@
1
- {"version":3,"file":"ws-realtime.d.ts","names":[],"sources":["../src/ws-realtime.ts"],"sourcesContent":[],"mappings":";;;;;;;;iBAqfgB,uBAAA,KACV,+BACM,oBACD;;;;;UAMC;;2BAEiB,0BAA0B;;mBAAqB,UAAA,CAEnC"}
1
+ {"version":3,"file":"ws-realtime.d.ts","names":[],"sources":["../src/ws-realtime.ts"],"sourcesContent":[],"mappings":";;;;;;;;iBA4hBgB,uBAAA,KACV,+BACM,oBACD;;;;;gBAMO;wBACQ;aACX;UACH;;2BAEiB,0BAA0B;;mBAAqB,UAAA,CAEnC"}
@@ -1,6 +1,7 @@
1
1
  import { DEFAULT_TEST_ID } from "./constants.js";
2
- import { flattenHeaders, generateToolCallId, isContentWithToolCallsResponse, isErrorResponse, isTextResponse, isToolCallResponse, isTranscriptionResponse, resolveFixtureBlocks, resolveResponse, resolveStrictMode, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } from "./helpers.js";
2
+ import { fixtureToolCallErrorCode, flattenHeaders, generateToolCallId, isCombinedFixtureResponse, isErrorResponse, isFixtureToolCallError, isTextResponse, isToolCallResponse, isTranscriptionResponse, journalFixtureToolCallError, prepareOpenAIChatMisbehavior, rejectResponsesOnlyToolCalls, requireServedFunctionToolCalls, resolveFixtureBlocks, resolveOpenAIChatMisbehaviorUsage, resolveResponse, resolveStrictMode, strictNoMatchLogLine, strictNoMatchMessage, strictOverrideField } 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";
@@ -14,6 +15,11 @@ import { randomBytes } from "node:crypto";
14
15
  * response.create) over WebSocket and sends back Realtime API events as
15
16
  * individual WebSocket text frames.
16
17
  */
18
+ /**
19
+ * Wire label for custom-tool-call rejections on this transport, on both the
20
+ * `toolCalls` and the ordered `blocks` path.
21
+ */
22
+ const REALTIME_WIRE = "OpenAI Realtime";
17
23
  /** Generate a Realtime-API-style ID with underscore separator (e.g. event_xxx, item_xxx). */
18
24
  function realtimeId(prefix) {
19
25
  return `${prefix}_${randomBytes(12).toString("base64url")}`;
@@ -135,6 +141,22 @@ function serializeSession(session, sessionId) {
135
141
  reasoning: session.reasoning
136
142
  };
137
143
  }
144
+ /** Realtime declares functions directly, rather than under Chat's `function` key. */
145
+ function realtimeToolDefinitions(tools) {
146
+ return tools.flatMap((value) => {
147
+ if (!value || typeof value !== "object") return [];
148
+ const tool = value;
149
+ if (tool.type !== "function" || typeof tool.name !== "string") return [];
150
+ return [{
151
+ type: "function",
152
+ function: {
153
+ name: tool.name,
154
+ ...typeof tool.description === "string" ? { description: tool.description } : {},
155
+ ...tool.parameters && typeof tool.parameters === "object" && !Array.isArray(tool.parameters) ? { parameters: tool.parameters } : {}
156
+ }
157
+ }];
158
+ });
159
+ }
138
160
  function realtimeItemsToMessages(items, instructions, logger) {
139
161
  const messages = [];
140
162
  if (instructions) messages.push({
@@ -370,15 +392,20 @@ function handleWebSocketRealtime(ws, fixtures, journal, defaults) {
370
392
  }, isBeta);
371
393
  let pending = Promise.resolve();
372
394
  ws.on("message", (raw) => {
373
- pending = pending.then(() => processMessage(raw, ws, fixtures, journal, defaults, session, conversationItems, isBeta).catch((err) => {
374
- const msg = err instanceof Error ? err.message : "Internal error";
375
- logger.error(`WebSocket realtime error: ${msg}`);
395
+ pending = pending.then(async () => {
376
396
  try {
377
- buildErrorRealtimeEvent(ws, msg, isBeta, "server_error");
378
- } catch (sendErr) {
379
- defaults.logger.debug(`Failed to send error to client: ${sendErr instanceof Error ? sendErr.message : "unknown"}`);
397
+ defaults.beforeProcessMessage?.();
398
+ await processMessage(raw, ws, fixtures, journal, defaults, session, conversationItems, isBeta);
399
+ } catch (err) {
400
+ const msg = err instanceof Error ? err.message : "Internal error";
401
+ logger.error(`WebSocket realtime error: ${msg}`);
402
+ try {
403
+ buildErrorRealtimeEvent(ws, msg, isBeta, "server_error");
404
+ } catch (sendErr) {
405
+ defaults.logger.debug(`Failed to send error to client: ${sendErr instanceof Error ? sendErr.message : "unknown"}`);
406
+ }
380
407
  }
381
- }));
408
+ });
382
409
  });
383
410
  }
384
411
  async function processMessage(raw, ws, fixtures, journal, defaults, session, conversationItems, isBeta) {
@@ -694,6 +721,57 @@ function sendLiveTranscriptionFailure(ws, itemId, error, isBeta) {
694
721
  error
695
722
  }, isBeta);
696
723
  }
724
+ /**
725
+ * Run a fixture tool-call `check` before any output item is sent. A rejected
726
+ * fixture (a custom tool call, which Realtime cannot carry, or a malformed
727
+ * `toolCalls` entry or tool-call block) marks the journal entry as a 500 and
728
+ * answers with a failed response — `response.created` then
729
+ * `response.done` with `status: "failed"` and the error, including its aimock
730
+ * `code`, in `status_details` — the same pair the error-fixture branch sends.
731
+ * Returns undefined when the response was rejected.
732
+ */
733
+ function checkRealtimeFixtureToolCalls(ws, journalEntry, responseId, isBeta, logger, check) {
734
+ try {
735
+ return journalFixtureToolCallError(journalEntry, check);
736
+ } catch (err) {
737
+ if (!isFixtureToolCallError(err)) throw err;
738
+ logger.error(`WebSocket realtime error: ${err.message}`);
739
+ sendEvent(ws, {
740
+ type: "response.created",
741
+ response: {
742
+ id: responseId,
743
+ object: "realtime.response",
744
+ status: "failed",
745
+ status_details: null,
746
+ output: [],
747
+ usage: null
748
+ }
749
+ }, isBeta);
750
+ sendEvent(ws, {
751
+ type: "response.done",
752
+ response: {
753
+ id: responseId,
754
+ object: "realtime.response",
755
+ status: "failed",
756
+ output: [],
757
+ status_details: {
758
+ type: "error",
759
+ error: {
760
+ message: err.message,
761
+ type: "server_error",
762
+ code: fixtureToolCallErrorCode(err)
763
+ }
764
+ },
765
+ usage: {
766
+ total_tokens: 0,
767
+ input_tokens: 0,
768
+ output_tokens: 0
769
+ }
770
+ }
771
+ }, isBeta);
772
+ return;
773
+ }
774
+ }
697
775
  async function handleResponseCreate(ws, fixtures, journal, defaults, session, conversationItems, isBeta, responseOverrides) {
698
776
  const messages = realtimeItemsToMessages(conversationItems, (responseOverrides?.instructions ?? session.instructions) || void 0, defaults.logger);
699
777
  const endpointType = {
@@ -703,10 +781,12 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
703
781
  }[session.type] ?? "realtime";
704
782
  const realtimeContextHeader = defaults.upgradeHeaders?.["x-aimock-context"];
705
783
  const realtimeContext = typeof realtimeContextHeader === "string" ? realtimeContextHeader : Array.isArray(realtimeContextHeader) && realtimeContextHeader.length > 0 ? realtimeContextHeader[0] : void 0;
784
+ const tools = realtimeToolDefinitions(Array.isArray(responseOverrides?.tools) ? responseOverrides.tools : session.tools);
706
785
  const completionReq = {
707
786
  model: session.model,
708
787
  messages,
709
788
  _endpointType: endpointType,
789
+ ...tools.length > 0 ? { tools } : {},
710
790
  _context: realtimeContext
711
791
  };
712
792
  const testId = defaults.testId ?? DEFAULT_TEST_ID;
@@ -778,11 +858,24 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
778
858
  return;
779
859
  }
780
860
  const response = await resolveResponse(fixture, completionReq);
781
- const latency = fixture.latency ?? defaults.latency;
782
- const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
783
- if (isErrorResponse(response)) {
784
- const status = response.status ?? 500;
785
- journal.add({
861
+ const plannerDefaults = {
862
+ ...defaults,
863
+ replaySpeed: defaults.replaySpeed ?? 1
864
+ };
865
+ let misbehavior = planMisbehavior({
866
+ wire: "openai-realtime",
867
+ emitsToolCallIds: true,
868
+ fixture,
869
+ response,
870
+ request: completionReq,
871
+ stream: true,
872
+ defaults: plannerDefaults,
873
+ rawHeaders: defaults.upgradeHeaders ?? {},
874
+ url: `/v1/realtime?testId=${encodeURIComponent(testId)}`
875
+ });
876
+ if (misbehavior.kind === "applied") misbehavior = prepareOpenAIChatMisbehavior(misbehavior);
877
+ const addResponseEntry = (status) => {
878
+ const entry = journal.add({
786
879
  method: "WS",
787
880
  path: "/v1/realtime",
788
881
  headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
@@ -792,6 +885,47 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
792
885
  fixture
793
886
  }
794
887
  });
888
+ recordMisbehaviorOutcome({
889
+ entry,
890
+ summary: misbehavior.summary,
891
+ defaults: plannerDefaults,
892
+ testId
893
+ });
894
+ return entry;
895
+ };
896
+ if (misbehavior.kind === "error") {
897
+ addResponseEntry(misbehavior.status);
898
+ if (!misbehavior.summary?.evaluations.length) defaults.logger.error(`[misbehavior] ${misbehavior.message} (testId=${testId})`);
899
+ buildErrorRealtimeEvent(ws, misbehavior.message, isBeta, "invalid_request_error", misbehavior.code);
900
+ return;
901
+ }
902
+ const latency = fixture.latency ?? defaults.latency;
903
+ const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
904
+ if (misbehavior.kind === "applied") {
905
+ const prepared = misbehavior.response;
906
+ const combined = isCombinedFixtureResponse(prepared);
907
+ const journalEntry = addResponseEntry(200);
908
+ const blocks = checkRealtimeFixtureToolCalls(ws, journalEntry, responseId, isBeta, defaults.logger, () => combined && prepared.blocks?.length ? resolveFixtureBlocks(prepared.blocks) : [...(isTextResponse(prepared) || combined) && prepared.content ? [{
909
+ type: "text",
910
+ text: prepared.content
911
+ }] : [], ...isToolCallResponse(prepared) || combined ? (prepared.toolCalls ?? []).map((call) => ({
912
+ type: "toolCall",
913
+ ...call
914
+ })) : []]);
915
+ if (!blocks) return;
916
+ const usage = resolveOpenAIChatMisbehaviorUsage(misbehavior, completionReq, false);
917
+ await streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, latency, chunkSize, isBeta, conversationItems, journalEntry, {
918
+ stop: misbehavior.stop,
919
+ usage: {
920
+ input_tokens: usage.prompt_tokens,
921
+ output_tokens: usage.completion_tokens,
922
+ total_tokens: usage.total_tokens
923
+ }
924
+ });
925
+ return;
926
+ }
927
+ if (isErrorResponse(response)) {
928
+ addResponseEntry(response.status ?? 500);
795
929
  sendEvent(ws, {
796
930
  type: "response.created",
797
931
  response: {
@@ -827,21 +961,20 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
827
961
  }, isBeta);
828
962
  return;
829
963
  }
830
- if (isContentWithToolCallsResponse(response)) {
831
- const journalEntry = journal.add({
832
- method: "WS",
833
- path: "/v1/realtime",
834
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
835
- body: completionReq,
836
- response: {
837
- status: 200,
838
- fixture
839
- }
840
- });
964
+ if (isCombinedFixtureResponse(response)) {
965
+ const journalEntry = addResponseEntry(200);
841
966
  if (response.blocks && response.blocks.length > 0) {
842
- await streamRealtimeBlocks(ws, resolveFixtureBlocks(response.blocks), responseId, fixture, defaults, latency, chunkSize, isBeta, conversationItems, journalEntry);
967
+ const blocks = response.blocks;
968
+ const resolvedBlocks = checkRealtimeFixtureToolCalls(ws, journalEntry, responseId, isBeta, defaults.logger, () => {
969
+ rejectResponsesOnlyToolCalls(response, REALTIME_WIRE);
970
+ return resolveFixtureBlocks(blocks);
971
+ });
972
+ if (!resolvedBlocks) return;
973
+ await streamRealtimeBlocks(ws, resolvedBlocks, responseId, fixture, defaults, latency, chunkSize, isBeta, conversationItems, journalEntry);
843
974
  return;
844
975
  }
976
+ const functionToolCalls = checkRealtimeFixtureToolCalls(ws, journalEntry, responseId, isBeta, defaults.logger, () => requireServedFunctionToolCalls(response, REALTIME_WIRE));
977
+ if (!functionToolCalls) return;
845
978
  sendEvent(ws, {
846
979
  type: "response.created",
847
980
  response: {
@@ -991,7 +1124,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
991
1124
  return;
992
1125
  }
993
1126
  allOutputItems.push(textOutputItem);
994
- const toolCalls = response.toolCalls ?? [];
1127
+ const toolCalls = functionToolCalls;
995
1128
  for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {
996
1129
  const tc = toolCalls[tcIdx];
997
1130
  const callId = tc.id ?? generateToolCallId();
@@ -1121,16 +1254,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1121
1254
  return;
1122
1255
  }
1123
1256
  if (isTextResponse(response)) {
1124
- const journalEntry = journal.add({
1125
- method: "WS",
1126
- path: "/v1/realtime",
1127
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
1128
- body: completionReq,
1129
- response: {
1130
- status: 200,
1131
- fixture
1132
- }
1133
- });
1257
+ const journalEntry = addResponseEntry(200);
1134
1258
  const itemId = realtimeId("item");
1135
1259
  const contentIndex = 0;
1136
1260
  const outputIndex = 0;
@@ -1289,16 +1413,9 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1289
1413
  return;
1290
1414
  }
1291
1415
  if (isToolCallResponse(response)) {
1292
- const journalEntry = journal.add({
1293
- method: "WS",
1294
- path: "/v1/realtime",
1295
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
1296
- body: completionReq,
1297
- response: {
1298
- status: 200,
1299
- fixture
1300
- }
1301
- });
1416
+ const journalEntry = addResponseEntry(200);
1417
+ const toolCalls = checkRealtimeFixtureToolCalls(ws, journalEntry, responseId, isBeta, defaults.logger, () => requireServedFunctionToolCalls(response, REALTIME_WIRE));
1418
+ if (!toolCalls) return;
1302
1419
  sendEvent(ws, {
1303
1420
  type: "response.created",
1304
1421
  response: {
@@ -1316,8 +1433,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1316
1433
  const { recordedTimings } = fixture;
1317
1434
  let interrupted = false;
1318
1435
  let eventIndex = 0;
1319
- for (let tcIdx = 0; tcIdx < response.toolCalls.length; tcIdx++) {
1320
- const tc = response.toolCalls[tcIdx];
1436
+ for (let tcIdx = 0; tcIdx < toolCalls.length; tcIdx++) {
1437
+ const tc = toolCalls[tcIdx];
1321
1438
  const callId = tc.id ?? generateToolCallId();
1322
1439
  const itemId = realtimeId("item");
1323
1440
  const outputItem = {
@@ -1432,16 +1549,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1432
1549
  for (const item of outputItems) conversationItems.push(item);
1433
1550
  return;
1434
1551
  }
1435
- journal.add({
1436
- method: "WS",
1437
- path: "/v1/realtime",
1438
- headers: flattenHeaders(defaults.upgradeHeaders ?? {}),
1439
- body: completionReq,
1440
- response: {
1441
- status: 500,
1442
- fixture
1443
- }
1444
- });
1552
+ addResponseEntry(500);
1445
1553
  buildErrorRealtimeEvent(ws, "Fixture response did not match any known type", isBeta, "server_error");
1446
1554
  }
1447
1555
  /**
@@ -1453,7 +1561,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1453
1561
  * as the legacy text/tool branches; a blocks-only fixture therefore never
1454
1562
  * produces an empty payload.
1455
1563
  */
1456
- async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, latency, chunkSize, isBeta, conversationItems, journalEntry) {
1564
+ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, latency, chunkSize, isBeta, conversationItems, journalEntry, fault) {
1457
1565
  sendEvent(ws, {
1458
1566
  type: "response.created",
1459
1567
  response: {
@@ -1592,10 +1700,11 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1592
1700
  const callId = block.id ?? generateToolCallId();
1593
1701
  const itemId = realtimeId("item");
1594
1702
  const args = block.arguments;
1703
+ const itemStatus = fault?.stop === "length" && outputIndex === blocks.length - 1 ? "incomplete" : "completed";
1595
1704
  const toolOutputItem = {
1596
1705
  id: itemId,
1597
1706
  type: "function_call",
1598
- status: "completed",
1707
+ status: itemStatus,
1599
1708
  call_id: callId,
1600
1709
  name: block.name,
1601
1710
  arguments: args
@@ -1669,7 +1778,7 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1669
1778
  id: itemId,
1670
1779
  object: "realtime.item",
1671
1780
  type: "function_call",
1672
- status: "completed",
1781
+ status: itemStatus,
1673
1782
  call_id: callId,
1674
1783
  name: block.name,
1675
1784
  arguments: args
@@ -1693,9 +1802,13 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1693
1802
  response: {
1694
1803
  id: responseId,
1695
1804
  object: "realtime.response",
1696
- status: "completed",
1805
+ status: fault?.stop === "length" || fault?.stop === "content_filter" ? "incomplete" : "completed",
1806
+ ...fault?.stop === "length" || fault?.stop === "content_filter" ? { status_details: {
1807
+ type: "incomplete",
1808
+ reason: fault.stop === "length" ? "max_output_tokens" : "content_filter"
1809
+ } } : {},
1697
1810
  output: allOutputItems,
1698
- usage: {
1811
+ usage: fault?.usage ?? {
1699
1812
  total_tokens: 0,
1700
1813
  input_tokens: 0,
1701
1814
  output_tokens: 0