@openai/agents-openai 0.13.1 → 0.13.2

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 (35) hide show
  1. package/dist/experimental/hostedMultiAgent/config.d.ts +7 -0
  2. package/dist/experimental/hostedMultiAgent/config.js +3 -0
  3. package/dist/experimental/hostedMultiAgent/config.js.map +1 -0
  4. package/dist/experimental/hostedMultiAgent/config.mjs +2 -0
  5. package/dist/experimental/hostedMultiAgent/config.mjs.map +1 -0
  6. package/dist/experimental/hostedMultiAgent/index.d.ts +3 -0
  7. package/dist/experimental/hostedMultiAgent/index.js +8 -0
  8. package/dist/experimental/hostedMultiAgent/index.js.map +1 -0
  9. package/dist/experimental/hostedMultiAgent/index.mjs +3 -0
  10. package/dist/experimental/hostedMultiAgent/index.mjs.map +1 -0
  11. package/dist/experimental/hostedMultiAgent/metadata.d.ts +8 -0
  12. package/dist/experimental/hostedMultiAgent/metadata.js +36 -0
  13. package/dist/experimental/hostedMultiAgent/metadata.js.map +1 -0
  14. package/dist/experimental/hostedMultiAgent/metadata.mjs +33 -0
  15. package/dist/experimental/hostedMultiAgent/metadata.mjs.map +1 -0
  16. package/dist/experimental/hostedMultiAgent/model.d.ts +28 -0
  17. package/dist/experimental/hostedMultiAgent/model.js +677 -0
  18. package/dist/experimental/hostedMultiAgent/model.js.map +1 -0
  19. package/dist/experimental/hostedMultiAgent/model.mjs +670 -0
  20. package/dist/experimental/hostedMultiAgent/model.mjs.map +1 -0
  21. package/dist/metadata.js +2 -2
  22. package/dist/metadata.mjs +2 -2
  23. package/dist/openaiChatCompletionsConverter.js +12 -0
  24. package/dist/openaiChatCompletionsConverter.js.map +1 -1
  25. package/dist/openaiChatCompletionsConverter.mjs +12 -0
  26. package/dist/openaiChatCompletionsConverter.mjs.map +1 -1
  27. package/dist/openaiChatCompletionsModel.js +27 -0
  28. package/dist/openaiChatCompletionsModel.js.map +1 -1
  29. package/dist/openaiChatCompletionsModel.mjs +27 -0
  30. package/dist/openaiChatCompletionsModel.mjs.map +1 -1
  31. package/dist/openaiResponsesModel.js +106 -45
  32. package/dist/openaiResponsesModel.js.map +1 -1
  33. package/dist/openaiResponsesModel.mjs +106 -45
  34. package/dist/openaiResponsesModel.mjs.map +1 -1
  35. package/package.json +14 -2
