@copilotkit/aimock 1.46.0 → 1.47.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 (183) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +12 -1
  4. package/README.md +4 -1
  5. package/dist/aws-event-stream.cjs +20 -23
  6. package/dist/aws-event-stream.cjs.map +1 -1
  7. package/dist/aws-event-stream.d.cts +0 -1
  8. package/dist/aws-event-stream.d.ts +0 -1
  9. package/dist/aws-event-stream.js +20 -24
  10. package/dist/aws-event-stream.js.map +1 -1
  11. package/dist/bedrock-converse.cjs +79 -82
  12. package/dist/bedrock-converse.cjs.map +1 -1
  13. package/dist/bedrock-converse.d.cts.map +1 -1
  14. package/dist/bedrock-converse.d.ts.map +1 -1
  15. package/dist/bedrock-converse.js +80 -83
  16. package/dist/bedrock-converse.js.map +1 -1
  17. package/dist/bedrock.cjs +112 -121
  18. package/dist/bedrock.cjs.map +1 -1
  19. package/dist/bedrock.d.cts.map +1 -1
  20. package/dist/bedrock.d.ts.map +1 -1
  21. package/dist/bedrock.js +113 -122
  22. package/dist/bedrock.js.map +1 -1
  23. package/dist/cohere.cjs +58 -106
  24. package/dist/cohere.cjs.map +1 -1
  25. package/dist/cohere.d.cts.map +1 -1
  26. package/dist/cohere.d.ts.map +1 -1
  27. package/dist/cohere.js +60 -108
  28. package/dist/cohere.js.map +1 -1
  29. package/dist/config-loader.d.cts.map +1 -1
  30. package/dist/config-loader.d.ts.map +1 -1
  31. package/dist/fixture-loader.cjs +103 -2
  32. package/dist/fixture-loader.cjs.map +1 -1
  33. package/dist/fixture-loader.d.cts.map +1 -1
  34. package/dist/fixture-loader.d.ts.map +1 -1
  35. package/dist/fixture-loader.js +104 -4
  36. package/dist/fixture-loader.js.map +1 -1
  37. package/dist/gemini-interactions.cjs +63 -121
  38. package/dist/gemini-interactions.cjs.map +1 -1
  39. package/dist/gemini-interactions.d.cts.map +1 -1
  40. package/dist/gemini-interactions.d.ts.map +1 -1
  41. package/dist/gemini-interactions.js +65 -123
  42. package/dist/gemini-interactions.js.map +1 -1
  43. package/dist/gemini.cjs +242 -155
  44. package/dist/gemini.cjs.map +1 -1
  45. package/dist/gemini.d.cts.map +1 -1
  46. package/dist/gemini.d.ts.map +1 -1
  47. package/dist/gemini.js +244 -157
  48. package/dist/gemini.js.map +1 -1
  49. package/dist/helpers.cjs +400 -7
  50. package/dist/helpers.cjs.map +1 -1
  51. package/dist/helpers.d.cts +51 -1
  52. package/dist/helpers.d.cts.map +1 -1
  53. package/dist/helpers.d.ts +51 -1
  54. package/dist/helpers.d.ts.map +1 -1
  55. package/dist/helpers.js +391 -8
  56. package/dist/helpers.js.map +1 -1
  57. package/dist/index.cjs +4 -2
  58. package/dist/index.d.cts +4 -4
  59. package/dist/index.d.ts +4 -4
  60. package/dist/index.js +4 -4
  61. package/dist/mcp-fakes.d.cts.map +1 -1
  62. package/dist/messages.cjs +159 -141
  63. package/dist/messages.cjs.map +1 -1
  64. package/dist/messages.d.cts.map +1 -1
  65. package/dist/messages.d.ts.map +1 -1
  66. package/dist/messages.js +161 -143
  67. package/dist/messages.js.map +1 -1
  68. package/dist/misbehavior.cjs +62 -3
  69. package/dist/misbehavior.cjs.map +1 -1
  70. package/dist/misbehavior.d.cts.map +1 -1
  71. package/dist/misbehavior.d.ts.map +1 -1
  72. package/dist/misbehavior.js +63 -4
  73. package/dist/misbehavior.js.map +1 -1
  74. package/dist/ndjson-writer.cjs +21 -23
  75. package/dist/ndjson-writer.cjs.map +1 -1
  76. package/dist/ndjson-writer.d.cts +0 -1
  77. package/dist/ndjson-writer.d.cts.map +1 -1
  78. package/dist/ndjson-writer.d.ts +0 -1
  79. package/dist/ndjson-writer.d.ts.map +1 -1
  80. package/dist/ndjson-writer.js +21 -24
  81. package/dist/ndjson-writer.js.map +1 -1
  82. package/dist/ollama.cjs +153 -147
  83. package/dist/ollama.cjs.map +1 -1
  84. package/dist/ollama.d.cts.map +1 -1
  85. package/dist/ollama.d.ts.map +1 -1
  86. package/dist/ollama.js +155 -149
  87. package/dist/ollama.js.map +1 -1
  88. package/dist/openrouter-chat.cjs +1 -1
  89. package/dist/openrouter-chat.js +1 -1
  90. package/dist/raw-validation.cjs +177 -0
  91. package/dist/raw-validation.cjs.map +1 -0
  92. package/dist/raw-validation.js +176 -0
  93. package/dist/raw-validation.js.map +1 -0
  94. package/dist/response/deliver.cjs +144 -0
  95. package/dist/response/deliver.cjs.map +1 -0
  96. package/dist/response/deliver.js +143 -0
  97. package/dist/response/deliver.js.map +1 -0
  98. package/dist/response/frame-loop.cjs +102 -0
  99. package/dist/response/frame-loop.cjs.map +1 -0
  100. package/dist/response/frame-loop.js +100 -0
  101. package/dist/response/frame-loop.js.map +1 -0
  102. package/dist/response/lifecycle.cjs +223 -0
  103. package/dist/response/lifecycle.cjs.map +1 -0
  104. package/dist/response/lifecycle.js +211 -0
  105. package/dist/response/lifecycle.js.map +1 -0
  106. package/dist/response/proxy.cjs +71 -0
  107. package/dist/response/proxy.cjs.map +1 -0
  108. package/dist/response/proxy.js +70 -0
  109. package/dist/response/proxy.js.map +1 -0
  110. package/dist/response/raw.cjs +228 -0
  111. package/dist/response/raw.cjs.map +1 -0
  112. package/dist/response/raw.js +227 -0
  113. package/dist/response/raw.js.map +1 -0
  114. package/dist/response/timing.cjs +157 -0
  115. package/dist/response/timing.cjs.map +1 -0
  116. package/dist/response/timing.js +150 -0
  117. package/dist/response/timing.js.map +1 -0
  118. package/dist/responses.cjs +269 -148
  119. package/dist/responses.cjs.map +1 -1
  120. package/dist/responses.d.cts.map +1 -1
  121. package/dist/responses.d.ts.map +1 -1
  122. package/dist/responses.js +270 -149
  123. package/dist/responses.js.map +1 -1
  124. package/dist/router.cjs +20 -4
  125. package/dist/router.cjs.map +1 -1
  126. package/dist/router.d.cts +7 -1
  127. package/dist/router.d.cts.map +1 -1
  128. package/dist/router.d.ts +7 -1
  129. package/dist/router.d.ts.map +1 -1
  130. package/dist/router.js +21 -5
  131. package/dist/router.js.map +1 -1
  132. package/dist/server.cjs +89 -120
  133. package/dist/server.cjs.map +1 -1
  134. package/dist/server.d.cts.map +1 -1
  135. package/dist/server.d.ts.map +1 -1
  136. package/dist/server.js +91 -122
  137. package/dist/server.js.map +1 -1
  138. package/dist/sse-writer.cjs +49 -30
  139. package/dist/sse-writer.cjs.map +1 -1
  140. package/dist/sse-writer.d.cts +0 -1
  141. package/dist/sse-writer.d.cts.map +1 -1
  142. package/dist/sse-writer.d.ts +0 -1
  143. package/dist/sse-writer.d.ts.map +1 -1
  144. package/dist/sse-writer.js +49 -31
  145. package/dist/sse-writer.js.map +1 -1
  146. package/dist/transcription.cjs +19 -33
  147. package/dist/transcription.cjs.map +1 -1
  148. package/dist/transcription.d.cts.map +1 -1
  149. package/dist/transcription.d.ts.map +1 -1
  150. package/dist/transcription.js +20 -34
  151. package/dist/transcription.js.map +1 -1
  152. package/dist/types.cjs.map +1 -1
  153. package/dist/types.d.cts +173 -10
  154. package/dist/types.d.cts.map +1 -1
  155. package/dist/types.d.ts +173 -10
  156. package/dist/types.d.ts.map +1 -1
  157. package/dist/types.js.map +1 -1
  158. package/dist/ws-framing.cjs +12 -6
  159. package/dist/ws-framing.cjs.map +1 -1
  160. package/dist/ws-framing.d.cts +2 -0
  161. package/dist/ws-framing.d.cts.map +1 -1
  162. package/dist/ws-framing.d.ts +2 -0
  163. package/dist/ws-framing.d.ts.map +1 -1
  164. package/dist/ws-framing.js +12 -6
  165. package/dist/ws-framing.js.map +1 -1
  166. package/dist/ws-gemini-live.cjs +120 -93
  167. package/dist/ws-gemini-live.cjs.map +1 -1
  168. package/dist/ws-gemini-live.js +120 -93
  169. package/dist/ws-gemini-live.js.map +1 -1
  170. package/dist/ws-realtime.cjs +80 -70
  171. package/dist/ws-realtime.cjs.map +1 -1
  172. package/dist/ws-realtime.d.cts.map +1 -1
  173. package/dist/ws-realtime.d.ts.map +1 -1
  174. package/dist/ws-realtime.js +80 -70
  175. package/dist/ws-realtime.js.map +1 -1
  176. package/dist/ws-responses.cjs +72 -53
  177. package/dist/ws-responses.cjs.map +1 -1
  178. package/dist/ws-responses.d.cts.map +1 -1
  179. package/dist/ws-responses.d.ts.map +1 -1
  180. package/dist/ws-responses.js +73 -54
  181. package/dist/ws-responses.js.map +1 -1
  182. package/package.json +1 -1
  183. package/skills/write-fixtures/SKILL.md +34 -2
