openai 7.15.0 → 7.16.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 (150) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +6 -0
  3. package/bedrock.d.mts.map +1 -1
  4. package/bedrock.d.ts.map +1 -1
  5. package/bedrock.js +9 -6
  6. package/bedrock.js.map +1 -1
  7. package/bedrock.mjs +9 -6
  8. package/bedrock.mjs.map +1 -1
  9. package/client.d.mts +13 -3
  10. package/client.d.mts.map +1 -1
  11. package/client.d.ts +13 -3
  12. package/client.d.ts.map +1 -1
  13. package/client.js +37 -20
  14. package/client.js.map +1 -1
  15. package/client.mjs +37 -20
  16. package/client.mjs.map +1 -1
  17. package/internal/realtime-credentials.d.mts +1 -1
  18. package/internal/realtime-credentials.d.ts +1 -1
  19. package/internal/realtime-credentials.js +1 -1
  20. package/internal/realtime-credentials.mjs +1 -1
  21. package/internal/utils/abort.d.mts +11 -0
  22. package/internal/utils/abort.d.mts.map +1 -0
  23. package/internal/utils/abort.d.ts +11 -0
  24. package/internal/utils/abort.d.ts.map +1 -0
  25. package/internal/utils/abort.js +87 -0
  26. package/internal/utils/abort.js.map +1 -0
  27. package/internal/utils/abort.mjs +83 -0
  28. package/internal/utils/abort.mjs.map +1 -0
  29. package/internal/ws.d.mts +13 -0
  30. package/internal/ws.d.mts.map +1 -1
  31. package/internal/ws.d.ts +13 -0
  32. package/internal/ws.d.ts.map +1 -1
  33. package/internal/ws.js +10 -0
  34. package/internal/ws.js.map +1 -1
  35. package/internal/ws.mjs +9 -0
  36. package/internal/ws.mjs.map +1 -1
  37. package/lib/live/transcript-grouping.d.mts +2 -2
  38. package/lib/live/transcript-grouping.d.mts.map +1 -1
  39. package/lib/live/transcript-grouping.d.ts +2 -2
  40. package/lib/live/transcript-grouping.d.ts.map +1 -1
  41. package/lib/live/transcript-grouping.js +44 -22
  42. package/lib/live/transcript-grouping.js.map +1 -1
  43. package/lib/live/transcript-grouping.mjs +44 -22
  44. package/lib/live/transcript-grouping.mjs.map +1 -1
  45. package/package.json +1 -1
  46. package/resources/beta/responses/internal-base.d.mts.map +1 -1
  47. package/resources/beta/responses/internal-base.d.ts.map +1 -1
  48. package/resources/beta/responses/internal-base.js +6 -0
  49. package/resources/beta/responses/internal-base.js.map +1 -1
  50. package/resources/beta/responses/internal-base.mjs +6 -0
  51. package/resources/beta/responses/internal-base.mjs.map +1 -1
  52. package/resources/beta/responses/ws-base.d.mts +13 -8
  53. package/resources/beta/responses/ws-base.d.mts.map +1 -1
  54. package/resources/beta/responses/ws-base.d.ts +13 -8
  55. package/resources/beta/responses/ws-base.d.ts.map +1 -1
  56. package/resources/beta/responses/ws-base.js +85 -14
  57. package/resources/beta/responses/ws-base.js.map +1 -1
  58. package/resources/beta/responses/ws-base.mjs +87 -16
  59. package/resources/beta/responses/ws-base.mjs.map +1 -1
  60. package/resources/beta/responses/ws.d.mts +1 -0
  61. package/resources/beta/responses/ws.d.mts.map +1 -1
  62. package/resources/beta/responses/ws.d.ts +1 -0
  63. package/resources/beta/responses/ws.d.ts.map +1 -1
  64. package/resources/beta/responses/ws.js.map +1 -1
  65. package/resources/beta/responses/ws.mjs.map +1 -1
  66. package/resources/live/forks/ws-base.d.mts +13 -8
  67. package/resources/live/forks/ws-base.d.mts.map +1 -1
  68. package/resources/live/forks/ws-base.d.ts +13 -8
  69. package/resources/live/forks/ws-base.d.ts.map +1 -1
  70. package/resources/live/forks/ws-base.js +85 -14
  71. package/resources/live/forks/ws-base.js.map +1 -1
  72. package/resources/live/forks/ws-base.mjs +87 -16
  73. package/resources/live/forks/ws-base.mjs.map +1 -1
  74. package/resources/live/forks/ws.d.mts +1 -0
  75. package/resources/live/forks/ws.d.mts.map +1 -1
  76. package/resources/live/forks/ws.d.ts +1 -0
  77. package/resources/live/forks/ws.d.ts.map +1 -1
  78. package/resources/live/forks/ws.js.map +1 -1
  79. package/resources/live/forks/ws.mjs.map +1 -1
  80. package/resources/live/sideband/ws-base.d.mts +13 -8
  81. package/resources/live/sideband/ws-base.d.mts.map +1 -1
  82. package/resources/live/sideband/ws-base.d.ts +13 -8
  83. package/resources/live/sideband/ws-base.d.ts.map +1 -1
  84. package/resources/live/sideband/ws-base.js +85 -14
  85. package/resources/live/sideband/ws-base.js.map +1 -1
  86. package/resources/live/sideband/ws-base.mjs +87 -16
  87. package/resources/live/sideband/ws-base.mjs.map +1 -1
  88. package/resources/live/sideband/ws.d.mts +1 -0
  89. package/resources/live/sideband/ws.d.mts.map +1 -1
  90. package/resources/live/sideband/ws.d.ts +1 -0
  91. package/resources/live/sideband/ws.d.ts.map +1 -1
  92. package/resources/live/sideband/ws.js.map +1 -1
  93. package/resources/live/sideband/ws.mjs.map +1 -1
  94. package/resources/live/ws-base.d.mts +13 -8
  95. package/resources/live/ws-base.d.mts.map +1 -1
  96. package/resources/live/ws-base.d.ts +13 -8
  97. package/resources/live/ws-base.d.ts.map +1 -1
  98. package/resources/live/ws-base.js +85 -14
  99. package/resources/live/ws-base.js.map +1 -1
  100. package/resources/live/ws-base.mjs +87 -16
  101. package/resources/live/ws-base.mjs.map +1 -1
  102. package/resources/live/ws.d.mts +1 -0
  103. package/resources/live/ws.d.mts.map +1 -1
  104. package/resources/live/ws.d.ts +1 -0
  105. package/resources/live/ws.d.ts.map +1 -1
  106. package/resources/live/ws.js.map +1 -1
  107. package/resources/live/ws.mjs.map +1 -1
  108. package/resources/responses/internal-base.d.mts.map +1 -1
  109. package/resources/responses/internal-base.d.ts.map +1 -1
  110. package/resources/responses/internal-base.js +6 -0
  111. package/resources/responses/internal-base.js.map +1 -1
  112. package/resources/responses/internal-base.mjs +6 -0
  113. package/resources/responses/internal-base.mjs.map +1 -1
  114. package/resources/responses/ws-base.d.mts +13 -8
  115. package/resources/responses/ws-base.d.mts.map +1 -1
  116. package/resources/responses/ws-base.d.ts +13 -8
  117. package/resources/responses/ws-base.d.ts.map +1 -1
  118. package/resources/responses/ws-base.js +85 -14
  119. package/resources/responses/ws-base.js.map +1 -1
  120. package/resources/responses/ws-base.mjs +87 -16
  121. package/resources/responses/ws-base.mjs.map +1 -1
  122. package/resources/responses/ws.d.mts +1 -0
  123. package/resources/responses/ws.d.mts.map +1 -1
  124. package/resources/responses/ws.d.ts +1 -0
  125. package/resources/responses/ws.d.ts.map +1 -1
  126. package/resources/responses/ws.js.map +1 -1
  127. package/resources/responses/ws.mjs.map +1 -1
  128. package/src/bedrock.ts +18 -7
  129. package/src/client.ts +43 -19
  130. package/src/internal/realtime-credentials.ts +1 -1
  131. package/src/internal/utils/abort.ts +111 -0
  132. package/src/internal/ws.ts +22 -0
  133. package/src/lib/live/transcript-grouping.ts +59 -27
  134. package/src/resources/beta/responses/internal-base.ts +5 -0
  135. package/src/resources/beta/responses/ws-base.ts +110 -21
  136. package/src/resources/beta/responses/ws.ts +2 -0
  137. package/src/resources/live/forks/ws-base.ts +110 -21
  138. package/src/resources/live/forks/ws.ts +2 -0
  139. package/src/resources/live/sideband/ws-base.ts +110 -21
  140. package/src/resources/live/sideband/ws.ts +2 -0
  141. package/src/resources/live/ws-base.ts +110 -21
  142. package/src/resources/live/ws.ts +2 -0
  143. package/src/resources/responses/internal-base.ts +5 -0
  144. package/src/resources/responses/ws-base.ts +110 -21
  145. package/src/resources/responses/ws.ts +2 -0
  146. package/src/version.ts +1 -1
  147. package/version.d.mts +1 -1
  148. package/version.d.ts +1 -1
  149. package/version.js +1 -1
  150. package/version.mjs +1 -1
