openai 7.17.0 → 7.18.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 (129) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/client.d.mts +2 -0
  3. package/client.d.mts.map +1 -1
  4. package/client.d.ts +2 -0
  5. package/client.d.ts.map +1 -1
  6. package/client.js +12 -0
  7. package/client.js.map +1 -1
  8. package/client.mjs +12 -0
  9. package/client.mjs.map +1 -1
  10. package/internal/ws.d.mts +7 -0
  11. package/internal/ws.d.mts.map +1 -1
  12. package/internal/ws.d.ts +7 -0
  13. package/internal/ws.d.ts.map +1 -1
  14. package/internal/ws.js +36 -2
  15. package/internal/ws.js.map +1 -1
  16. package/internal/ws.mjs +34 -3
  17. package/internal/ws.mjs.map +1 -1
  18. package/lib/responses/responses-websocket-lane.d.mts +63 -0
  19. package/lib/responses/responses-websocket-lane.d.mts.map +1 -0
  20. package/lib/responses/responses-websocket-lane.d.ts +63 -0
  21. package/lib/responses/responses-websocket-lane.d.ts.map +1 -0
  22. package/lib/responses/responses-websocket-lane.js +314 -0
  23. package/lib/responses/responses-websocket-lane.js.map +1 -0
  24. package/lib/responses/responses-websocket-lane.mjs +309 -0
  25. package/lib/responses/responses-websocket-lane.mjs.map +1 -0
  26. package/lib/responses/responses-websocket-session.d.mts +38 -0
  27. package/lib/responses/responses-websocket-session.d.mts.map +1 -0
  28. package/lib/responses/responses-websocket-session.d.ts +38 -0
  29. package/lib/responses/responses-websocket-session.d.ts.map +1 -0
  30. package/lib/responses/responses-websocket-session.js +268 -0
  31. package/lib/responses/responses-websocket-session.js.map +1 -0
  32. package/lib/responses/responses-websocket-session.mjs +263 -0
  33. package/lib/responses/responses-websocket-session.mjs.map +1 -0
  34. package/package.json +1 -1
  35. package/resources/beta/agents/sessions/sessions.d.mts +42 -1
  36. package/resources/beta/agents/sessions/sessions.d.mts.map +1 -1
  37. package/resources/beta/agents/sessions/sessions.d.ts +42 -1
  38. package/resources/beta/agents/sessions/sessions.d.ts.map +1 -1
  39. package/resources/beta/agents/sessions/sessions.js +2 -1
  40. package/resources/beta/agents/sessions/sessions.js.map +1 -1
  41. package/resources/beta/agents/sessions/sessions.mjs +2 -1
  42. package/resources/beta/agents/sessions/sessions.mjs.map +1 -1
  43. package/resources/beta/responses/responses.d.mts +14 -4
  44. package/resources/beta/responses/responses.d.mts.map +1 -1
  45. package/resources/beta/responses/responses.d.ts +14 -4
  46. package/resources/beta/responses/responses.d.ts.map +1 -1
  47. package/resources/beta/responses/responses.js.map +1 -1
  48. package/resources/beta/responses/responses.mjs.map +1 -1
  49. package/resources/beta/responses/ws-base.d.mts +4 -0
  50. package/resources/beta/responses/ws-base.d.mts.map +1 -1
  51. package/resources/beta/responses/ws-base.d.ts +4 -0
  52. package/resources/beta/responses/ws-base.d.ts.map +1 -1
  53. package/resources/beta/responses/ws-base.js +22 -1
  54. package/resources/beta/responses/ws-base.js.map +1 -1
  55. package/resources/beta/responses/ws-base.mjs +21 -2
  56. package/resources/beta/responses/ws-base.mjs.map +1 -1
  57. package/resources/beta/responses/ws.d.mts.map +1 -1
  58. package/resources/beta/responses/ws.d.ts.map +1 -1
  59. package/resources/beta/responses/ws.js +10 -6
  60. package/resources/beta/responses/ws.js.map +1 -1
  61. package/resources/beta/responses/ws.mjs +10 -6
  62. package/resources/beta/responses/ws.mjs.map +1 -1
  63. package/resources/live/forks/ws.d.mts.map +1 -1
  64. package/resources/live/forks/ws.d.ts.map +1 -1
  65. package/resources/live/forks/ws.js +2 -4
  66. package/resources/live/forks/ws.js.map +1 -1
  67. package/resources/live/forks/ws.mjs +2 -4
  68. package/resources/live/forks/ws.mjs.map +1 -1
  69. package/resources/live/sideband/ws.d.mts.map +1 -1
  70. package/resources/live/sideband/ws.d.ts.map +1 -1
  71. package/resources/live/sideband/ws.js +2 -4
  72. package/resources/live/sideband/ws.js.map +1 -1
  73. package/resources/live/sideband/ws.mjs +2 -4
  74. package/resources/live/sideband/ws.mjs.map +1 -1
  75. package/resources/live/ws.d.mts.map +1 -1
  76. package/resources/live/ws.d.ts.map +1 -1
  77. package/resources/live/ws.js +2 -4
  78. package/resources/live/ws.js.map +1 -1
  79. package/resources/live/ws.mjs +2 -4
  80. package/resources/live/ws.mjs.map +1 -1
  81. package/resources/responses/responses.d.mts +11 -1
  82. package/resources/responses/responses.d.mts.map +1 -1
  83. package/resources/responses/responses.d.ts +11 -1
  84. package/resources/responses/responses.d.ts.map +1 -1
  85. package/resources/responses/responses.js.map +1 -1
  86. package/resources/responses/responses.mjs.map +1 -1
  87. package/resources/responses/ws-base.d.mts +6 -0
  88. package/resources/responses/ws-base.d.mts.map +1 -1
  89. package/resources/responses/ws-base.d.ts +6 -0
  90. package/resources/responses/ws-base.d.ts.map +1 -1
  91. package/resources/responses/ws-base.js +27 -4
  92. package/resources/responses/ws-base.js.map +1 -1
  93. package/resources/responses/ws-base.mjs +26 -5
  94. package/resources/responses/ws-base.mjs.map +1 -1
  95. package/resources/responses/ws.d.mts.map +1 -1
  96. package/resources/responses/ws.d.ts.map +1 -1
  97. package/resources/responses/ws.js +10 -6
  98. package/resources/responses/ws.js.map +1 -1
  99. package/resources/responses/ws.mjs +10 -6
  100. package/resources/responses/ws.mjs.map +1 -1
  101. package/resources/shared.d.mts +1 -1
  102. package/resources/shared.d.mts.map +1 -1
  103. package/resources/shared.d.ts +1 -1
  104. package/resources/shared.d.ts.map +1 -1
  105. package/resources/webhooks/webhooks.d.mts +3 -4
  106. package/resources/webhooks/webhooks.d.mts.map +1 -1
  107. package/resources/webhooks/webhooks.d.ts +3 -4
  108. package/resources/webhooks/webhooks.d.ts.map +1 -1
  109. package/src/client.ts +15 -0
  110. package/src/internal/ws.ts +37 -3
  111. package/src/lib/responses/responses-websocket-lane.ts +388 -0
  112. package/src/lib/responses/responses-websocket-session.ts +317 -0
  113. package/src/resources/beta/agents/sessions/sessions.ts +47 -1
  114. package/src/resources/beta/responses/responses.ts +24 -4
  115. package/src/resources/beta/responses/ws-base.ts +24 -1
  116. package/src/resources/beta/responses/ws.ts +9 -6
  117. package/src/resources/live/forks/ws.ts +4 -5
  118. package/src/resources/live/sideband/ws.ts +4 -5
  119. package/src/resources/live/ws.ts +4 -5
  120. package/src/resources/responses/responses.ts +15 -1
  121. package/src/resources/responses/ws-base.ts +29 -4
  122. package/src/resources/responses/ws.ts +9 -6
  123. package/src/resources/shared.ts +4 -2
  124. package/src/resources/webhooks/webhooks.ts +3 -4
  125. package/src/version.ts +1 -1
  126. package/version.d.mts +1 -1
  127. package/version.d.ts +1 -1
  128. package/version.js +1 -1
  129. package/version.mjs +1 -1