@@ -0,0 +1,677 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.OpenAIHostedMultiAgentModel = void 0;
7
+ const agents_core_1 = require("@openai/agents-core");
8
+ const openai_1 = __importDefault(require("openai"));
9
+ const ws_1 = require("openai/resources/beta/responses/ws");
10
+ const defaults_1 = require("../../defaults.js");
11
+ const openaiResponsesModel_1 = require("../../openaiResponsesModel.js");
12
+ const responsesTransportUtils_1 = require("../../responsesTransportUtils.js");
13
+ const responsesWebSocketConnection_1 = require("../../responsesWebSocketConnection.js");
14
+ const responsesUtils_1 = require("../../responsesUtils.js");
15
+ const ROOT_AGENT_NAME = '/root';
16
+ const MULTI_AGENT_BETA = 'responses_multi_agent=v1';
17
+ const HOSTED_COLLABORATION_ITEM_TYPES = new Set([
18
+ 'agent_message',
19
+ 'multi_agent_call',
20
+ 'multi_agent_call_output',
21
+ ]);
22
+ const HOSTED_TERMINAL_RESPONSE_EVENT_TYPES = new Set([
23
+ 'response.completed',
24
+ 'response.failed',
25
+ 'response.incomplete',
26
+ 'response.error',
27
+ ]);
28
+ const WEBSOCKET_CONNECTING_READY_STATE = 0;
29
+ const WEBSOCKET_OPEN_READY_STATE = 1;
30
+ function isReusableWebSocket(webSocket) {
31
+ return (webSocket.socket.readyState === WEBSOCKET_CONNECTING_READY_STATE ||
32
+ webSocket.socket.readyState === WEBSOCKET_OPEN_READY_STATE);
33
+ }
34
+ function isHostedTerminalResponseEventType(eventType) {
35
+ return (typeof eventType === 'string' &&
36
+ HOSTED_TERMINAL_RESPONSE_EVENT_TYPES.has(eventType));
37
+ }
38
+ class HostedMultiAgentWebSocketClosedError extends Error {
39
+ frameWasUnsent;
40
+ constructor(message, frameWasUnsent) {
41
+ super(message);
42
+ this.frameWasUnsent = frameWasUnsent;
43
+ this.name = 'HostedMultiAgentWebSocketClosedError';
44
+ }
45
+ }
46
+ function createWebSocketClient(client, extraQuery) {
47
+ const websocketClient = Object.create(client);
48
+ // ResponsesWS adds client.apiKey after applying the finalized header merge.
49
+ // Keep authentication entirely in the explicit headers so null unsets survive.
50
+ websocketClient.apiKey = null;
51
+ websocketClient.buildURL = (path, query, defaultBaseURL) => {
52
+ const url = new URL(client.buildURL(path, query, defaultBaseURL));
53
+ (0, responsesTransportUtils_1.mergeQueryParamsIntoURL)(url, extraQuery);
54
+ return url.toString();
55
+ };
56
+ return websocketClient;
57
+ }
58
+ function mergeResponseUsages(usages) {
59
+ return new agents_core_1.Usage({
60
+ requests: usages.length,
61
+ inputTokens: usages.reduce((total, usage) => total + (usage?.input_tokens ?? 0), 0),
62
+ outputTokens: usages.reduce((total, usage) => total + (usage?.output_tokens ?? 0), 0),
63
+ totalTokens: usages.reduce((total, usage) => total + (usage?.total_tokens ?? 0), 0),
64
+ inputTokensDetails: usages.map((usage) => ({
65
+ ...usage?.input_tokens_details,
66
+ })),
67
+ outputTokensDetails: usages.map((usage) => ({
68
+ ...usage?.output_tokens_details,
69
+ })),
70
+ requestUsageEntries: usages.map((usage) => (0, responsesUtils_1.toRequestUsageEntry)(usage, 'responses.create')),
71
+ });
72
+ }
73
+ function sortedEntries(record) {
74
+ return Object.entries(record).sort(([left], [right]) => left.localeCompare(right));
75
+ }
76
+ function getTransportOverridesKey(client, options) {
77
+ const websocketClient = createWebSocketClient(client, options.extraQuery);
78
+ const url = websocketClient.buildURL('/responses', {}, undefined);
79
+ const headerAccumulator = (0, responsesTransportUtils_1.createHeaderAccumulator)();
80
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, options.extraHeaders, {
81
+ allowBlockedOverride: true,
82
+ });
83
+ return JSON.stringify([
84
+ url,
85
+ sortedEntries((0, responsesTransportUtils_1.headerAccumulatorToRecord)(headerAccumulator)),
86
+ [...headerAccumulator.blockedLowercaseNames].sort(),
87
+ ]);
88
+ }
89
+ function validateConfig(config) {
90
+ const maxConcurrentSubagents = config?.maxConcurrentSubagents;
91
+ if (typeof maxConcurrentSubagents !== 'undefined' &&
92
+ (!Number.isInteger(maxConcurrentSubagents) || maxConcurrentSubagents <= 0)) {
93
+ throw new agents_core_1.UserError('HostedMultiAgentConfig.maxConcurrentSubagents must be a positive integer.');
94
+ }
95
+ return Object.freeze(typeof maxConcurrentSubagents === 'undefined'
96
+ ? {}
97
+ : { maxConcurrentSubagents });
98
+ }
99
+ function isRootFinalMessage(item) {
100
+ return (item.type === 'message' &&
101
+ item.agent?.agent_name === ROOT_AGENT_NAME &&
102
+ item.phase === 'final_answer');
103
+ }
104
+ function toResponseCreateFrame(requestData) {
105
+ const { betas: _betas, stream: _stream, ...frame } = requestData;
106
+ return { ...frame, type: 'response.create' };
107
+ }
108
+ function getFunctionCallOutputs(requestData, pendingCallIds) {
109
+ if (!Array.isArray(requestData.input)) {
110
+ return [];
111
+ }
112
+ return requestData.input.filter((item) => Boolean(item &&
113
+ typeof item === 'object' &&
114
+ item.type === 'function_call_output' &&
115
+ typeof item.call_id === 'string' &&
116
+ pendingCallIds.has(item.call_id)));
117
+ }
118
+ /**
119
+ * Experimental OpenAI Responses model that opts into service-hosted Multi-agent orchestration.
120
+ *
121
+ * The hosted beta requires a persistent Responses WebSocket because local tool outputs must be
122
+ * injected into the active response. Call {@link close} when the model is no longer needed.
123
+ */
124
+ class OpenAIHostedMultiAgentModel extends openaiResponsesModel_1.OpenAIResponsesModel {
125
+ config;
126
+ #webSocket;
127
+ #webSocketIterator;
128
+ #webSocketConnectionKey;
129
+ #webSocketTransportOverridesKey;
130
+ #activeResponse;
131
+ #normalizedResponses = new WeakMap();
132
+ #responseUsages = new WeakMap();
133
+ #syntheticBoundaryEvents = new WeakSet();
134
+ #requestInProgress = false;
135
+ constructor(client, model, config) {
136
+ super(client, model);
137
+ this.config = validateConfig(config);
138
+ }
139
+ getRetryAdvice(args) {
140
+ if (args.error instanceof HostedMultiAgentWebSocketClosedError &&
141
+ args.error.frameWasUnsent) {
142
+ return {
143
+ suggested: true,
144
+ replaySafety: 'safe',
145
+ reason: args.error.message,
146
+ };
147
+ }
148
+ return super.getRetryAdvice(args);
149
+ }
150
+ /** Close the persistent Responses WebSocket owned by this model. */
151
+ async close() {
152
+ this.#activeResponse = undefined;
153
+ this.#dropWebSocketConnection();
154
+ }
155
+ #dropWebSocketConnection() {
156
+ this.#webSocketIterator = undefined;
157
+ const webSocket = this.#webSocket;
158
+ this.#webSocket = undefined;
159
+ this.#webSocketConnectionKey = undefined;
160
+ this.#webSocketTransportOverridesKey = undefined;
161
+ webSocket?.close();
162
+ }
163
+ /** @internal */
164
+ _createResponsesWebSocket(options) {
165
+ return new ws_1.ResponsesWS(options.client, {
166
+ headers: options.headers,
167
+ });
168
+ }
169
+ _getResponsesCreateRequestOverrides(request, requestData) {
170
+ if (request.handoffs.length > 0) {
171
+ throw new agents_core_1.UserError('OpenAIHostedMultiAgentModel does not support SDK handoffs. Remove the Agent handoffs or use OpenAIResponsesModel.');
172
+ }
173
+ if (requestData.reasoning?.summary != null) {
174
+ throw new agents_core_1.UserError('OpenAIHostedMultiAgentModel does not support reasoning.summary. Remove the reasoning summary setting.');
175
+ }
176
+ if (requestData.max_tool_calls != null) {
177
+ throw new agents_core_1.UserError('OpenAIHostedMultiAgentModel does not support max_tool_calls. Remove that provider setting.');
178
+ }
179
+ return {
180
+ multi_agent: {
181
+ enabled: true,
182
+ ...(typeof this.config.maxConcurrentSubagents === 'number'
183
+ ? {
184
+ max_concurrent_subagents: this.config.maxConcurrentSubagents,
185
+ }
186
+ : {}),
187
+ },
188
+ };
189
+ }
190
+ _convertResponseOutputItems(items) {
191
+ const stableItems = items.filter((item) => !HOSTED_COLLABORATION_ITEM_TYPES.has(item.type) &&
192
+ (item.type !== 'message' || isRootFinalMessage(item)));
193
+ return (0, openaiResponsesModel_1.convertToOutputItem)(stableItems);
194
+ }
195
+ _getResponseForSDKOutput(response) {
196
+ return this.#normalizedResponses.get(response) ?? response;
197
+ }
198
+ _getResponseUsage(response) {
199
+ return (this.#responseUsages.get(response) ?? super._getResponseUsage(response));
200
+ }
201
+ _getStreamedResponseUsage(response) {
202
+ return (this.#responseUsages.get(response) ??
203
+ super._getStreamedResponseUsage(response));
204
+ }
205
+ _shouldEmitOutputTextDelta(event, outputItem) {
206
+ const agentName = event.agent?.agent_name;
207
+ return (Boolean(outputItem && isRootFinalMessage(outputItem)) &&
208
+ (typeof agentName === 'undefined' || agentName === ROOT_AGENT_NAME));
209
+ }
210
+ _shouldEmitRawModelEvent(event) {
211
+ return !this.#syntheticBoundaryEvents.has(event);
212
+ }
213
+ async _fetchResponse(request, stream) {
214
+ const events = this.#runWebSocketTurn(request);
215
+ if (stream) {
216
+ return events;
217
+ }
218
+ let response;
219
+ for await (const event of events) {
220
+ if (isHostedTerminalResponseEventType(event.type)) {
221
+ response = event.response;
222
+ }
223
+ }
224
+ if (!response) {
225
+ throw new Error('Hosted Multi-agent WebSocket turn ended without a response boundary.');
226
+ }
227
+ return response;
228
+ }
229
+ async *#runWebSocketTurn(request) {
230
+ if (this.#requestInProgress) {
231
+ throw new agents_core_1.UserError('OpenAIHostedMultiAgentModel does not support concurrent requests on one model instance.');
232
+ }
233
+ this.#requestInProgress = true;
234
+ const hadActiveResponse = Boolean(this.#activeResponse);
235
+ let sentWebSocketFrame = false;
236
+ let sentWebSocketFrameType;
237
+ let receivedServerMessage = false;
238
+ let requestMayHaveReachedServer = false;
239
+ let sentFrameWasReturnedUnsent = false;
240
+ let reachedResponseBoundary = false;
241
+ let threwError = false;
242
+ const requestTimeoutDeadline = this.#createWebSocketRequestTimeoutDeadline();
243
+ const sendWebSocketFrame = (webSocket, frame, signal) => {
244
+ if (signal?.aborted) {
245
+ throw new openai_1.default.APIUserAbortError();
246
+ }
247
+ sentWebSocketFrame = true;
248
+ sentWebSocketFrameType = frame.type;
249
+ if (webSocket.socket.readyState === WEBSOCKET_OPEN_READY_STATE) {
250
+ requestMayHaveReachedServer = true;
251
+ }
252
+ webSocket.send(frame);
253
+ };
254
+ try {
255
+ const builtRequest = this._buildResponsesCreateRequest(request, true);
256
+ const requestData = builtRequest.requestData;
257
+ const webSocket = await this.#ensureWebSocket({
258
+ extraHeaders: builtRequest.transportExtraHeaders,
259
+ extraQuery: builtRequest.transportExtraQuery,
260
+ }, Boolean(this.#activeResponse), builtRequest.signal, requestTimeoutDeadline);
261
+ let pendingInjections = 0;
262
+ const injectingCallIds = new Set();
263
+ if (this.#activeResponse) {
264
+ const activeResponse = this.#activeResponse;
265
+ if (activeResponse.pendingContinuationFrame) {
266
+ sendWebSocketFrame(webSocket, activeResponse.pendingContinuationFrame, builtRequest.signal);
267
+ }
268
+ else {
269
+ const outputs = getFunctionCallOutputs(requestData, activeResponse.pendingCallIds);
270
+ const outputCallIds = new Set(outputs.map((output) => output.call_id));
271
+ const missingCallIds = Array.from(activeResponse.pendingCallIds).filter((callId) => !outputCallIds.has(callId));
272
+ if (missingCallIds.length > 0) {
273
+ throw new agents_core_1.UserError(`The hosted response is waiting for local function outputs for: ${missingCallIds.join(', ')}. Resume it with the same model instance and RunState.`);
274
+ }
275
+ if (activeResponse.terminalEvent) {
276
+ const continuationFrame = this.#prepareTerminalContinuation(activeResponse, requestData, outputs);
277
+ sendWebSocketFrame(webSocket, continuationFrame, builtRequest.signal);
278
+ }
279
+ else {
280
+ if (outputs.length === 0 || !activeResponse.responseId) {
281
+ throw new agents_core_1.UserError('The hosted response is waiting for local function outputs. Resume it with the same model instance and RunState.');
282
+ }
283
+ pendingInjections = 1;
284
+ for (const output of outputs) {
285
+ injectingCallIds.add(output.call_id);
286
+ }
287
+ sendWebSocketFrame(webSocket, {
288
+ type: 'response.inject',
289
+ response_id: activeResponse.responseId,
290
+ input: outputs,
291
+ }, builtRequest.signal);
292
+ }
293
+ }
294
+ }
295
+ else {
296
+ this.#activeResponse = {
297
+ responseCreateInput: Array.isArray(requestData.input)
298
+ ? [...requestData.input]
299
+ : [],
300
+ responseCreatePreviousResponseId: typeof requestData.previous_response_id === 'string'
301
+ ? requestData.previous_response_id
302
+ : undefined,
303
+ responseStored: requestData.store !== false,
304
+ pendingCallIds: new Set(),
305
+ emittedCallIds: new Set(),
306
+ queuedFunctionCalls: [],
307
+ fallbackInput: [],
308
+ requestUsages: [],
309
+ };
310
+ sendWebSocketFrame(webSocket, toResponseCreateFrame(requestData), builtRequest.signal);
311
+ }
312
+ while (true) {
313
+ const message = await this.#nextWebSocketMessage(builtRequest.signal, requestTimeoutDeadline);
314
+ if (!message) {
315
+ throw new Error('Hosted Multi-agent WebSocket closed before a response boundary.');
316
+ }
317
+ if (message.type === 'open' || message.type === 'reconnected') {
318
+ requestMayHaveReachedServer = true;
319
+ }
320
+ if (message.type === 'error') {
321
+ throw message.error;
322
+ }
323
+ if (message.type === 'close') {
324
+ const currentFrameWasReturnedUnsent = sentWebSocketFrame &&
325
+ typeof sentWebSocketFrameType === 'string' &&
326
+ Array.isArray(message.unsent) &&
327
+ message.unsent.some((item) => {
328
+ const unsentFrame = item?.type === 'message' ? item.message : item;
329
+ return unsentFrame?.type === sentWebSocketFrameType;
330
+ });
331
+ if (currentFrameWasReturnedUnsent) {
332
+ requestMayHaveReachedServer = false;
333
+ sentFrameWasReturnedUnsent = true;
334
+ }
335
+ throw new HostedMultiAgentWebSocketClosedError(`Hosted Multi-agent WebSocket closed (${String(message.code)}): ${String(message.reason ?? '')}`, currentFrameWasReturnedUnsent);
336
+ }
337
+ if (message.type !== 'message') {
338
+ continue;
339
+ }
340
+ receivedServerMessage = true;
341
+ requestMayHaveReachedServer = true;
342
+ const event = message.message;
343
+ const eventType = event.type;
344
+ const activeResponse = this.#activeResponse;
345
+ if (!activeResponse) {
346
+ throw new Error('Hosted Multi-agent response state was lost.');
347
+ }
348
+ if (eventType === 'response.created') {
349
+ activeResponse.responseId = event.response?.id;
350
+ activeResponse.responseTemplate = event.response;
351
+ activeResponse.pendingContinuationFrame = undefined;
352
+ }
353
+ else if (eventType === 'response.output_item.done') {
354
+ const item = event.item;
355
+ if (item) {
356
+ if (item.type === 'function_call' &&
357
+ typeof item.call_id === 'string') {
358
+ activeResponse.pendingCallIds.add(item.call_id);
359
+ if (!activeResponse.emittedCallIds.has(item.call_id) &&
360
+ !activeResponse.queuedFunctionCalls.some((queued) => queued.call_id === item.call_id)) {
361
+ activeResponse.queuedFunctionCalls.push(item);
362
+ }
363
+ }
364
+ }
365
+ }
366
+ else if (eventType === 'response.inject.created') {
367
+ pendingInjections = Math.max(0, pendingInjections - 1);
368
+ for (const callId of injectingCallIds) {
369
+ activeResponse.pendingCallIds.delete(callId);
370
+ }
371
+ }
372
+ else if (eventType === 'response.inject.failed') {
373
+ pendingInjections = Math.max(0, pendingInjections - 1);
374
+ if (event.error?.code !== 'response_already_completed') {
375
+ throw new Error(`Hosted Multi-agent response injection failed: ${JSON.stringify(event.error)}`);
376
+ }
377
+ if (Array.isArray(event.input)) {
378
+ activeResponse.fallbackInput.push(...event.input);
379
+ }
380
+ for (const callId of injectingCallIds) {
381
+ activeResponse.pendingCallIds.delete(callId);
382
+ }
383
+ }
384
+ else if (isHostedTerminalResponseEventType(eventType)) {
385
+ activeResponse.terminalEvent = event;
386
+ }
387
+ else if (eventType === 'error') {
388
+ throw new Error(`Hosted Multi-agent WebSocket response failed: ${JSON.stringify(event)}`);
389
+ }
390
+ if (!isHostedTerminalResponseEventType(eventType)) {
391
+ yield event;
392
+ }
393
+ if (activeResponse.queuedFunctionCalls.length > 0 &&
394
+ pendingInjections === 0) {
395
+ const functionCalls = activeResponse.queuedFunctionCalls.splice(0);
396
+ const partialResponse = this.#buildBoundaryResponse(functionCalls);
397
+ const boundaryEvent = {
398
+ type: 'response.completed',
399
+ response: partialResponse,
400
+ };
401
+ this.#syntheticBoundaryEvents.add(boundaryEvent);
402
+ reachedResponseBoundary = true;
403
+ yield boundaryEvent;
404
+ return;
405
+ }
406
+ if (activeResponse.terminalEvent && pendingInjections === 0) {
407
+ if (activeResponse.fallbackInput.length > 0) {
408
+ const continuationFrame = this.#prepareTerminalContinuation(activeResponse, requestData, []);
409
+ sendWebSocketFrame(webSocket, continuationFrame, builtRequest.signal);
410
+ injectingCallIds.clear();
411
+ continue;
412
+ }
413
+ const terminalEvent = activeResponse.terminalEvent;
414
+ const response = terminalEvent.response;
415
+ const normalizedResponse = {
416
+ ...response,
417
+ output: (Array.isArray(response.output)
418
+ ? response.output
419
+ : []).filter((item) => item.type !== 'function_call' ||
420
+ !activeResponse.emittedCallIds.has(item.call_id)),
421
+ };
422
+ this.#normalizedResponses.set(response, normalizedResponse);
423
+ this.#responseUsages.set(response, mergeResponseUsages([
424
+ ...activeResponse.requestUsages,
425
+ response.usage,
426
+ ]));
427
+ this.#activeResponse = undefined;
428
+ reachedResponseBoundary = true;
429
+ yield terminalEvent;
430
+ return;
431
+ }
432
+ }
433
+ }
434
+ catch (error) {
435
+ threwError = true;
436
+ if (requestMayHaveReachedServer && error instanceof Error) {
437
+ error.unsafeToReplay = true;
438
+ }
439
+ if (hadActiveResponse && sentFrameWasReturnedUnsent) {
440
+ const transportOverridesKey = this.#webSocketTransportOverridesKey;
441
+ this.#dropWebSocketConnection();
442
+ this.#webSocketTransportOverridesKey = transportOverridesKey;
443
+ }
444
+ else if (!hadActiveResponse ||
445
+ sentWebSocketFrame ||
446
+ receivedServerMessage) {
447
+ await this.close();
448
+ }
449
+ throw error;
450
+ }
451
+ finally {
452
+ try {
453
+ if (!threwError && !reachedResponseBoundary) {
454
+ await this.close();
455
+ }
456
+ }
457
+ finally {
458
+ this.#requestInProgress = false;
459
+ }
460
+ }
461
+ }
462
+ #buildBoundaryResponse(functionCalls) {
463
+ const activeResponse = this.#activeResponse;
464
+ if (!activeResponse?.responseTemplate || !activeResponse.responseId) {
465
+ throw new Error('Hosted Multi-agent function call arrived before response.created.');
466
+ }
467
+ for (const functionCall of functionCalls) {
468
+ activeResponse.emittedCallIds.add(functionCall.call_id);
469
+ }
470
+ const boundaryResponse = {
471
+ ...activeResponse.responseTemplate,
472
+ id: activeResponse.responseId,
473
+ status: 'completed',
474
+ output: functionCalls,
475
+ usage: undefined,
476
+ };
477
+ this.#responseUsages.set(boundaryResponse, new agents_core_1.Usage());
478
+ return boundaryResponse;
479
+ }
480
+ #prepareTerminalContinuation(activeResponse, requestData, functionOutputs) {
481
+ const terminalResponse = activeResponse.terminalEvent?.response;
482
+ if (!terminalResponse?.id) {
483
+ throw new Error('Hosted Multi-agent could not continue after a terminal response.');
484
+ }
485
+ const continuationInput = [
486
+ ...activeResponse.fallbackInput,
487
+ ...functionOutputs,
488
+ ];
489
+ if (continuationInput.length === 0) {
490
+ throw new Error('Hosted Multi-agent terminal response continuation requires function outputs.');
491
+ }
492
+ activeResponse.requestUsages.push(terminalResponse.usage);
493
+ const terminalResponseStored = typeof terminalResponse.store === 'boolean'
494
+ ? terminalResponse.store
495
+ : activeResponse.responseStored;
496
+ const fallbackFrame = toResponseCreateFrame(requestData);
497
+ if (fallbackFrame.conversation != null) {
498
+ fallbackFrame.input = continuationInput;
499
+ delete fallbackFrame.previous_response_id;
500
+ }
501
+ else if (terminalResponseStored) {
502
+ fallbackFrame.input = continuationInput;
503
+ fallbackFrame.previous_response_id = terminalResponse.id;
504
+ }
505
+ else {
506
+ fallbackFrame.input = [
507
+ ...activeResponse.responseCreateInput,
508
+ ...(Array.isArray(terminalResponse.output)
509
+ ? terminalResponse.output
510
+ : []),
511
+ ...continuationInput,
512
+ ];
513
+ if (activeResponse.responseCreatePreviousResponseId) {
514
+ fallbackFrame.previous_response_id =
515
+ activeResponse.responseCreatePreviousResponseId;
516
+ }
517
+ else {
518
+ delete fallbackFrame.previous_response_id;
519
+ }
520
+ }
521
+ activeResponse.responseCreateInput = Array.isArray(fallbackFrame.input)
522
+ ? [...fallbackFrame.input]
523
+ : [];
524
+ activeResponse.responseCreatePreviousResponseId =
525
+ typeof fallbackFrame.previous_response_id === 'string'
526
+ ? fallbackFrame.previous_response_id
527
+ : undefined;
528
+ activeResponse.responseStored = fallbackFrame.store !== false;
529
+ activeResponse.responseId = undefined;
530
+ activeResponse.responseTemplate = undefined;
531
+ activeResponse.pendingCallIds.clear();
532
+ activeResponse.queuedFunctionCalls = [];
533
+ activeResponse.terminalEvent = undefined;
534
+ activeResponse.fallbackInput = [];
535
+ activeResponse.pendingContinuationFrame = fallbackFrame;
536
+ return fallbackFrame;
537
+ }
538
+ async #ensureWebSocket(transportOptions, activeResponse, signal, requestTimeoutDeadline) {
539
+ if (signal?.aborted) {
540
+ throw new openai_1.default.APIUserAbortError();
541
+ }
542
+ const transportOverridesKey = getTransportOverridesKey(this._client, transportOptions);
543
+ if (activeResponse) {
544
+ if (transportOverridesKey !== this.#webSocketTransportOverridesKey) {
545
+ throw new agents_core_1.UserError('An active hosted response must be resumed with the same WebSocket transport headers and query.');
546
+ }
547
+ if (this.#webSocket) {
548
+ if (isReusableWebSocket(this.#webSocket)) {
549
+ return this.#webSocket;
550
+ }
551
+ this.#dropWebSocketConnection();
552
+ this.#webSocketTransportOverridesKey = transportOverridesKey;
553
+ }
554
+ }
555
+ const creationOptions = await this.#prepareWebSocketCreationOptions(transportOptions, signal, requestTimeoutDeadline);
556
+ const connectionURL = creationOptions.client.buildURL('/responses', {}, undefined);
557
+ const connectionKey = JSON.stringify([
558
+ connectionURL,
559
+ sortedEntries(creationOptions.headers),
560
+ ]);
561
+ if (!activeResponse &&
562
+ this.#webSocket &&
563
+ !isReusableWebSocket(this.#webSocket)) {
564
+ await this.close();
565
+ }
566
+ if (this.#webSocket && this.#webSocketConnectionKey !== connectionKey) {
567
+ await this.close();
568
+ }
569
+ if (!this.#webSocket) {
570
+ this.#webSocket = this._createResponsesWebSocket(creationOptions);
571
+ this.#webSocketIterator = this.#webSocket[Symbol.asyncIterator]();
572
+ this.#webSocketConnectionKey = connectionKey;
573
+ }
574
+ this.#webSocketTransportOverridesKey = transportOverridesKey;
575
+ return this.#webSocket;
576
+ }
577
+ async #prepareWebSocketCreationOptions(transportOptions, signal, requestTimeoutDeadline) {
578
+ const client = this._client;
579
+ if (typeof client._callApiKey === 'function') {
580
+ await this.#awaitWebSocketRequestTimedOperation(client._callApiKey(), signal, requestTimeoutDeadline, (configuredTimeoutMs) => `Hosted Multi-agent WebSocket auth header preparation timed out after ${configuredTimeoutMs}ms.`);
581
+ }
582
+ const websocketClient = createWebSocketClient(client, transportOptions.extraQuery);
583
+ const websocketURL = new URL(websocketClient.buildURL('/responses', {}, undefined));
584
+ const authHeaderQuery = (0, responsesUtils_1.searchParamsToAuthHeaderQuery)(websocketURL.searchParams);
585
+ const authHeaders = typeof client.authHeaders === 'function'
586
+ ? await this.#awaitWebSocketRequestTimedOperation(client.authHeaders({
587
+ method: 'get',
588
+ path: websocketURL.pathname,
589
+ ...(authHeaderQuery ? { query: authHeaderQuery } : {}),
590
+ }), signal, requestTimeoutDeadline, (configuredTimeoutMs) => `Hosted Multi-agent WebSocket auth header preparation timed out after ${configuredTimeoutMs}ms.`)
591
+ : undefined;
592
+ const headerAccumulator = (0, responsesTransportUtils_1.createHeaderAccumulator)();
593
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, authHeaders);
594
+ if (typeof client.authHeaders !== 'function' &&
595
+ typeof client.apiKey === 'string' &&
596
+ client.apiKey.length > 0 &&
597
+ client.apiKey !== 'Missing Key') {
598
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, {
599
+ Authorization: `Bearer ${client.apiKey}`,
600
+ });
601
+ }
602
+ if (client.organization) {
603
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, {
604
+ 'OpenAI-Organization': client.organization,
605
+ });
606
+ }
607
+ if (client.project) {
608
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, {
609
+ 'OpenAI-Project': client.project,
610
+ });
611
+ }
612
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, client._options?.defaultHeaders);
613
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, defaults_1.HEADERS);
614
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, transportOptions.extraHeaders, { allowBlockedOverride: true });
615
+ (0, responsesTransportUtils_1.applyHeadersToAccumulator)(headerAccumulator, { 'OpenAI-Beta': MULTI_AGENT_BETA }, { allowBlockedOverride: true });
616
+ return {
617
+ client: websocketClient,
618
+ headers: (0, responsesTransportUtils_1.headerAccumulatorToRecord)(headerAccumulator),
619
+ };
620
+ }
621
+ async #nextWebSocketMessage(signal, requestTimeoutDeadline) {
622
+ if (signal?.aborted) {
623
+ throw new openai_1.default.APIUserAbortError();
624
+ }
625
+ const iterator = this.#webSocketIterator;
626
+ if (!iterator) {
627
+ throw new Error('Hosted Multi-agent WebSocket iterator is unavailable.');
628
+ }
629
+ const frameReadTimeout = this.#resolveWebSocketRequestTimeout(requestTimeoutDeadline, (configuredTimeoutMs) => `Hosted Multi-agent WebSocket frame read timed out after ${configuredTimeoutMs}ms.`);
630
+ const result = await (0, responsesWebSocketConnection_1.withAbortSignal)((0, responsesWebSocketConnection_1.withTimeout)(iterator.next(), frameReadTimeout.timeoutMs, frameReadTimeout.errorMessage), signal);
631
+ return result.done ? undefined : result.value;
632
+ }
633
+ #getWebSocketFrameReadTimeoutMs() {
634
+ const client = this._client;
635
+ const timeoutCandidate = typeof client.timeout === 'number'
636
+ ? client.timeout
637
+ : client._options?.timeout;
638
+ if (typeof timeoutCandidate === 'number') {
639
+ return timeoutCandidate;
640
+ }
641
+ return openai_1.default.DEFAULT_TIMEOUT;
642
+ }
643
+ #createWebSocketRequestTimeoutDeadline() {
644
+ const timeoutMs = this.#getWebSocketFrameReadTimeoutMs();
645
+ if (typeof timeoutMs !== 'number' ||
646
+ !Number.isFinite(timeoutMs) ||
647
+ timeoutMs <= 0) {
648
+ return undefined;
649
+ }
650
+ return {
651
+ configuredTimeoutMs: timeoutMs,
652
+ deadlineAtMs: Date.now() + timeoutMs,
653
+ };
654
+ }
655
+ #resolveWebSocketRequestTimeout(requestTimeoutDeadline, errorMessageForConfiguredTimeout) {
656
+ const configuredTimeoutMs = requestTimeoutDeadline?.configuredTimeoutMs ??
657
+ this.#getWebSocketFrameReadTimeoutMs();
658
+ const safeConfiguredTimeoutMs = typeof configuredTimeoutMs === 'number'
659
+ ? configuredTimeoutMs
660
+ : openai_1.default.DEFAULT_TIMEOUT;
661
+ const errorMessage = errorMessageForConfiguredTimeout(safeConfiguredTimeoutMs);
662
+ if (!requestTimeoutDeadline) {
663
+ return { timeoutMs: configuredTimeoutMs, errorMessage };
664
+ }
665
+ const remainingTimeoutMs = Math.ceil(requestTimeoutDeadline.deadlineAtMs - Date.now());
666
+ if (remainingTimeoutMs <= 0) {
667
+ throw new Error(errorMessage);
668
+ }
669
+ return { timeoutMs: remainingTimeoutMs, errorMessage };
670
+ }
671
+ async #awaitWebSocketRequestTimedOperation(promise, signal, requestTimeoutDeadline, errorMessageForConfiguredTimeout) {
672
+ const timeout = this.#resolveWebSocketRequestTimeout(requestTimeoutDeadline, errorMessageForConfiguredTimeout);
673
+ return await (0, responsesWebSocketConnection_1.withAbortSignal)((0, responsesWebSocketConnection_1.withTimeout)(promise, timeout.timeoutMs, timeout.errorMessage), signal);
674
+ }
675
+ }
676
+ exports.OpenAIHostedMultiAgentModel = OpenAIHostedMultiAgentModel;
677
+ //# sourceMappingURL=model.js.map