@@ -6,6 +6,8 @@ import { sleep } from '../../internal/utils/sleep';
6
6
  import { type WebSocketLike, ReadyState } from '../../internal/ws-adapter';
7
7
  import {
8
8
  SendQueue,
9
+ getMaxBufferedEvents,
10
+ type WebSocketStreamOptions,
9
11
  flattenRawData,
10
12
  isRecoverableClose,
11
13
  type RawWebSocketData,
@@ -51,11 +53,11 @@ export interface LiveWSBaseOptions {
51
53
  reconnect?: LiveWSReconnectOptions | null | undefined;
52
54
 
53
55
  /**
54
- * Maximum size of the outgoing message queue in bytes.
55
- * Messages queued while the socket is connecting or reconnecting are held
56
- * in memory up to this limit. Once the limit is reached, new messages are
57
- * discarded and an `error` event is emitted.
58
- * Default: 1 MB
56
+ * Byte budget for outgoing messages queued while the socket is connecting
57
+ * or reconnecting. An empty queue accepts one message even if it exceeds
58
+ * this budget. Further messages are discarded and an `error` event is emitted
59
+ * if the total queued size would exceed the budget.
60
+ * Default: 1 MiB (1,048,576 bytes).
59
61
  */
60
62
  maxQueueSize?: number | undefined;
61
63
  }
@@ -165,6 +167,11 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
165
167
  * The iterator will exit if the socket closes but exiting the iterator
166
168
  * does not close the socket.
167
169
  *
170
+ * Pass `maxBufferedEvents` to limit queued records for this iterator, including
171
+ * lifecycle events. Overflow discards its backlog and rejects `next()` with a
172
+ * WebSocketError; the shared socket and other iterators remain active.
173
+ * Omitted means unlimited. This is an event-count limit, not a byte limit.
174
+ *
168
175
  * @example
169
176
  * ```ts
170
177
  * for await (const event of client.stream()) {
@@ -182,26 +189,59 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
182
189
  * }
183
190
  * ```
184
191
  */
185
- stream(): AsyncIterableIterator<LiveStreamMessage> {
186
- return this[Symbol.asyncIterator]();
192
+ stream(options?: WebSocketStreamOptions): AsyncIterableIterator<LiveStreamMessage> {
193
+ return options === undefined ? this[Symbol.asyncIterator]() : this[Symbol.asyncIterator](options);
187
194
  }
188
195
 
189
- [Symbol.asyncIterator](): AsyncIterableIterator<LiveStreamMessage> {
196
+ [Symbol.asyncIterator](options?: WebSocketStreamOptions): AsyncIterableIterator<LiveStreamMessage> {
190
197
  if (!this.socket) {
191
198
  throw new OpenAIError('Internal error: failed to initialize socket. Please report this issue.');
192
199
  }
193
200
 
201
+ const maxBufferedEvents = getMaxBufferedEvents(options);
202
+
194
203
  // Two-queue async iterator: `queue` buffers incoming messages,
195
204
  // `resolvers` buffers waiting next() calls. A push wakes the
196
205
  // oldest next(); a next() drains the oldest message.
197
- const queue: LiveStreamMessage[] = [];
198
- const resolvers: (() => void)[] = [];
206
+ const queue: (LiveStreamMessage | undefined)[] = [];
207
+ const resolvers: ((() => void) | undefined)[] = [];
208
+ let queueHead = 0;
209
+ let resolverHead = 0;
199
210
  let done = false;
211
+ let failure: WebSocketError | undefined;
200
212
  let currentSocket = this.socket;
201
213
 
214
+ const wakeResolver = () => {
215
+ if (resolverHead >= resolvers.length) return;
216
+
217
+ const resolver = resolvers[resolverHead];
218
+ resolvers[resolverHead] = undefined;
219
+ resolverHead += 1;
220
+ if (resolverHead >= 64 && resolverHead * 2 >= resolvers.length) {
221
+ resolvers.splice(0, resolverHead);
222
+ resolverHead = 0;
223
+ }
224
+ resolver?.();
225
+ };
226
+
202
227
  const push = (msg: LiveStreamMessage) => {
228
+ if (done) return;
229
+
230
+ if (maxBufferedEvents !== undefined && queue.length - queueHead >= maxBufferedEvents) {
231
+ failure = new WebSocketError(
232
+ `WebSocket stream exceeded maxBufferedEvents (${maxBufferedEvents})`,
233
+ null,
234
+ );
235
+ done = true;
236
+ queue.length = 0;
237
+ queueHead = 0;
238
+ cleanup();
239
+ flushResolvers();
240
+ return;
241
+ }
242
+
203
243
  queue.push(msg);
204
- resolvers.shift()?.();
244
+ wakeResolver();
205
245
  };
206
246
 
207
247
  const onEvent = (event: LiveAPI.ServerEvent) => {
@@ -231,9 +271,14 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
231
271
  };
232
272
 
233
273
  const flushResolvers = () => {
234
- for (let resolver = resolvers.shift(); resolver; resolver = resolvers.shift()) {
235
- resolver();
274
+ while (resolverHead < resolvers.length) {
275
+ const resolver = resolvers[resolverHead];
276
+ resolvers[resolverHead] = undefined;
277
+ resolverHead += 1;
278
+ resolver?.();
236
279
  }
280
+ resolvers.length = 0;
281
+ resolverHead = 0;
237
282
  };
238
283
 
239
284
  const onClose = (code: number, reason: string, unsent: UnsentMessage<LiveAPI.ClientEvent>[]) => {
@@ -243,8 +288,9 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
243
288
  cleanup();
244
289
  };
245
290
 
246
- const onSocketSwap = (oldSocket: TSocket, newSocket: TSocket) => {
247
- oldSocket.off('open', onOpen);
291
+ const onSocketSwap = (_oldSocket: TSocket, newSocket: TSocket) => {
292
+ if (currentSocket === newSocket) return;
293
+ currentSocket.off('open', onOpen);
248
294
  newSocket.on('open', onOpen);
249
295
  currentSocket = newSocket;
250
296
  };
@@ -301,9 +347,21 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
301
347
  }
302
348
  }
303
349
 
304
- const resolve = (res: (value: IteratorResult<LiveStreamMessage>) => void) => {
305
- if (queue.length > 0) {
306
- res({ value: queue.shift()!, done: false });
350
+ const resolve = (
351
+ res: (value: IteratorResult<LiveStreamMessage>) => void,
352
+ reject: (error: WebSocketError) => void,
353
+ ) => {
354
+ if (failure) {
355
+ reject(failure);
356
+ } else if (queueHead < queue.length) {
357
+ const queued = queue[queueHead]!;
358
+ queue[queueHead] = undefined;
359
+ queueHead += 1;
360
+ if (queueHead >= 64 && queueHead * 2 >= queue.length) {
361
+ queue.splice(0, queueHead);
362
+ queueHead = 0;
363
+ }
364
+ res({ value: queued, done: false });
307
365
  } else if (done) {
308
366
  res({ value: undefined, done: true });
309
367
  } else {
@@ -313,10 +371,10 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
313
371
  };
314
372
 
315
373
  const next = (): Promise<IteratorResult<LiveStreamMessage>> =>
316
- new Promise((res) => {
317
- if (resolve(res)) return;
374
+ new Promise((res, reject) => {
375
+ if (resolve(res, reject)) return;
318
376
  resolvers.push(() => {
319
- resolve(res);
377
+ resolve(res, reject);
320
378
  });
321
379
  });
322
380
 
@@ -324,6 +382,8 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
324
382
  next,
325
383
  return: (): Promise<IteratorReturnResult<undefined>> => {
326
384
  done = true;
385
+ queue.length = 0;
386
+ queueHead = 0;
327
387
  cleanup();
328
388
  flushResolvers();
329
389
  return Promise.resolve({ value: undefined, done: true });
@@ -356,6 +416,35 @@ export abstract class LiveWSBase<TSocket extends WebSocketLike> extends LiveEmit
356
416
  return;
357
417
  }
358
418
 
419
+ if (
420
+ event === null ||
421
+ typeof event !== 'object' ||
422
+ Array.isArray(event) ||
423
+ !Object.prototype.hasOwnProperty.call(event, 'type') ||
424
+ typeof event.type !== 'string'
425
+ ) {
426
+ this._onError(
427
+ null,
428
+ 'received invalid WebSocket event: expected an object with an own string type',
429
+ undefined,
430
+ );
431
+ return;
432
+ }
433
+
434
+ const eventType: string = event.type;
435
+ const reservedEventType =
436
+ eventType === 'raw' ||
437
+ eventType === 'close' ||
438
+ eventType === 'event' ||
439
+ eventType === 'reconnecting' ||
440
+ eventType === 'reconnected' ||
441
+ eventType === 'open' ||
442
+ eventType === 'error';
443
+ if (reservedEventType && eventType !== 'error') {
444
+ this._onError(null, 'received reserved WebSocket event type', undefined);
445
+ return;
446
+ }
447
+
359
448
  this._emit('event', event);
360
449
 
361
450
  if (event.type === 'error') {
@@ -6,6 +6,8 @@ import { LiveWSBase, type LiveWSBaseOptions } from './ws-base';
6
6
  import { OpenAI } from '../../client';
7
7
  import { VERSION } from '../../version';
8
8
 
9
+ export type { WebSocketStreamOptions } from '../../internal/ws';
10
+
9
11
  export type { LiveWSReconnectOptions } from './ws-base';
10
12
 
11
13
  export interface LiveWSClientOptions extends WS.ClientOptions, LiveWSBaseOptions {}
@@ -75,6 +75,11 @@ export abstract class ResponsesEmitter extends EventEmitter<WebSocketEvents> {
75
75
  protected _onError(event: WebSocketErrorEvent | null, message?: string | undefined, cause?: any): void {
76
76
  const eventMessage = event && ('error' in event ? event.error?.message : event.message);
77
77
  message = message ?? eventMessage ?? safeJSONStringify(event) ?? 'unknown error';
78
+ try {
79
+ message = String(message);
80
+ } catch {
81
+ message = '[unserializable error value]';
82
+ }
78
83
 
79
84
  if (!this._hasListener('error')) {
80
85
  const error = new WebSocketError(
@@ -6,6 +6,8 @@ import { sleep } from '../../internal/utils/sleep';
6
6
  import { type WebSocketLike, ReadyState } from '../../internal/ws-adapter';
7
7
  import {
8
8
  SendQueue,
9
+ getMaxBufferedEvents,
10
+ type WebSocketStreamOptions,
9
11
  flattenRawData,
10
12
  isRecoverableClose,
11
13
  type RawWebSocketData,
@@ -51,11 +53,11 @@ export interface ResponsesWSBaseOptions {
51
53
  reconnect?: ResponsesWSReconnectOptions | null | undefined;
52
54
 
53
55
  /**
54
- * Maximum size of the outgoing message queue in bytes.
55
- * Messages queued while the socket is connecting or reconnecting are held
56
- * in memory up to this limit. Once the limit is reached, new messages are
57
- * discarded and an `error` event is emitted.
58
- * Default: 1 MB
56
+ * Byte budget for outgoing messages queued while the socket is connecting
57
+ * or reconnecting. An empty queue accepts one message even if it exceeds
58
+ * this budget. Further messages are discarded and an `error` event is emitted
59
+ * if the total queued size would exceed the budget.
60
+ * Default: 1 MiB (1,048,576 bytes).
59
61
  */
60
62
  maxQueueSize?: number | undefined;
61
63
  }
@@ -165,6 +167,11 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
165
167
  * The iterator will exit if the socket closes but exiting the iterator
166
168
  * does not close the socket.
167
169
  *
170
+ * Pass `maxBufferedEvents` to limit queued records for this iterator, including
171
+ * lifecycle events. Overflow discards its backlog and rejects `next()` with a
172
+ * WebSocketError; the shared socket and other iterators remain active.
173
+ * Omitted means unlimited. This is an event-count limit, not a byte limit.
174
+ *
168
175
  * @example
169
176
  * ```ts
170
177
  * for await (const event of client.stream()) {
@@ -182,26 +189,59 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
182
189
  * }
183
190
  * ```
184
191
  */
185
- stream(): AsyncIterableIterator<ResponsesStreamMessage> {
186
- return this[Symbol.asyncIterator]();
192
+ stream(options?: WebSocketStreamOptions): AsyncIterableIterator<ResponsesStreamMessage> {
193
+ return options === undefined ? this[Symbol.asyncIterator]() : this[Symbol.asyncIterator](options);
187
194
  }
188
195
 
189
- [Symbol.asyncIterator](): AsyncIterableIterator<ResponsesStreamMessage> {
196
+ [Symbol.asyncIterator](options?: WebSocketStreamOptions): AsyncIterableIterator<ResponsesStreamMessage> {
190
197
  if (!this.socket) {
191
198
  throw new OpenAIError('Internal error: failed to initialize socket. Please report this issue.');
192
199
  }
193
200
 
201
+ const maxBufferedEvents = getMaxBufferedEvents(options);
202
+
194
203
  // Two-queue async iterator: `queue` buffers incoming messages,
195
204
  // `resolvers` buffers waiting next() calls. A push wakes the
196
205
  // oldest next(); a next() drains the oldest message.
197
- const queue: ResponsesStreamMessage[] = [];
198
- const resolvers: (() => void)[] = [];
206
+ const queue: (ResponsesStreamMessage | undefined)[] = [];
207
+ const resolvers: ((() => void) | undefined)[] = [];
208
+ let queueHead = 0;
209
+ let resolverHead = 0;
199
210
  let done = false;
211
+ let failure: WebSocketError | undefined;
200
212
  let currentSocket = this.socket;
201
213
 
214
+ const wakeResolver = () => {
215
+ if (resolverHead >= resolvers.length) return;
216
+
217
+ const resolver = resolvers[resolverHead];
218
+ resolvers[resolverHead] = undefined;
219
+ resolverHead += 1;
220
+ if (resolverHead >= 64 && resolverHead * 2 >= resolvers.length) {
221
+ resolvers.splice(0, resolverHead);
222
+ resolverHead = 0;
223
+ }
224
+ resolver?.();
225
+ };
226
+
202
227
  const push = (msg: ResponsesStreamMessage) => {
228
+ if (done) return;
229
+
230
+ if (maxBufferedEvents !== undefined && queue.length - queueHead >= maxBufferedEvents) {
231
+ failure = new WebSocketError(
232
+ `WebSocket stream exceeded maxBufferedEvents (${maxBufferedEvents})`,
233
+ null,
234
+ );
235
+ done = true;
236
+ queue.length = 0;
237
+ queueHead = 0;
238
+ cleanup();
239
+ flushResolvers();
240
+ return;
241
+ }
242
+
203
243
  queue.push(msg);
204
- resolvers.shift()?.();
244
+ wakeResolver();
205
245
  };
206
246
 
207
247
  const onEvent = (event: ResponsesAPI.ResponsesServerEvent) => {
@@ -231,9 +271,14 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
231
271
  };
232
272
 
233
273
  const flushResolvers = () => {
234
- for (let resolver = resolvers.shift(); resolver; resolver = resolvers.shift()) {
235
- resolver();
274
+ while (resolverHead < resolvers.length) {
275
+ const resolver = resolvers[resolverHead];
276
+ resolvers[resolverHead] = undefined;
277
+ resolverHead += 1;
278
+ resolver?.();
236
279
  }
280
+ resolvers.length = 0;
281
+ resolverHead = 0;
237
282
  };
238
283
 
239
284
  const onClose = (
@@ -247,8 +292,9 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
247
292
  cleanup();
248
293
  };
249
294
 
250
- const onSocketSwap = (oldSocket: TSocket, newSocket: TSocket) => {
251
- oldSocket.off('open', onOpen);
295
+ const onSocketSwap = (_oldSocket: TSocket, newSocket: TSocket) => {
296
+ if (currentSocket === newSocket) return;
297
+ currentSocket.off('open', onOpen);
252
298
  newSocket.on('open', onOpen);
253
299
  currentSocket = newSocket;
254
300
  };
@@ -305,9 +351,21 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
305
351
  }
306
352
  }
307
353
 
308
- const resolve = (res: (value: IteratorResult<ResponsesStreamMessage>) => void) => {
309
- if (queue.length > 0) {
310
- res({ value: queue.shift()!, done: false });
354
+ const resolve = (
355
+ res: (value: IteratorResult<ResponsesStreamMessage>) => void,
356
+ reject: (error: WebSocketError) => void,
357
+ ) => {
358
+ if (failure) {
359
+ reject(failure);
360
+ } else if (queueHead < queue.length) {
361
+ const queued = queue[queueHead]!;
362
+ queue[queueHead] = undefined;
363
+ queueHead += 1;
364
+ if (queueHead >= 64 && queueHead * 2 >= queue.length) {
365
+ queue.splice(0, queueHead);
366
+ queueHead = 0;
367
+ }
368
+ res({ value: queued, done: false });
311
369
  } else if (done) {
312
370
  res({ value: undefined, done: true });
313
371
  } else {
@@ -317,10 +375,10 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
317
375
  };
318
376
 
319
377
  const next = (): Promise<IteratorResult<ResponsesStreamMessage>> =>
320
- new Promise((res) => {
321
- if (resolve(res)) return;
378
+ new Promise((res, reject) => {
379
+ if (resolve(res, reject)) return;
322
380
  resolvers.push(() => {
323
- resolve(res);
381
+ resolve(res, reject);
324
382
  });
325
383
  });
326
384
 
@@ -328,6 +386,8 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
328
386
  next,
329
387
  return: (): Promise<IteratorReturnResult<undefined>> => {
330
388
  done = true;
389
+ queue.length = 0;
390
+ queueHead = 0;
331
391
  cleanup();
332
392
  flushResolvers();
333
393
  return Promise.resolve({ value: undefined, done: true });
@@ -360,6 +420,35 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
360
420
  return;
361
421
  }
362
422
 
423
+ if (
424
+ event === null ||
425
+ typeof event !== 'object' ||
426
+ Array.isArray(event) ||
427
+ !Object.prototype.hasOwnProperty.call(event, 'type') ||
428
+ typeof event.type !== 'string'
429
+ ) {
430
+ this._onError(
431
+ null,
432
+ 'received invalid WebSocket event: expected an object with an own string type',
433
+ undefined,
434
+ );
435
+ return;
436
+ }
437
+
438
+ const eventType: string = event.type;
439
+ const reservedEventType =
440
+ eventType === 'raw' ||
441
+ eventType === 'close' ||
442
+ eventType === 'event' ||
443
+ eventType === 'reconnecting' ||
444
+ eventType === 'reconnected' ||
445
+ eventType === 'open' ||
446
+ eventType === 'error';
447
+ if (reservedEventType && eventType !== 'error') {
448
+ this._onError(null, 'received reserved WebSocket event type', undefined);
449
+ return;
450
+ }
451
+
363
452
  this._emit('event', event);
364
453
 
365
454
  if (event.type === 'error') {
@@ -6,6 +6,8 @@ import { ResponsesWSBase, type ResponsesWSBaseOptions } from './ws-base';
6
6
  import { OpenAI } from '../../client';
7
7
  import { VERSION } from '../../version';
8
8
 
9
+ export type { WebSocketStreamOptions } from '../../internal/ws';
10
+
9
11
  export type { ResponsesWSReconnectOptions } from './ws-base';
10
12
 
11
13
  export interface ResponsesWSClientOptions extends WS.ClientOptions, ResponsesWSBaseOptions {}
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** Version of the installed OpenAI SDK package. */
2
- export const VERSION = '7.15.0'; // x-release-please-version
2
+ export const VERSION = '7.16.0'; // x-release-please-version
package/version.d.mts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Version of the installed OpenAI SDK package. */
2
- export declare const VERSION = "7.15.0";
2
+ export declare const VERSION = "7.16.0";
3
3
  //# sourceMappingURL=version.d.mts.map
package/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Version of the installed OpenAI SDK package. */
2
- export declare const VERSION = "7.15.0";
2
+ export declare const VERSION = "7.16.0";
3
3
  //# sourceMappingURL=version.d.ts.map
package/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
4
  /** Version of the installed OpenAI SDK package. */
5
- exports.VERSION = '7.15.0'; // x-release-please-version
5
+ exports.VERSION = '7.16.0'; // x-release-please-version
6
6
  //# sourceMappingURL=version.js.map
package/version.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Version of the installed OpenAI SDK package. */
2
- export const VERSION = '7.15.0'; // x-release-please-version
2
+ export const VERSION = '7.16.0'; // x-release-please-version
3
3
  //# sourceMappingURL=version.mjs.map