@@ -0,0 +1,317 @@
1
+ import type { ResponsesServerEvent } from '../../resources/responses/responses';
2
+ import type { ResponsesEmitter } from '../../resources/responses/internal-base';
3
+ import { WebSocketError } from '../../resources/responses/internal-base';
4
+ import { OpenAIError } from '../../core/error';
5
+ import { ReadyState } from '../../internal/ws-adapter';
6
+ import type { WebSocketLike } from '../../internal/ws-adapter';
7
+ import { getWebSocketError, rawByteLength } from '../../internal/ws';
8
+ import { hasOwn, isObj } from '../../internal/utils/values';
9
+ import { getWebSocketEventBytes, getWebSocketEventPayload } from '../../resources/responses/ws-base';
10
+ import {
11
+ getWebSocketEventBytes as getBetaWebSocketEventBytes,
12
+ getWebSocketEventPayload as getBetaWebSocketEventPayload,
13
+ } from '../../resources/beta/responses/ws-base';
14
+ import { ResponsesWebSocketLane, positiveInteger } from './responses-websocket-lane';
15
+
16
+ export { ResponsesWebSocketLane } from './responses-websocket-lane';
17
+ export type { ResponsesWebSocketEvent } from './responses-websocket-lane';
18
+
19
+ interface LaneState {
20
+ lane: ResponsesWebSocketLane;
21
+ events: number;
22
+ bytes: number;
23
+ }
24
+
25
+ /** Limits for this optional helper. They do not change the underlying socket's limits. */
26
+ export interface ResponsesWebSocketSessionOptions {
27
+ /** Maximum lane IDs registered until the next reconnect, including detached lanes. */
28
+ maxLanes: number;
29
+ /** Maximum queued events across all lanes. */
30
+ maxBufferedEvents: number;
31
+ /** Maximum queued UTF-8 JSON bytes across all lanes. */
32
+ maxBufferedBytes: number;
33
+ }
34
+
35
+ function parseEvent(serialized: string): ResponsesServerEvent {
36
+ // SAFETY: Validate the envelope below, as the native transport does for server-defined payloads.
37
+ const event = JSON.parse(serialized) as ResponsesServerEvent;
38
+ if (
39
+ !isObj(event) ||
40
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- Match the native event envelope at this untyped boundary.
41
+ typeof Object.getOwnPropertyDescriptor(event, 'type')?.value !== 'string'
42
+ ) {
43
+ throw new OpenAIError('Invalid WebSocket event shape');
44
+ }
45
+ return event;
46
+ }
47
+
48
+ function serializeCustomEvent(incoming: ResponsesServerEvent): string {
49
+ const snapshot = structuredClone(incoming);
50
+ // Mask inherited serialization hooks throughout our copy, not the caller's event.
51
+ const pending: unknown[] = [snapshot];
52
+ const visited = new Set<object>();
53
+ while (pending.length > 0) {
54
+ const value = pending.pop();
55
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- Traverse only objects in the untyped structured clone.
56
+ if (value === null || typeof value !== 'object' || visited.has(value)) {
57
+ continue;
58
+ }
59
+ visited.add(value);
60
+ // Keep Date's standard JSON conversion, which is owned by Date.prototype.
61
+ if (!(value instanceof Date) && !hasOwn(value, 'toJSON')) {
62
+ Object.defineProperty(value, 'toJSON', { value: undefined });
63
+ }
64
+ for (const child of Object.values(value)) {
65
+ pending.push(child);
66
+ }
67
+ }
68
+ return JSON.stringify(snapshot);
69
+ }
70
+
71
+ /**
72
+ * Routes events from an existing Responses socket without creating another reader.
73
+ * Register lanes before sending. Unregistered events remain observable on the socket.
74
+ * Closing this helper releases its listeners and lanes, but leaves the socket open.
75
+ * Attaching to a closing or closed socket is rejected.
76
+ * Reconnecting invalidates lanes: register new ones after restoring application state.
77
+ * No request is replayed by this helper.
78
+ */
79
+ export class ResponsesWebSocketSession {
80
+ readonly #connection: ResponsesEmitter & { readonly socket: WebSocketLike };
81
+ readonly #lanes = new Map<string | undefined, LaneState>();
82
+ readonly #maxLanes: number;
83
+ readonly #maxEvents: number;
84
+ readonly #maxBytes: number;
85
+ #events = 0;
86
+ #bytes = 0;
87
+ #closed = false;
88
+ #socket: WebSocketLike | undefined;
89
+ #failedTransport: { socket: WebSocketLike | undefined; error: WebSocketError } | undefined;
90
+
91
+ constructor(
92
+ connection: ResponsesEmitter & { readonly socket: WebSocketLike },
93
+ options: ResponsesWebSocketSessionOptions,
94
+ ) {
95
+ this.#connection = connection;
96
+ this.#maxLanes = positiveInteger(options.maxLanes);
97
+ this.#maxEvents = positiveInteger(options.maxBufferedEvents);
98
+ this.#maxBytes = positiveInteger(options.maxBufferedBytes);
99
+ if (
100
+ connection.socket.readyState === ReadyState.CLOSING ||
101
+ connection.socket.readyState === ReadyState.CLOSED
102
+ ) {
103
+ throw new OpenAIError('Cannot attach a Responses WebSocket session to a closing or closed socket');
104
+ }
105
+ connection.on('event', this.#onEvent);
106
+ connection.on('error', this.#onError);
107
+ connection.on('close', this.#onClose);
108
+ connection.on('reconnecting', this.#onReconnect);
109
+ connection.on('reconnected', this.#onReconnected);
110
+ this.#onReconnected();
111
+ }
112
+
113
+ /** Omit streamID for the protocol's default lane. A lane has one consumer.
114
+ * IDs remain reserved until reconnect, including after close or failure:
115
+ * a terminal response can still be followed by an automatic successor.
116
+ */
117
+ lane(
118
+ streamID?: string,
119
+ limits: { maxBufferedEvents?: number; maxBufferedBytes?: number } = {},
120
+ ): ResponsesWebSocketLane {
121
+ if (this.#closed) {
122
+ throw new OpenAIError('Responses WebSocket session is closed');
123
+ }
124
+ this.#assertTransportAvailable(this.#connection.socket);
125
+ if (
126
+ streamID !== undefined &&
127
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- Untyped JavaScript callers must not create non-string routing keys through RegExp coercion.
128
+ (typeof streamID !== 'string' || !/^[A-Za-z0-9_.-]{1,256}$/u.test(streamID))
129
+ ) {
130
+ throw new OpenAIError('Invalid Responses WebSocket stream ID');
131
+ }
132
+ if (this.#lanes.has(streamID)) {
133
+ throw new OpenAIError('Responses WebSocket lane is already registered');
134
+ }
135
+ if (this.#lanes.size >= this.#maxLanes) {
136
+ throw new OpenAIError('Responses WebSocket lane limit exceeded');
137
+ }
138
+ const entry: LaneState = {
139
+ events: 0,
140
+ bytes: 0,
141
+ lane: new ResponsesWebSocketLane(
142
+ streamID,
143
+ (event) => {
144
+ const { socket } = this.#connection;
145
+ this.#assertTransportAvailable(socket);
146
+ if (socket.readyState !== ReadyState.OPEN) {
147
+ throw new OpenAIError('Wait for an open Responses WebSocket before sending');
148
+ }
149
+ // The emitter's reconnect queue may replay an uncertain write. Send
150
+ // directly to the physical socket, including during its open callback.
151
+ socket.send(JSON.stringify(event));
152
+ },
153
+ (bytes) => {
154
+ this.#events -= 1;
155
+ this.#bytes -= bytes;
156
+ entry.events -= 1;
157
+ entry.bytes -= bytes;
158
+ },
159
+ positiveInteger(limits.maxBufferedEvents ?? this.#maxEvents),
160
+ positiveInteger(limits.maxBufferedBytes ?? this.#maxBytes),
161
+ ),
162
+ };
163
+ this.#lanes.set(streamID, entry);
164
+ return entry.lane;
165
+ }
166
+
167
+ close(): void {
168
+ this.#closed = true;
169
+ this.#removeListeners();
170
+ this.#failLanes(new OpenAIError('Responses WebSocket session is closed'));
171
+ this.#lanes.clear();
172
+ }
173
+
174
+ #removeListeners(): void {
175
+ this.#connection.off('event', this.#onEvent);
176
+ this.#connection.off('error', this.#onError);
177
+ this.#connection.off('close', this.#onClose);
178
+ this.#connection.off('reconnecting', this.#onReconnect);
179
+ this.#connection.off('reconnected', this.#onReconnected);
180
+ this.#socket?.off('error', this.#onSocketError);
181
+ this.#socket = undefined;
182
+ }
183
+
184
+ #onEvent = (incoming: ResponsesServerEvent): void => {
185
+ let event: ResponsesServerEvent;
186
+ let bytes: number;
187
+ try {
188
+ const payload = getWebSocketEventPayload(incoming) ?? getBetaWebSocketEventPayload(incoming);
189
+ // Native events are copied from the wire, before any observer's mutations.
190
+ // Clone custom inputs once to strip prototypes and evaluate accessors,
191
+ // then retain only the JSON representation covered by byte accounting.
192
+ let serialized = payload;
193
+ if (serialized === undefined) {
194
+ serialized = serializeCustomEvent(incoming);
195
+ }
196
+ event = parseEvent(serialized);
197
+ bytes =
198
+ payload === undefined
199
+ ? rawByteLength(serialized)
200
+ : (getBetaWebSocketEventBytes(incoming) ?? getWebSocketEventBytes(incoming));
201
+ } catch {
202
+ this.#failLanes(new OpenAIError('Cannot snapshot custom WebSocket event'));
203
+ return;
204
+ }
205
+ const routing = Object.getOwnPropertyDescriptor(event, 'stream_id');
206
+ let streamID: string | undefined;
207
+ if (routing) {
208
+ const value: unknown = routing.value;
209
+ // oxlint-disable-next-line anti-slop/no-runtime-typeof -- Raw event observers may mutate routing; only an own string value can select a lane, without invoking accessors.
210
+ if (typeof value !== 'string') {
211
+ return;
212
+ }
213
+ streamID = value;
214
+ }
215
+ const entry = this.#lanes.get(streamID);
216
+ if (!entry || entry.lane.ended) {
217
+ return;
218
+ }
219
+ if (bytes > this.#maxBytes) {
220
+ entry.lane.fail(new OpenAIError('Responses WebSocket helper buffer limit exceeded'));
221
+ return;
222
+ }
223
+ this.#events += 1;
224
+ this.#bytes += bytes;
225
+ entry.events += 1;
226
+ entry.bytes += bytes;
227
+ // Apply the lane's own limits first, releasing its backlog on overflow.
228
+ entry.lane.push(event, bytes);
229
+ while (this.#events > this.#maxEvents || this.#bytes > this.#maxBytes) {
230
+ const bytePressure = this.#bytes > this.#maxBytes;
231
+ let largest = entry;
232
+ let largestSize = 0;
233
+ for (const candidate of this.#lanes.values()) {
234
+ // Attribute pressure to existing backlogs, excluding the incoming event.
235
+ const size = bytePressure
236
+ ? candidate.bytes - (candidate === entry ? bytes : 0)
237
+ : candidate.events - (candidate === entry ? 1 : 0);
238
+ // Strict comparison breaks ties by lane registration order.
239
+ if (size > largestSize) {
240
+ largest = candidate;
241
+ largestSize = size;
242
+ }
243
+ }
244
+ largest.lane.fail(new OpenAIError('Responses WebSocket helper buffer limit exceeded'));
245
+ }
246
+ };
247
+
248
+ #onClose = (): void => {
249
+ if (this.#closed) {
250
+ return;
251
+ }
252
+ this.#closed = true;
253
+ this.#removeListeners();
254
+ for (const { lane } of this.#lanes.values()) {
255
+ lane.end(new OpenAIError('Responses WebSocket connection closed'));
256
+ }
257
+ };
258
+ // oxlint-disable-next-line eslint/class-methods-use-this -- Each session owns a distinct listener so detaching one does not unhandle another session's errors.
259
+ #onError = (): void => {
260
+ // API errors are routed as events. Other emitter errors may be recoverable
261
+ // diagnostics; only the physical socket's errors end all lanes.
262
+ };
263
+ #onSocketError = (cause: Error): void => {
264
+ const error = new WebSocketError(cause.message, null);
265
+ Object.assign(error, { cause });
266
+ this.#failedTransport = { socket: this.#socket, error };
267
+ for (const { lane } of this.#lanes.values()) {
268
+ lane.end(error);
269
+ }
270
+ };
271
+ #onReconnect = (): void => {
272
+ this.#socket?.off('error', this.#onSocketError);
273
+ this.#socket = undefined;
274
+ this.#failLanes(new OpenAIError('Responses WebSocket reconnected state must be restored explicitly'));
275
+ this.#lanes.clear();
276
+ };
277
+ #onReconnected = (): void => {
278
+ if (this.#closed) {
279
+ return;
280
+ }
281
+ this.#socket?.off('error', this.#onSocketError);
282
+ this.#socket = this.#connection.socket;
283
+ this.#clearRecoveredTransportError(this.#socket);
284
+ this.#socket.on('error', this.#onSocketError);
285
+ };
286
+
287
+ #assertTransportAvailable(socket: WebSocketLike): void {
288
+ // Native transports record failure before forwarding their public error event.
289
+ const cause = getWebSocketError(socket);
290
+ if (cause) {
291
+ const error = new WebSocketError(cause.message, null);
292
+ Object.assign(error, { cause });
293
+ throw error;
294
+ }
295
+ this.#clearRecoveredTransportError(socket);
296
+ if (this.#failedTransport) {
297
+ throw this.#failedTransport.error;
298
+ }
299
+ }
300
+
301
+ #clearRecoveredTransportError(socket: WebSocketLike): void {
302
+ // Application recovery callbacks can run before our reconnected listener.
303
+ if (
304
+ this.#failedTransport &&
305
+ socket !== this.#failedTransport.socket &&
306
+ socket.readyState === ReadyState.OPEN
307
+ ) {
308
+ this.#failedTransport = undefined;
309
+ }
310
+ }
311
+
312
+ #failLanes(error: Error): void {
313
+ for (const { lane } of this.#lanes.values()) {
314
+ lane.fail(error);
315
+ }
316
+ }
317
+ }
@@ -100,7 +100,8 @@ export class Sessions extends APIResource {
100
100
  }