@@ -6,7 +6,7 @@ import { calculateDelay, delay } from "./sse-writer.js";
6
6
  import { planMisbehavior, recordMisbehaviorOutcome } from "./misbehavior.js";
7
7
  import { matchFixtureDiagnostic } from "./router.js";
8
8
  import "./journal.js";
9
- import { createInterruptionSignal } from "./interruption.js";
9
+ import { markInterrupted, markWsTurnStopped, watchWsClose, wsLifecycle } from "./response/lifecycle.js";
10
10
  import { render } from "./response/usage/codecs/realtime.js";
11
11
  import { randomBytes } from "node:crypto";
12
12
 
@@ -368,6 +368,7 @@ function rejectRetiredBetaShape(ws, logger) {
368
368
  function handleWebSocketRealtime(ws, fixtures, journal, defaults) {
369
369
  const { logger } = defaults;
370
370
  const sessionId = realtimeId("sess");
371
+ watchWsClose(ws);
371
372
  const isBeta = defaults.upgradeHeaders?.["openai-beta"] ? String(defaults.upgradeHeaders["openai-beta"]).includes("realtime=v1") : false;
372
373
  if (isBeta) {
373
374
  rejectRetiredBetaShape(ws, logger);
@@ -676,18 +677,17 @@ async function emitLiveTranscriptionEvents(ws, fixtures, journal, defaults, sess
676
677
  const latency = fixture.latency ?? defaults.latency;
677
678
  const chunkSize = Math.max(1, fixture.chunkSize ?? defaults.chunkSize);
678
679
  const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
679
- const interruption = createInterruptionSignal(fixture);
680
+ const lifecycle = wsLifecycle(ws, fixture);
680
681
  let chunkIndex = 0;
681
682
  for (let index = 0; index < transcript.length; index += chunkSize) {
682
683
  const chunkDelay = calculateDelay(chunkIndex, fixture.streamingProfile, latency, fixture.recordedTimings, replaySpeed);
683
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
684
- if (interruption?.signal.aborted || ws.isClosed) {
685
- if (interruption?.signal.aborted) {
686
- journalEntry.response.interrupted = true;
687
- journalEntry.response.interruptReason = interruption.reason();
684
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
685
+ if (lifecycle.signal.aborted || ws.isClosed) {
686
+ if (lifecycle.signal.aborted) {
687
+ markInterrupted(journalEntry, lifecycle.reason());
688
688
  ws.destroy();
689
- }
690
- interruption?.cleanup();
689
+ } else markWsTurnStopped(journalEntry, ws, lifecycle);
690
+ lifecycle.dispose();
691
691
  return;
692
692
  }
693
693
  sendEvent(ws, {
@@ -696,14 +696,13 @@ async function emitLiveTranscriptionEvents(ws, fixtures, journal, defaults, sess
696
696
  content_index: 0,
697
697
  delta: transcript.slice(index, index + chunkSize)
698
698
  }, isBeta);
699
- interruption?.tick();
699
+ lifecycle.tick();
700
700
  chunkIndex++;
701
701
  }
702
- if (interruption?.signal.aborted) {
703
- journalEntry.response.interrupted = true;
704
- journalEntry.response.interruptReason = interruption.reason();
702
+ if (lifecycle.signal.aborted || ws.isClosed) {
703
+ markWsTurnStopped(journalEntry, ws, lifecycle);
705
704
  ws.destroy();
706
- interruption.cleanup();
705
+ lifecycle.dispose();
707
706
  return;
708
707
  }
709
708
  sendEvent(ws, {
@@ -714,7 +713,7 @@ async function emitLiveTranscriptionEvents(ws, fixtures, journal, defaults, sess
714
713
  usage,
715
714
  ...response.transcription.languages !== void 0 ? { languages: response.transcription.languages } : {}
716
715
  }, isBeta);
717
- interruption?.cleanup();
716
+ lifecycle.dispose();
718
717
  }
719
718
  function sendLiveTranscriptionFailure(ws, itemId, error, isBeta) {
720
719
  sendEvent(ws, {
@@ -976,7 +975,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
976
975
  usage: null
977
976
  }
978
977
  }, isBeta);
979
- const interruption = createInterruptionSignal(fixture);
978
+ const lifecycle = wsLifecycle(ws, fixture);
980
979
  let interrupted = false;
981
980
  const allOutputItems = [];
982
981
  const textItemId = realtimeId("item");
@@ -1024,8 +1023,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1024
1023
  for (let i = 0; i < content.length; i += chunkSize) {
1025
1024
  if (ws.isClosed) break;
1026
1025
  const chunkDelay = calculateDelay(eventIndex, void 0, latency, recordedTimings, replaySpeed);
1027
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
1028
- if (interruption?.signal.aborted) {
1026
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
1027
+ if (lifecycle.signal.aborted) {
1029
1028
  interrupted = true;
1030
1029
  break;
1031
1030
  }
@@ -1045,21 +1044,21 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1045
1044
  break;
1046
1045
  }
1047
1046
  eventIndex++;
1048
- interruption?.tick();
1049
- if (interruption?.signal.aborted) {
1047
+ lifecycle.tick();
1048
+ if (lifecycle.signal.aborted) {
1050
1049
  interrupted = true;
1051
1050
  break;
1052
1051
  }
1053
1052
  }
1054
1053
  if (interrupted) {
1055
1054
  ws.destroy();
1056
- journalEntry.response.interrupted = true;
1057
- journalEntry.response.interruptReason = interruption?.reason();
1058
- interruption?.cleanup();
1055
+ markInterrupted(journalEntry, lifecycle.reason());
1056
+ lifecycle.dispose();
1059
1057
  return;
1060
1058
  }
1061
1059
  if (ws.isClosed) {
1062
- interruption?.cleanup();
1060
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1061
+ lifecycle.dispose();
1063
1062
  return;
1064
1063
  }
1065
1064
  sendEvent(ws, {
@@ -1071,7 +1070,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1071
1070
  text: content
1072
1071
  }, isBeta);
1073
1072
  if (ws.isClosed) {
1074
- interruption?.cleanup();
1073
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1074
+ lifecycle.dispose();
1075
1075
  return;
1076
1076
  }
1077
1077
  sendEvent(ws, {
@@ -1086,7 +1086,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1086
1086
  }
1087
1087
  }, isBeta);
1088
1088
  if (ws.isClosed) {
1089
- interruption?.cleanup();
1089
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1090
+ lifecycle.dispose();
1090
1091
  return;
1091
1092
  }
1092
1093
  sendEvent(ws, {
@@ -1110,7 +1111,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1110
1111
  }
1111
1112
  }, isBeta);
1112
1113
  if (ws.isClosed) {
1113
- interruption?.cleanup();
1114
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1115
+ lifecycle.dispose();
1114
1116
  return;
1115
1117
  }
1116
1118
  allOutputItems.push(textOutputItem);
@@ -1146,8 +1148,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1146
1148
  for (let i = 0; i < args.length; i += chunkSize) {
1147
1149
  if (ws.isClosed) break;
1148
1150
  const chunkDelay = calculateDelay(eventIndex, void 0, latency, recordedTimings, replaySpeed);
1149
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
1150
- if (interruption?.signal.aborted) {
1151
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
1152
+ if (lifecycle.signal.aborted) {
1151
1153
  interrupted = true;
1152
1154
  break;
1153
1155
  }
@@ -1167,8 +1169,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1167
1169
  break;
1168
1170
  }
1169
1171
  eventIndex++;
1170
- interruption?.tick();
1171
- if (interruption?.signal.aborted) {
1172
+ lifecycle.tick();
1173
+ if (lifecycle.signal.aborted) {
1172
1174
  interrupted = true;
1173
1175
  break;
1174
1176
  }
@@ -1210,13 +1212,15 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1210
1212
  }
1211
1213
  if (interrupted) {
1212
1214
  ws.destroy();
1213
- journalEntry.response.interrupted = true;
1214
- journalEntry.response.interruptReason = interruption?.reason();
1215
- interruption?.cleanup();
1215
+ markInterrupted(journalEntry, lifecycle.reason());
1216
+ lifecycle.dispose();
1217
+ return;
1218
+ }
1219
+ lifecycle.dispose();
1220
+ if (ws.isClosed) {
1221
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1216
1222
  return;
1217
1223
  }
1218
- interruption?.cleanup();
1219
- if (ws.isClosed) return;
1220
1224
  sendEvent(ws, {
1221
1225
  type: "response.done",
1222
1226
  response: {
@@ -1292,14 +1296,14 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1292
1296
  const content = response.content ?? "";
1293
1297
  const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
1294
1298
  const { recordedTimings } = fixture;
1295
- const interruption = createInterruptionSignal(fixture);
1299
+ const lifecycle = wsLifecycle(ws, fixture);
1296
1300
  let interrupted = false;
1297
1301
  let eventIndex = 0;
1298
1302
  for (let i = 0; i < content.length; i += chunkSize) {
1299
1303
  if (ws.isClosed) break;
1300
1304
  const chunkDelay = calculateDelay(eventIndex, void 0, latency, recordedTimings, replaySpeed);
1301
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
1302
- if (interruption?.signal.aborted) {
1305
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
1306
+ if (lifecycle.signal.aborted) {
1303
1307
  interrupted = true;
1304
1308
  break;
1305
1309
  }
@@ -1319,21 +1323,23 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1319
1323
  break;
1320
1324
  }
1321
1325
  eventIndex++;
1322
- interruption?.tick();
1323
- if (interruption?.signal.aborted) {
1326
+ lifecycle.tick();
1327
+ if (lifecycle.signal.aborted) {
1324
1328
  interrupted = true;
1325
1329
  break;
1326
1330
  }
1327
1331
  }
1328
1332
  if (interrupted) {
1329
1333
  ws.destroy();
1330
- journalEntry.response.interrupted = true;
1331
- journalEntry.response.interruptReason = interruption?.reason();
1332
- interruption?.cleanup();
1334
+ markInterrupted(journalEntry, lifecycle.reason());
1335
+ lifecycle.dispose();
1336
+ return;
1337
+ }
1338
+ lifecycle.dispose();
1339
+ if (ws.isClosed) {
1340
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1333
1341
  return;
1334
1342
  }
1335
- interruption?.cleanup();
1336
- if (ws.isClosed) return;
1337
1343
  sendEvent(ws, {
1338
1344
  type: "response.output_text.done",
1339
1345
  response_id: responseId,
@@ -1410,7 +1416,7 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1410
1416
  }
1411
1417
  }, isBeta);
1412
1418
  const outputItems = [];
1413
- const interruption = createInterruptionSignal(fixture);
1419
+ const lifecycle = wsLifecycle(ws, fixture);
1414
1420
  const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
1415
1421
  const { recordedTimings } = fixture;
1416
1422
  let interrupted = false;
@@ -1445,8 +1451,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1445
1451
  for (let i = 0; i < args.length; i += chunkSize) {
1446
1452
  if (ws.isClosed) break;
1447
1453
  const chunkDelay = calculateDelay(eventIndex, void 0, latency, recordedTimings, replaySpeed);
1448
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
1449
- if (interruption?.signal.aborted) {
1454
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
1455
+ if (lifecycle.signal.aborted) {
1450
1456
  interrupted = true;
1451
1457
  break;
1452
1458
  }
@@ -1466,8 +1472,8 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1466
1472
  break;
1467
1473
  }
1468
1474
  eventIndex++;
1469
- interruption?.tick();
1470
- if (interruption?.signal.aborted) {
1475
+ lifecycle.tick();
1476
+ if (lifecycle.signal.aborted) {
1471
1477
  interrupted = true;
1472
1478
  break;
1473
1479
  }
@@ -1507,13 +1513,15 @@ async function handleResponseCreate(ws, fixtures, journal, defaults, session, co
1507
1513
  }
1508
1514
  if (interrupted) {
1509
1515
  ws.destroy();
1510
- journalEntry.response.interrupted = true;
1511
- journalEntry.response.interruptReason = interruption?.reason();
1512
- interruption?.cleanup();
1516
+ markInterrupted(journalEntry, lifecycle.reason());
1517
+ lifecycle.dispose();
1518
+ return;
1519
+ }
1520
+ lifecycle.dispose();
1521
+ if (ws.isClosed) {
1522
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1513
1523
  return;
1514
1524
  }
1515
- interruption?.cleanup();
1516
- if (ws.isClosed) return;
1517
1525
  sendEvent(ws, {
1518
1526
  type: "response.done",
1519
1527
  response: {
@@ -1551,7 +1559,7 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1551
1559
  usage: null
1552
1560
  }
1553
1561
  }, isBeta);
1554
- const interruption = createInterruptionSignal(fixture);
1562
+ const lifecycle = wsLifecycle(ws, fixture);
1555
1563
  let interrupted = false;
1556
1564
  const allOutputItems = [];
1557
1565
  const replaySpeed = fixture.replaySpeed ?? defaults.replaySpeed;
@@ -1603,8 +1611,8 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1603
1611
  for (let i = 0; i < text.length; i += chunkSize) {
1604
1612
  if (ws.isClosed) break;
1605
1613
  const chunkDelay = calculateDelay(eventIndex, void 0, latency, recordedTimings, replaySpeed);
1606
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
1607
- if (interruption?.signal.aborted) {
1614
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
1615
+ if (lifecycle.signal.aborted) {
1608
1616
  interrupted = true;
1609
1617
  break;
1610
1618
  }
@@ -1624,8 +1632,8 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1624
1632
  break;
1625
1633
  }
1626
1634
  eventIndex++;
1627
- interruption?.tick();
1628
- if (interruption?.signal.aborted) {
1635
+ lifecycle.tick();
1636
+ if (lifecycle.signal.aborted) {
1629
1637
  interrupted = true;
1630
1638
  break;
1631
1639
  }
@@ -1704,8 +1712,8 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1704
1712
  for (let i = 0; i < args.length; i += chunkSize) {
1705
1713
  if (ws.isClosed) break;
1706
1714
  const chunkDelay = calculateDelay(eventIndex, void 0, latency, recordedTimings, replaySpeed);
1707
- if (chunkDelay > 0) await delay(chunkDelay, interruption?.signal);
1708
- if (interruption?.signal.aborted) {
1715
+ if (chunkDelay > 0) await delay(chunkDelay, lifecycle.signal);
1716
+ if (lifecycle.signal.aborted) {
1709
1717
  interrupted = true;
1710
1718
  break;
1711
1719
  }
@@ -1725,8 +1733,8 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1725
1733
  break;
1726
1734
  }
1727
1735
  eventIndex++;
1728
- interruption?.tick();
1729
- if (interruption?.signal.aborted) {
1736
+ lifecycle.tick();
1737
+ if (lifecycle.signal.aborted) {
1730
1738
  interrupted = true;
1731
1739
  break;
1732
1740
  }
@@ -1768,13 +1776,15 @@ async function streamRealtimeBlocks(ws, blocks, responseId, fixture, defaults, l
1768
1776
  }
1769
1777
  if (interrupted) {
1770
1778
  ws.destroy();
1771
- journalEntry.response.interrupted = true;
1772
- journalEntry.response.interruptReason = interruption?.reason();
1773
- interruption?.cleanup();
1779
+ markInterrupted(journalEntry, lifecycle.reason());
1780
+ lifecycle.dispose();
1781
+ return;
1782
+ }
1783
+ lifecycle.dispose();
1784
+ if (ws.isClosed) {
1785
+ markWsTurnStopped(journalEntry, ws, lifecycle);
1774
1786
  return;
1775
1787
  }
1776
- interruption?.cleanup();
1777
- if (ws.isClosed) return;
1778
1788
  sendEvent(ws, {
1779
1789
  type: "response.done",
1780
1790
  response: {