101
101
 
102
102
  /**
103
- * Updates session metadata. Omitted fields are unchanged. See
103
+ * Updates session metadata, model, reasoning effort, or service tier. Model
104
+ * settings apply to subsequent turns. Omitted fields are unchanged. See
104
105
  * [managing sessions](https://developers.openai.com/api/docs/guides/agents-api/sessions/manage).
105
106
  *
106
107
  * @example
@@ -277,6 +278,11 @@ export interface SessionCreateParamsStreaming extends SessionCreateParamsBase {
277
278
  }
278
279
 
279
280
  export interface SessionUpdateParams {
281
+ /**
282
+ * Model settings for subsequent turns. Omitted fields stay unchanged.
283
+ */
284
+ agent?: SessionUpdateParams.Agent;
285
+
280
286
  /**
281
287
  * Replaces all metadata. Omit to leave unchanged, or pass null or {} to clear it.
282
288
  * Up to 16 string key-value pairs, with keys up to 64 and values up to 512
@@ -285,6 +291,46 @@ export interface SessionUpdateParams {
285
291
  metadata?: { [key: string]: string } | null;
286
292
  }
287
293
 
294
+ export namespace SessionUpdateParams {
295
+ /**
296
+ * Model settings for subsequent turns. Omitted fields stay unchanged.
297
+ */
298
+ export interface Agent {
299
+ /**
300
+ * The model for subsequent turns. Omit to keep the current model.
301
+ */
302
+ model?: string;
303
+
304
+ /**
305
+ * Reasoning settings to update. Omit to keep the current effort.
306
+ */
307
+ reasoning?: Agent.Reasoning;
308
+
309
+ /**
310
+ * The service tier used for model requests.
311
+ *
312
+ * - `auto` - Selects the service tier automatically.
313
+ * - `default` - Uses the default service tier.
314
+ * - `flex` - Uses the flex service tier.
315
+ * - `priority` - Uses the priority service tier.
316
+ * - `fast` - Uses the fast service tier.
317
+ */
318
+ service_tier?: 'auto' | 'default' | 'flex' | 'priority' | 'fast' | null;
319
+ }
320
+
321
+ export namespace Agent {
322
+ /**
323
+ * Reasoning settings to update. Omit to keep the current effort.
324
+ */
325
+ export interface Reasoning {
326
+ /**
327
+ * The amount of reasoning effort the model should use.
328
+ */
329
+ effort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;
330
+ }
331
+ }
332
+ }
333
+
288
334
  export interface SessionListParams extends CursorPageParams {
289
335
  /**
290
336
  * Only return sessions whose root agent has this ID. Omit to return sessions for
@@ -1163,7 +1163,6 @@ export interface BetaResponse {
1163
1163
  | 'gpt-5.1'
1164
1164
  | 'gpt-5.1-2025-11-13'
1165
1165
  | 'gpt-5.1-codex'
1166
- | 'gpt-5.1-mini'
1167
1166
  | 'gpt-5.1-chat-latest'
1168
1167
  | 'gpt-5'
1169
1168
  | 'gpt-5-mini'
@@ -1194,6 +1193,8 @@ export interface BetaResponse {
1194
1193
  | 'gpt-4o-2024-11-20'
1195
1194
  | 'gpt-4o-2024-08-06'
1196
1195
  | 'gpt-4o-2024-05-13'
1196
+ | 'gpt-audio-mini'
1197
+ | 'gpt-audio-mini-2025-12-15'
1197
1198
  | 'gpt-4o-audio-preview'
1198
1199
  | 'gpt-4o-audio-preview-2024-10-01'
1199
1200
  | 'gpt-4o-audio-preview-2024-12-17'
@@ -1227,6 +1228,7 @@ export interface BetaResponse {
1227
1228
  | 'gpt-3.5-turbo-1106'
1228
1229
  | 'gpt-3.5-turbo-0125'
1229
1230
  | 'gpt-3.5-turbo-16k-0613'
1231
+ | 'gpt-5.1-mini'
1230
1232
  | 'o1-pro'
1231
1233
  | 'o1-pro-2025-03-19'
1232
1234
  | 'o3-pro'
@@ -11740,7 +11742,6 @@ export namespace BetaResponsesClientEvent {
11740
11742
  | 'gpt-5.1'
11741
11743
  | 'gpt-5.1-2025-11-13'
11742
11744
  | 'gpt-5.1-codex'
11743
- | 'gpt-5.1-mini'
11744
11745
  | 'gpt-5.1-chat-latest'
11745
11746
  | 'gpt-5'
11746
11747
  | 'gpt-5-mini'
@@ -11771,6 +11772,8 @@ export namespace BetaResponsesClientEvent {
11771
11772
  | 'gpt-4o-2024-11-20'
11772
11773
  | 'gpt-4o-2024-08-06'
11773
11774
  | 'gpt-4o-2024-05-13'
11775
+ | 'gpt-audio-mini'
11776
+ | 'gpt-audio-mini-2025-12-15'
11774
11777
  | 'gpt-4o-audio-preview'
11775
11778
  | 'gpt-4o-audio-preview-2024-10-01'
11776
11779
  | 'gpt-4o-audio-preview-2024-12-17'
@@ -11804,6 +11807,7 @@ export namespace BetaResponsesClientEvent {
11804
11807
  | 'gpt-3.5-turbo-1106'
11805
11808
  | 'gpt-3.5-turbo-0125'
11806
11809
  | 'gpt-3.5-turbo-16k-0613'
11810
+ | 'gpt-5.1-mini'
11807
11811
  | 'o1-pro'
11808
11812
  | 'o1-pro-2025-03-19'
11809
11813
  | 'o3-pro'
@@ -12178,6 +12182,12 @@ export namespace BetaResponsesClientEvent {
12178
12182
  */
12179
12183
  mode?: 'implicit' | 'explicit';
12180
12184
 
12185
+ /**
12186
+ * Prepares the prompt cache without generating output. Defaults to `false`. When
12187
+ * set to `true`, overrides the `generate` field to `false`.
12188
+ */
12189
+ prewarm?: boolean;
12190
+
12181
12191
  /**
12182
12192
  * The minimum lifetime applied to every implicit and explicit cache breakpoint
12183
12193
  * written by the request. Defaults to `30m`, which is currently the only supported
@@ -13983,7 +13993,6 @@ export interface ResponseCreateParamsBase {
13983
13993
  | 'gpt-5.1'
13984
13994
  | 'gpt-5.1-2025-11-13'
13985
13995
  | 'gpt-5.1-codex'
13986
- | 'gpt-5.1-mini'
13987
13996
  | 'gpt-5.1-chat-latest'
13988
13997
  | 'gpt-5'
13989
13998
  | 'gpt-5-mini'
@@ -14014,6 +14023,8 @@ export interface ResponseCreateParamsBase {
14014
14023
  | 'gpt-4o-2024-11-20'
14015
14024
  | 'gpt-4o-2024-08-06'
14016
14025
  | 'gpt-4o-2024-05-13'
14026
+ | 'gpt-audio-mini'
14027
+ | 'gpt-audio-mini-2025-12-15'
14017
14028
  | 'gpt-4o-audio-preview'
14018
14029
  | 'gpt-4o-audio-preview-2024-10-01'
14019
14030
  | 'gpt-4o-audio-preview-2024-12-17'
@@ -14047,6 +14058,7 @@ export interface ResponseCreateParamsBase {
14047
14058
  | 'gpt-3.5-turbo-1106'
14048
14059
  | 'gpt-3.5-turbo-0125'
14049
14060
  | 'gpt-3.5-turbo-16k-0613'
14061
+ | 'gpt-5.1-mini'
14050
14062
  | 'o1-pro'
14051
14063
  | 'o1-pro-2025-03-19'
14052
14064
  | 'o3-pro'
@@ -14422,6 +14434,12 @@ export namespace ResponseCreateParams {
14422
14434
  */
14423
14435
  mode?: 'implicit' | 'explicit';
14424
14436
 
14437
+ /**
14438
+ * Prepares the prompt cache without generating output. Defaults to `false`. When
14439
+ * set to `true`, overrides the `generate` field to `false`.
14440
+ */
14441
+ prewarm?: boolean;
14442
+
14425
14443
  /**
14426
14444
  * The minimum lifetime applied to every implicit and explicit cache breakpoint
14427
14445
  * written by the request. Defaults to `30m`, which is currently the only supported
@@ -14645,7 +14663,6 @@ export interface ResponseCompactParams {
14645
14663
  | 'gpt-5.1'
14646
14664
  | 'gpt-5.1-2025-11-13'
14647
14665
  | 'gpt-5.1-codex'
14648
- | 'gpt-5.1-mini'
14649
14666
  | 'gpt-5.1-chat-latest'
14650
14667
  | 'gpt-5'
14651
14668
  | 'gpt-5-mini'
@@ -14676,6 +14693,8 @@ export interface ResponseCompactParams {
14676
14693
  | 'gpt-4o-2024-11-20'
14677
14694
  | 'gpt-4o-2024-08-06'
14678
14695
  | 'gpt-4o-2024-05-13'
14696
+ | 'gpt-audio-mini'
14697
+ | 'gpt-audio-mini-2025-12-15'
14679
14698
  | 'gpt-4o-audio-preview'
14680
14699
  | 'gpt-4o-audio-preview-2024-10-01'
14681
14700
  | 'gpt-4o-audio-preview-2024-12-17'
@@ -14709,6 +14728,7 @@ export interface ResponseCompactParams {
14709
14728
  | 'gpt-3.5-turbo-1106'
14710
14729
  | 'gpt-3.5-turbo-0125'
14711
14730
  | 'gpt-3.5-turbo-16k-0613'
14731
+ | 'gpt-5.1-mini'
14712
14732
  | 'o1-pro'
14713
14733
  | 'o1-pro-2025-03-19'
14714
14734
  | 'o3-pro'
@@ -7,6 +7,8 @@ import { type WebSocketLike, ReadyState } from '../../../internal/ws-adapter';
7
7
  import {
8
8
  SendQueue,
9
9
  getMaxBufferedEvents,
10
+ recordWebSocketError,
11
+ rawByteLength,
10
12
  type WebSocketStreamOptions,
11
13
  flattenRawData,
12
14
  isRecoverableClose,
@@ -19,6 +21,19 @@ import * as ResponsesAPI from './responses';
19
21
  import { OpenAI } from '../../../client';
20
22
  import { OpenAIError } from '../../../core/error';
21
23
 
24
+ const webSocketEventPayloads = new WeakMap<object, string>();
25
+ const webSocketEventBytes = new WeakMap<object, number>();
26
+
27
+ /** Original wire size, available only during synchronous event notification. @internal */
28
+ export function getWebSocketEventBytes(event: object): number | undefined {
29
+ return webSocketEventBytes.get(event);
30
+ }
31
+
32
+ /** Original JSON, available only during synchronous event notification. @internal */
33
+ export function getWebSocketEventPayload(event: object): string | undefined {
34
+ return webSocketEventPayloads.get(event);
35
+ }
36
+
22
37
  export interface ResponsesWSReconnectOptions {
23
38
  /**
24
39
  * Called before each reconnect attempt. Return an object with
@@ -457,7 +472,14 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
457
472
  return;
458
473
  }
459
474
 
460
- this._emit('event', event);
475
+ webSocketEventBytes.set(event, rawByteLength(data));
476
+ webSocketEventPayloads.set(event, text);
477
+ try {
478
+ this._emit('event', event);
479
+ } finally {
480
+ webSocketEventBytes.delete(event);
481
+ webSocketEventPayloads.delete(event);
482
+ }
461
483
 
462
484
  if (event.type === 'error') {
463
485
  this._onError(event);
@@ -468,6 +490,7 @@ export abstract class ResponsesWSBase<TSocket extends WebSocketLike> extends Res
468
490
  });
469
491
 
470
492
  socket.on('error', (err: Error) => {
493
+ recordWebSocketError(socket, err);
471
494
  // Suppress transient errors during reconnection — the retry loop
472
495
  // already handles them and will surface a close if retries exhaust.
473
496
  if (this._isReconnecting) return;
@@ -4,7 +4,6 @@ import * as WS from 'ws';
4
4
  import { NodeWebSocket } from '../../../internal/ws-adapter-node';
5
5
  import { ResponsesWSBase, type ResponsesWSBaseOptions } from './ws-base';
6
6
  import { OpenAI } from '../../../client';
7
- import { VERSION } from '../../../version';
8
7
  import { OpenAIError } from '../../../core/error';
9
8
  import { snapshotWebSocketCredentials } from '../../../internal/ws';
10
9
 
@@ -34,13 +33,17 @@ export class ResponsesWS extends ResponsesWSBase<NodeWebSocket> {
34
33
 
35
34
  protected _createSocket(url: URL, authHeaders: Record<string, string>): NodeWebSocket {
36
35
  const capturedAuthHeaders = { ...authHeaders };
36
+ const headers = new Map(Object.entries(this._client._buildWebSocketHeaders(capturedAuthHeaders)));
37
+ for (const [name, value] of Object.entries(this._wsOptions?.headers ?? {})) {
38
+ if (value === null) {
39
+ headers.delete(name.toLowerCase());
40
+ } else if (value !== undefined) {
41
+ headers.set(name.toLowerCase(), value);
42
+ }
43
+ }
37
44
  const socketOptions: ResponsesWSClientOptions = {
38
45
  ...this._wsOptions,
39
- headers: {
40
- 'User-Agent': `${this._client.constructor.name}/JS ${VERSION}`,
41
- ...capturedAuthHeaders,
42
- ...this._wsOptions?.headers,
43
- },
46
+ headers: Object.fromEntries(headers),
44
47
  followRedirects: false,
45
48
  };
46
49
  if (
@@ -4,7 +4,6 @@ import * as WS from 'ws';
4
4
  import { NodeWebSocket } from '../../../internal/ws-adapter-node';
5
5
  import { ForksWSBase, type ForksWSBaseOptions, type ForksWSParameters } from './ws-base';
6
6
  import { OpenAI } from '../../../client';
7
- import { VERSION } from '../../../version';
8
7
 
9
8
  export type { WebSocketStreamOptions } from '../../../internal/ws';
10
9
 
@@ -36,10 +35,10 @@ export class ForksWS extends ForksWSBase<NodeWebSocket> {
36
35
  const ws = new WS.WebSocket(url, {
37
36
  ...this._wsOptions,
38
37
  headers: {
39
- 'User-Agent': `${this._client.constructor.name}/JS ${VERSION}`,
40
-
41
- ...authHeaders,
42
- ...this._wsOptions?.headers,
38
+ ...this._client._buildWebSocketHeaders(authHeaders),
39
+ ...Object.fromEntries(
40
+ Object.entries(this._wsOptions?.headers ?? {}).map(([name, value]) => [name.toLowerCase(), value]),
41
+ ),
43
42
  },
44
43
  followRedirects: false,
45
44
  });
@@ -4,7 +4,6 @@ import * as WS from 'ws';
4
4
  import { NodeWebSocket } from '../../../internal/ws-adapter-node';
5
5
  import { SidebandWSBase, type SidebandWSBaseOptions, type SidebandWSParameters } from './ws-base';
6
6
  import { OpenAI } from '../../../client';
7
- import { VERSION } from '../../../version';
8
7
 
9
8
  export type { WebSocketStreamOptions } from '../../../internal/ws';
10
9
 
@@ -36,10 +35,10 @@ export class SidebandWS extends SidebandWSBase<NodeWebSocket> {
36
35
  const ws = new WS.WebSocket(url, {
37
36
  ...this._wsOptions,
38
37
  headers: {
39
- 'User-Agent': `${this._client.constructor.name}/JS ${VERSION}`,
40
-
41
- ...authHeaders,
42
- ...this._wsOptions?.headers,
38
+ ...this._client._buildWebSocketHeaders(authHeaders),
39
+ ...Object.fromEntries(
40
+ Object.entries(this._wsOptions?.headers ?? {}).map(([name, value]) => [name.toLowerCase(), value]),
41
+ ),
43
42
  },
44
43
  followRedirects: false,
45
44
  });
@@ -4,7 +4,6 @@ import * as WS from 'ws';
4
4
  import { NodeWebSocket } from '../../internal/ws-adapter-node';
5
5
  import { LiveWSBase, type LiveWSBaseOptions } from './ws-base';
6
6
  import { OpenAI } from '../../client';
7
- import { VERSION } from '../../version';
8
7
 
9
8
  export type { WebSocketStreamOptions } from '../../internal/ws';
10
9
 
@@ -32,10 +31,10 @@ export class LiveWS extends LiveWSBase<NodeWebSocket> {
32
31
  const ws = new WS.WebSocket(url, {
33
32
  ...this._wsOptions,
34
33
  headers: {
35
- 'User-Agent': `${this._client.constructor.name}/JS ${VERSION}`,
36
-
37
- ...authHeaders,
38
- ...this._wsOptions?.headers,
34
+ ...this._client._buildWebSocketHeaders(authHeaders),
35
+ ...Object.fromEntries(
36
+ Object.entries(this._wsOptions?.headers ?? {}).map(([name, value]) => [name.toLowerCase(), value]),
37
+ ),
39
38
  },
40
39
  followRedirects: false,
41
40
  });