@yourgpt/llm-sdk 2.6.0-beta.0 → 2.6.0-beta.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 (64) hide show
  1. package/README.md +189 -0
  2. package/dist/adapters/index.d.mts +11 -13
  3. package/dist/adapters/index.d.ts +11 -13
  4. package/dist/adapters/index.js +610 -186
  5. package/dist/adapters/index.mjs +610 -186
  6. package/dist/audio-BBSwnjo8.d.mts +92 -0
  7. package/dist/audio-BBSwnjo8.d.ts +92 -0
  8. package/dist/{base-tNgbBaSo.d.mts → base-BICaQaRS.d.mts} +8 -3
  9. package/dist/{base-C58Dsr9p.d.ts → base-CpRPB8u8.d.ts} +8 -3
  10. package/dist/fallback/index.d.mts +4 -4
  11. package/dist/fallback/index.d.ts +4 -4
  12. package/dist/fallback/index.js +75 -39
  13. package/dist/fallback/index.mjs +75 -39
  14. package/dist/index.d.mts +18 -35
  15. package/dist/index.d.ts +18 -35
  16. package/dist/index.js +304 -88
  17. package/dist/index.mjs +302 -89
  18. package/dist/providers/anthropic/index.d.mts +3 -3
  19. package/dist/providers/anthropic/index.d.ts +3 -3
  20. package/dist/providers/anthropic/index.js +123 -7
  21. package/dist/providers/anthropic/index.mjs +123 -7
  22. package/dist/providers/azure/index.d.mts +3 -3
  23. package/dist/providers/azure/index.d.ts +3 -3
  24. package/dist/providers/azure/index.js +101 -4
  25. package/dist/providers/azure/index.mjs +101 -4
  26. package/dist/providers/fireworks/index.d.mts +3 -3
  27. package/dist/providers/fireworks/index.d.ts +3 -3
  28. package/dist/providers/fireworks/index.js +559 -178
  29. package/dist/providers/fireworks/index.mjs +559 -178
  30. package/dist/providers/google/index.d.mts +3 -3
  31. package/dist/providers/google/index.d.ts +3 -3
  32. package/dist/providers/google/index.js +559 -178
  33. package/dist/providers/google/index.mjs +559 -178
  34. package/dist/providers/ollama/index.d.mts +4 -4
  35. package/dist/providers/ollama/index.d.ts +4 -4
  36. package/dist/providers/ollama/index.js +87 -2
  37. package/dist/providers/ollama/index.mjs +87 -2
  38. package/dist/providers/openai/index.d.mts +25 -23
  39. package/dist/providers/openai/index.d.ts +25 -23
  40. package/dist/providers/openai/index.js +1397 -481
  41. package/dist/providers/openai/index.mjs +1396 -482
  42. package/dist/providers/openrouter/index.d.mts +3 -3
  43. package/dist/providers/openrouter/index.d.ts +3 -3
  44. package/dist/providers/openrouter/index.js +559 -178
  45. package/dist/providers/openrouter/index.mjs +559 -178
  46. package/dist/providers/togetherai/index.d.mts +3 -3
  47. package/dist/providers/togetherai/index.d.ts +3 -3
  48. package/dist/providers/togetherai/index.js +559 -178
  49. package/dist/providers/togetherai/index.mjs +559 -178
  50. package/dist/providers/xai/index.d.mts +3 -3
  51. package/dist/providers/xai/index.d.ts +3 -3
  52. package/dist/providers/xai/index.js +559 -178
  53. package/dist/providers/xai/index.mjs +559 -178
  54. package/dist/{types-B6dhnguR.d.mts → types-C3RgRbEC.d.mts} +11 -4
  55. package/dist/{types-CCxPmkmK.d.ts → types-DCFqkJAy.d.ts} +11 -4
  56. package/dist/{types-BQ31QIsA.d.ts → types-DHQEMFHA.d.mts} +3 -11
  57. package/dist/{types-BkQCSiIt.d.mts → types-Dg1Bcg1k.d.mts} +127 -3
  58. package/dist/{types-BkQCSiIt.d.ts → types-Dg1Bcg1k.d.ts} +127 -3
  59. package/dist/{types-BSSiJW2o.d.mts → types-Dikj3En4.d.ts} +3 -11
  60. package/dist/yourgpt/index.d.mts +1 -1
  61. package/dist/yourgpt/index.d.ts +1 -1
  62. package/docs/multimodal-and-audio.md +170 -0
  63. package/package.json +117 -49
  64. package/LICENSE +0 -21
@@ -1,3 +1,157 @@
1
+ // src/core/tool-output.ts
2
+ var imageTypes = /* @__PURE__ */ new Set([
3
+ "image/png",
4
+ "image/jpeg",
5
+ "image/webp",
6
+ "image/gif"
7
+ ]);
8
+ function normalizeToolOutput(value) {
9
+ const output = value;
10
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
11
+ throw new Error("Tool model output must contain a nonempty content array");
12
+ }
13
+ return {
14
+ type: "content",
15
+ content: output.content.map((part) => {
16
+ if (part?.type === "text" && typeof part.text === "string")
17
+ return { type: "text", text: part.text };
18
+ if (part?.type !== "image")
19
+ throw new Error("Unsupported tool output content type");
20
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
21
+ if (sources.length !== 1)
22
+ throw new Error(
23
+ "Tool image requires exactly one of data, url, or fileId"
24
+ );
25
+ if ("fileId" in part) {
26
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
27
+ throw new Error(
28
+ "Tool image file references must name the openai provider and fileId"
29
+ );
30
+ return { type: "image", fileId: part.fileId, provider: "openai" };
31
+ }
32
+ if ("url" in part) {
33
+ let url;
34
+ try {
35
+ url = new URL(part.url);
36
+ } catch {
37
+ throw new Error("Invalid tool image URL");
38
+ }
39
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
40
+ throw new Error(
41
+ "Tool image URL must use HTTP(S) without credentials"
42
+ );
43
+ return { type: "image", url: url.href };
44
+ }
45
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
46
+ throw new Error("Unsupported tool image media type");
47
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
48
+ if (typeof data !== "string")
49
+ throw new Error("Tool image data must be base64 or bytes");
50
+ if (data.startsWith("data:")) {
51
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
52
+ if (!match || match[1] !== part.mediaType)
53
+ throw new Error(
54
+ "Tool image data URL media type does not match mediaType"
55
+ );
56
+ data = match[2];
57
+ }
58
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
59
+ throw new Error("Invalid tool image base64 data");
60
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
61
+ throw new Error("Tool image exceeds 20 MiB");
62
+ if (Buffer.from(data, "base64").toString("base64") !== data)
63
+ throw new Error("Invalid tool image base64 data");
64
+ return { type: "image", data, mediaType: part.mediaType };
65
+ })
66
+ };
67
+ }
68
+ function toolOutputForProvider(value, provider) {
69
+ const output = normalizeToolOutput(value);
70
+ return output.content.map((part) => {
71
+ if (part.type === "text")
72
+ return {
73
+ type: provider === "responses" ? "input_text" : "text",
74
+ text: part.text
75
+ };
76
+ if (provider === "unsupported")
77
+ throw new Error(
78
+ "Image tool results require OpenAI Responses or Anthropic; this endpoint is not supported"
79
+ );
80
+ if ("fileId" in part) {
81
+ if (provider !== "responses")
82
+ throw new Error(
83
+ "OpenAI image file references cannot be sent to another provider"
84
+ );
85
+ return { type: "input_image", file_id: part.fileId, detail: "auto" };
86
+ }
87
+ if (provider === "responses")
88
+ return {
89
+ type: "input_image",
90
+ image_url: "url" in part ? part.url : `data:${part.mediaType};base64,${part.data}`,
91
+ detail: "auto"
92
+ };
93
+ return {
94
+ type: "image",
95
+ source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
96
+ };
97
+ });
98
+ }
99
+ function textToolOutput(value, fallback) {
100
+ if (value === void 0) return fallback;
101
+ return toolOutputForProvider(value, "unsupported").map((part) => part.text).join("\n");
102
+ }
103
+
104
+ // src/core/openai-parameters.ts
105
+ function capabilities(model) {
106
+ const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
107
+ const major = Number(gpt?.[1] ?? 0);
108
+ const minor = Number(gpt?.[2] ?? 0);
109
+ const chat = gpt?.[3]?.startsWith("chat") ?? false;
110
+ const reasoning = /^o\d+(?:-|$)/i.test(model) || major >= 5 && !chat;
111
+ const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
112
+ return { major, minor, reasoning, supportsNone };
113
+ }
114
+ function requiresOpenAIResponses(model, baseUrl, options = {}) {
115
+ if (options.parameterPolicy === "passthrough") return false;
116
+ const c = capabilities(model);
117
+ if (!c.reasoning || options.reasoningEffort === "none") return false;
118
+ if (!(c.major >= 6 || c.major === 5 && c.minor >= 4)) return false;
119
+ if (!baseUrl) return true;
120
+ try {
121
+ return new URL(baseUrl).hostname === "api.openai.com";
122
+ } catch {
123
+ return false;
124
+ }
125
+ }
126
+ function buildOpenAIParameters(model, maxTokens, temperature, options = {}, api = "chat") {
127
+ const c = capabilities(model ?? "");
128
+ const normalize = options.parameterPolicy !== "passthrough";
129
+ const effort = options.reasoningEffort;
130
+ if (normalize && c.reasoning && effort === "none" && !c.supportsNone) {
131
+ throw new Error(`${model} does not support reasoningEffort: none`);
132
+ }
133
+ if (normalize && c.major >= 6 && effort === "minimal") {
134
+ throw new Error(`${model} does not support reasoningEffort: minimal`);
135
+ }
136
+ const result = {
137
+ [api === "responses" ? "max_output_tokens" : normalize && c.reasoning ? "max_completion_tokens" : "max_tokens"]: maxTokens
138
+ };
139
+ if (effort !== void 0) {
140
+ if (api === "responses") result.reasoning = { effort };
141
+ else result.reasoning_effort = effort;
142
+ }
143
+ if (temperature !== void 0) {
144
+ if (!normalize || !c.reasoning || effort === "none" && c.supportsNone) {
145
+ result.temperature = temperature;
146
+ } else {
147
+ (options.onWarning ?? console.warn)(
148
+ `[llm-sdk] ${model}: omitted temperature because reasoning is enabled.`
149
+ );
150
+ }
151
+ }
152
+ return result;
153
+ }
154
+
1
155
  // src/adapters/base.ts
2
156
  function stringifyForDebug(value) {
3
157
  return JSON.stringify(
@@ -104,16 +258,6 @@ function normalizeObjectJsonSchema(schema) {
104
258
  }
105
259
  return normalized;
106
260
  }
107
- function isOpenAIReasoningModel(modelId) {
108
- if (!modelId) return false;
109
- return /^(o1|o3|o4|gpt-5)/i.test(modelId);
110
- }
111
- function buildOpenAITokenParams(modelId, maxTokens, temperature) {
112
- if (isOpenAIReasoningModel(modelId)) {
113
- return { max_completion_tokens: maxTokens };
114
- }
115
- return { max_tokens: maxTokens, temperature };
116
- }
117
261
  function toOpenAIResponseFormat(rf) {
118
262
  if (!rf) return void 0;
119
263
  if (rf.type === "json_object") return { type: "json_object" };
@@ -198,7 +342,7 @@ function messageToOpenAIContent(message) {
198
342
  }
199
343
  return blocks;
200
344
  }
201
- function formatMessagesForOpenAI(messages, systemPrompt) {
345
+ function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
202
346
  const formatted = [];
203
347
  if (systemPrompt) {
204
348
  formatted.push({ role: "system", content: systemPrompt });
@@ -216,7 +360,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
216
360
  const assistantMsg = {
217
361
  role: "assistant",
218
362
  // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
219
- content: hasToolCalls ? msg.content || null : msg.content
363
+ content: hasToolCalls ? msg.content || null : msg.content,
364
+ ...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
220
365
  };
221
366
  if (hasToolCalls) {
222
367
  assistantMsg.tool_calls = msg.tool_calls;
@@ -225,7 +370,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
225
370
  } else if (msg.role === "tool" && msg.tool_call_id) {
226
371
  formatted.push({
227
372
  role: "tool",
228
- content: msg.content ?? "",
373
+ content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
374
+ ...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
229
375
  tool_call_id: msg.tool_call_id
230
376
  });
231
377
  }
@@ -461,7 +607,7 @@ function formatMessagesForXAI(messages) {
461
607
  return {
462
608
  role: "tool",
463
609
  tool_call_id: msg.toolCallId,
464
- content: msg.content
610
+ content: textToolOutput(msg.modelOutput, msg.content)
465
611
  };
466
612
  default:
467
613
  return msg;
@@ -469,6 +615,86 @@ function formatMessagesForXAI(messages) {
469
615
  });
470
616
  }
471
617
 
618
+ // src/core/openai-responses.ts
619
+ function resolveOpenAITransport(defaults, overrides) {
620
+ return {
621
+ api: overrides?.api ?? defaults.api ?? "auto",
622
+ responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
623
+ };
624
+ }
625
+ function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
626
+ const api = transport.api ?? "auto";
627
+ if (!["auto", "chat", "responses"].includes(api)) {
628
+ throw new Error(`Unknown OpenAI API selection: ${api}`);
629
+ }
630
+ if (api === "chat") {
631
+ if (transport.responses !== void 0 || nativeToolSearch) {
632
+ throw new Error(
633
+ "Responses options and native tool search require the Responses API"
634
+ );
635
+ }
636
+ return false;
637
+ }
638
+ let officialEndpoint = !baseURL;
639
+ try {
640
+ officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
641
+ } catch {
642
+ }
643
+ return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
644
+ }
645
+ function responseMetadata(response) {
646
+ const output = Array.isArray(response?.output) ? response.output : [];
647
+ return {
648
+ openai: {
649
+ response: {
650
+ id: response?.id,
651
+ model: response?.model,
652
+ status: response?.status,
653
+ output,
654
+ usage: response?.usage,
655
+ store: response?.store,
656
+ refusals: output.flatMap(
657
+ (item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
658
+ (part) => part?.type === "refusal" && typeof part.refusal === "string"
659
+ ).map((part) => part.refusal) : []
660
+ )
661
+ }
662
+ }
663
+ };
664
+ }
665
+ function getResponseReplay(metadata) {
666
+ const response = metadata?.openai?.response;
667
+ if (response === void 0) return void 0;
668
+ if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
669
+ throw new Error(
670
+ "Invalid OpenAI Responses replay metadata: output must contain typed items"
671
+ );
672
+ }
673
+ return response.output;
674
+ }
675
+
676
+ // src/core/provider-error.ts
677
+ function providerErrorEvent(error, code) {
678
+ const details = error ?? {};
679
+ const event = {
680
+ type: "error",
681
+ message: error instanceof Error ? error.message : String(error),
682
+ code,
683
+ ...typeof details.status === "number" ? { status: details.status } : {},
684
+ ...typeof details.code === "string" ? { providerCode: details.code } : {},
685
+ ...typeof details.param === "string" ? { param: details.param } : {},
686
+ ...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
687
+ };
688
+ Object.defineProperty(event, "cause", { value: error, enumerable: false });
689
+ return event;
690
+ }
691
+ function throwIfAborted(signal) {
692
+ if (!signal?.aborted) return;
693
+ const error = new Error("The operation was aborted");
694
+ error.name = "AbortError";
695
+ throw error;
696
+ }
697
+
472
698
  // src/core/utils.ts
473
699
  function generateId(prefix = "id") {
474
700
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -500,39 +726,41 @@ var OpenAIAdapter = class _OpenAIAdapter {
500
726
  const { default: OpenAI } = await import('openai');
501
727
  this.client = new OpenAI({
502
728
  apiKey: this.config.apiKey,
503
- baseURL: this.config.baseUrl
729
+ baseURL: this.config.baseUrl,
730
+ organization: this.config.organization,
731
+ defaultHeaders: this.config.headers
504
732
  });
505
733
  }
506
734
  return this.client;
507
735
  }
736
+ parameterOptions(request) {
737
+ return {
738
+ ...this.config,
739
+ reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
740
+ };
741
+ }
742
+ toolDefinitions(request) {
743
+ if (request.toolDefinitions?.length) return request.toolDefinitions;
744
+ return formatTools(request.actions ?? []).map((tool) => ({
745
+ name: tool.function.name,
746
+ description: tool.function.description ?? "",
747
+ location: "server",
748
+ inputSchema: tool.function.parameters
749
+ }));
750
+ }
508
751
  shouldUseResponsesApi(request) {
509
- const hasTools = Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
510
- if (!hasTools) return false;
511
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
512
- return true;
513
- }
514
- return this.requiresResponsesApiForTools(
515
- request.config?.model || this.model
752
+ return useOpenAIResponses(
753
+ request.config?.model || this.model,
754
+ this.config.baseUrl,
755
+ this.parameterOptions(request),
756
+ resolveOpenAITransport(this.config, request.config?.openai),
757
+ this.toolDefinitions(request).length > 0,
758
+ !!(request.rawMessages ?? request.messages)?.some(
759
+ (message) => message.providerMetadata?.openai?.response
760
+ ),
761
+ request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
516
762
  );
517
763
  }
518
- /**
519
- * Whether this model rejects function tools on /v1/chat/completions.
520
- *
521
- * Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
522
- * providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
523
- * restriction and may not implement /v1/responses at all.
524
- */
525
- requiresResponsesApiForTools(modelId) {
526
- if (!modelId) return false;
527
- if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
528
- const baseUrl = this.config.baseUrl;
529
- if (!baseUrl) return true;
530
- try {
531
- return new URL(baseUrl).hostname === "api.openai.com";
532
- } catch {
533
- return false;
534
- }
535
- }
536
764
  /**
537
765
  * Convert one message's content to Responses content parts.
538
766
  *
@@ -563,11 +791,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
563
791
  });
564
792
  }
565
793
  buildResponsesInput(request) {
566
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
794
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
567
795
  const input = [];
568
796
  for (const message of sourceMessages) {
569
797
  if (message.role === "system") {
570
- if (!request.systemPrompt && message.content) {
798
+ if (message.content && message.content !== request.systemPrompt) {
571
799
  input.push({
572
800
  type: "message",
573
801
  role: "developer",
@@ -577,6 +805,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
577
805
  continue;
578
806
  }
579
807
  if (message.role === "assistant") {
808
+ const replay = getResponseReplay(message.providerMetadata);
809
+ if (replay) {
810
+ input.push(...replay);
811
+ continue;
812
+ }
580
813
  const content = this.toResponsesContent(message.content, "assistant");
581
814
  if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
582
815
  input.push({
@@ -600,7 +833,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
600
833
  input.push({
601
834
  type: "function_call_output",
602
835
  call_id: message.tool_call_id,
603
- output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
836
+ output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
604
837
  });
605
838
  continue;
606
839
  }
@@ -613,6 +846,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
613
846
  }
614
847
  return input;
615
848
  }
849
+ /** Preserve Copilot screenshot attachments on every OpenAI transport. */
850
+ formatRawMessages(messages, preserveProviderMetadata = false) {
851
+ return messages.map((message) => {
852
+ const { attachments, providerMetadata, modelOutput, ...rest } = message;
853
+ let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
854
+ if (preserveProviderMetadata && modelOutput)
855
+ rest.modelOutput = modelOutput;
856
+ if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
857
+ content = null;
858
+ }
859
+ if (Array.isArray(attachments) && attachments.length > 0) {
860
+ const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
861
+ (attachment) => attachmentToOpenAIImage(attachment)
862
+ ).filter((image) => image !== null);
863
+ if (images.length > 0) {
864
+ const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
865
+ content = [...parts, ...images];
866
+ }
867
+ }
868
+ return {
869
+ ...rest,
870
+ content,
871
+ ...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
872
+ };
873
+ });
874
+ }
616
875
  /**
617
876
  * Build the web_search tool for the Responses API, or undefined when web
618
877
  * search is off.
@@ -691,20 +950,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
691
950
  ).map((part) => part.text) : []
692
951
  ).join("") : "";
693
952
  const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
694
- const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
695
- id: item.call_id ?? item.id ?? generateToolCallId(),
696
- name: item.name,
697
- args: (() => {
698
- try {
699
- return JSON.parse(item.arguments ?? "{}");
700
- } catch {
701
- return {};
702
- }
703
- })()
704
- })) : [];
953
+ const seenCallIds = /* @__PURE__ */ new Set();
954
+ const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
955
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
956
+ throw new Error("Responses contains an incomplete function call");
957
+ }
958
+ if (seenCallIds.has(item.call_id))
959
+ throw new Error("Responses contains duplicate function call IDs");
960
+ seenCallIds.add(item.call_id);
961
+ const args = JSON.parse(item.arguments);
962
+ if (!args || typeof args !== "object" || Array.isArray(args))
963
+ throw new Error(
964
+ "Responses function arguments must be a JSON object"
965
+ );
966
+ return { id: item.call_id, name: item.name, args };
967
+ }) : [];
705
968
  return {
706
969
  content,
707
970
  toolCalls,
971
+ providerMetadata: responseMetadata(response),
708
972
  usage: response?.usage ? {
709
973
  promptTokens: response.usage.input_tokens ?? 0,
710
974
  completionTokens: response.usage.output_tokens ?? 0,
@@ -715,6 +979,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
715
979
  }
716
980
  buildResponsesPayload(request, stream) {
717
981
  const openaiToolOptions = request.providerToolOptions?.openai;
982
+ const options = resolveOpenAITransport(
983
+ this.config,
984
+ request.config?.openai
985
+ ).responses;
986
+ const parameters = buildOpenAIParameters(
987
+ request.config?.model || this.model,
988
+ request.config?.maxTokens ?? this.config.maxTokens,
989
+ request.config?.temperature ?? this.config.temperature,
990
+ this.parameterOptions(request),
991
+ "responses"
992
+ );
718
993
  const responsesTextFormat = toOpenAIResponsesTextFormat(
719
994
  request.config?.responseFormat
720
995
  );
@@ -724,18 +999,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
724
999
  instructions: request.systemPrompt,
725
1000
  input: this.buildResponsesInput(request),
726
1001
  tools: this.buildResponsesTools(
727
- request.toolDefinitions ?? [],
1002
+ this.toolDefinitions(request),
728
1003
  request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
729
1004
  this.buildResponsesWebSearchTool(request)
730
1005
  ),
731
- tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
1006
+ tool_choice: openaiToolOptions?.toolChoice,
732
1007
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
733
- // Reasoning models reject `temperature` outright — sending it would swap one
734
- // 400 for another. isOpenAIReasoningModel already encodes that family test.
735
- ...isOpenAIReasoningModel(modelIdForPayload) ? {} : {
736
- temperature: request.config?.temperature ?? this.config.temperature
737
- },
738
- max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
1008
+ ...parameters,
1009
+ ...options?.reasoningSummary ? {
1010
+ reasoning: {
1011
+ ...parameters.reasoning,
1012
+ summary: options.reasoningSummary
1013
+ }
1014
+ } : {},
1015
+ ...options?.store !== void 0 ? { store: options.store } : {},
1016
+ ...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
1017
+ ...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
1018
+ ...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
1019
+ ...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
1020
+ ...options?.store === false || options?.include ? {
1021
+ include: [
1022
+ .../* @__PURE__ */ new Set([
1023
+ ...options?.include ?? [],
1024
+ ...options?.store === false ? ["reasoning.encrypted_content"] : []
1025
+ ])
1026
+ ]
1027
+ } : {},
739
1028
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
740
1029
  stream
741
1030
  };
@@ -743,10 +1032,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
743
1032
  }
744
1033
  async completeWithResponses(request) {
745
1034
  const client = await this.getClient();
1035
+ throwIfAborted(request.signal);
746
1036
  const payload = this.buildResponsesPayload(request, false);
747
1037
  logProviderPayload("openai", "request payload", payload, request.debug);
748
- const response = await client.responses.create(payload);
1038
+ if (!client.responses?.create)
1039
+ throw new Error(
1040
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
1041
+ );
1042
+ const response = await client.responses.create(payload, {
1043
+ signal: request.signal
1044
+ });
1045
+ throwIfAborted(request.signal);
749
1046
  logProviderPayload("openai", "response payload", response, request.debug);
1047
+ if (response.status && response.status !== "completed") {
1048
+ throw Object.assign(
1049
+ new Error(
1050
+ response.error?.message ?? `Responses request ${response.status}`
1051
+ ),
1052
+ response.error
1053
+ );
1054
+ }
750
1055
  return this.parseResponsesResult(response);
751
1056
  }
752
1057
  /**
@@ -764,13 +1069,30 @@ var OpenAIAdapter = class _OpenAIAdapter {
764
1069
  */
765
1070
  async *streamWithResponses(request) {
766
1071
  const client = await this.getClient();
1072
+ throwIfAborted(request.signal);
767
1073
  const payload = this.buildResponsesPayload(request, true);
768
1074
  logProviderPayload("openai", "request payload", payload, request.debug);
769
- const stream = await client.responses.create(payload);
1075
+ if (!client.responses?.create)
1076
+ throw new Error(
1077
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
1078
+ );
1079
+ const stream = await client.responses.create(payload, {
1080
+ signal: request.signal
1081
+ });
770
1082
  const toolCalls = /* @__PURE__ */ new Map();
771
1083
  let usage;
772
1084
  const citations = [];
1085
+ let completed = false;
1086
+ let terminalResponse;
1087
+ let responseIdentity = {};
1088
+ const outputItems = /* @__PURE__ */ new Map();
1089
+ let streamedText = "";
773
1090
  function* flushToolCalls() {
1091
+ for (const call of toolCalls.values()) {
1092
+ if (!call.name)
1093
+ throw new Error("Responses tool call is missing its name");
1094
+ JSON.parse(call.arguments || "{}");
1095
+ }
774
1096
  for (const call of toolCalls.values()) {
775
1097
  yield { type: "action:start", id: call.id, name: call.name };
776
1098
  yield { type: "action:args", id: call.id, args: call.arguments };
@@ -779,19 +1101,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
779
1101
  toolCalls.clear();
780
1102
  }
781
1103
  for await (const event of stream) {
782
- if (request.signal?.aborted) break;
1104
+ throwIfAborted(request.signal);
783
1105
  logProviderPayload("openai", "stream chunk", event, request.debug);
1106
+ if (completed)
1107
+ throw new Error("Responses stream emitted an event after completion");
784
1108
  const index = event?.output_index ?? 0;
785
1109
  switch (event?.type) {
1110
+ case "response.created":
1111
+ responseIdentity = {
1112
+ id: event.response?.id,
1113
+ model: event.response?.model
1114
+ };
1115
+ break;
1116
+ case "response.output_item.done":
1117
+ if (event.item) outputItems.set(index, event.item);
1118
+ if (event.item?.type === "function_call") {
1119
+ toolCalls.set(index, {
1120
+ id: event.item.call_id,
1121
+ name: event.item.name,
1122
+ arguments: event.item.arguments
1123
+ });
1124
+ }
1125
+ break;
786
1126
  case "response.output_text.delta":
787
1127
  if (event.delta) {
1128
+ streamedText += event.delta;
788
1129
  yield { type: "message:delta", content: event.delta };
789
1130
  }
790
1131
  break;
791
1132
  case "response.output_item.added":
792
1133
  if (event.item?.type === "function_call") {
793
1134
  toolCalls.set(index, {
794
- id: event.item.call_id ?? event.item.id ?? generateToolCallId(),
1135
+ id: event.item.call_id ?? "",
795
1136
  name: event.item.name ?? "",
796
1137
  arguments: event.item.arguments ?? ""
797
1138
  });
@@ -809,8 +1150,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
809
1150
  }
810
1151
  break;
811
1152
  }
812
- case "response.completed":
813
- case "response.incomplete": {
1153
+ case "response.completed": {
1154
+ if (event.response?.status && event.response.status !== "completed")
1155
+ throw new Error(`Responses stream ${event.response.status}`);
1156
+ completed = true;
1157
+ terminalResponse = { ...responseIdentity, ...event.response };
814
1158
  const found = this.collectResponsesCitations(
815
1159
  event.response?.output,
816
1160
  citations.length
@@ -826,21 +1170,88 @@ var OpenAIAdapter = class _OpenAIAdapter {
826
1170
  }
827
1171
  break;
828
1172
  }
829
- case "error":
830
- case "response.failed":
1173
+ case "response.incomplete":
831
1174
  throw new Error(
832
- event.message ?? event.response?.error?.message ?? "Responses stream failed"
1175
+ `Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
1176
+ );
1177
+ case "error":
1178
+ case "response.failed": {
1179
+ const details = event.response?.error ?? event;
1180
+ throw Object.assign(
1181
+ new Error(details.message ?? "Responses stream failed"),
1182
+ {
1183
+ code: details.code,
1184
+ param: details.param,
1185
+ status: details.status
1186
+ }
833
1187
  );
1188
+ }
1189
+ }
1190
+ }
1191
+ throwIfAborted(request.signal);
1192
+ if (!completed)
1193
+ throw new Error("Responses stream ended without a completed response");
1194
+ const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
1195
+ if (output.some((item) => item.type === "function_call"))
1196
+ toolCalls.clear();
1197
+ for (const [index, item] of output.entries()) {
1198
+ if (item.type === "function_call") {
1199
+ toolCalls.set(index, {
1200
+ id: item.call_id,
1201
+ name: item.name,
1202
+ arguments: item.arguments
1203
+ });
834
1204
  }
835
1205
  }
1206
+ const uniqueCalls = /* @__PURE__ */ new Map();
1207
+ for (const call of toolCalls.values()) {
1208
+ if (!call.id || !call.name)
1209
+ throw new Error("Responses stream contains an incomplete tool call");
1210
+ uniqueCalls.set(call.id, call);
1211
+ }
1212
+ toolCalls.clear();
1213
+ [...uniqueCalls.values()].forEach(
1214
+ (call, index) => toolCalls.set(index, call)
1215
+ );
1216
+ if (!output.length && toolCalls.size) {
1217
+ for (const call of toolCalls.values())
1218
+ output.push({
1219
+ type: "function_call",
1220
+ call_id: call.id,
1221
+ name: call.name,
1222
+ arguments: call.arguments
1223
+ });
1224
+ }
1225
+ if (!output.length && streamedText)
1226
+ output.push({
1227
+ type: "message",
1228
+ role: "assistant",
1229
+ content: [{ type: "output_text", text: streamedText, annotations: [] }]
1230
+ });
1231
+ terminalResponse.output = output;
1232
+ const finalText = this.parseResponsesResult(terminalResponse).content;
1233
+ if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
1234
+ yield {
1235
+ type: "message:delta",
1236
+ content: finalText.slice(streamedText.length)
1237
+ };
1238
+ }
836
1239
  yield* flushToolCalls();
837
1240
  if (citations.length > 0) {
838
1241
  yield { type: "citation", citations: deduplicateCitations(citations) };
839
1242
  }
840
- yield { type: "message:end" };
841
- yield { type: "done", usage };
1243
+ yield {
1244
+ type: "message:end",
1245
+ providerMetadata: responseMetadata(terminalResponse)
1246
+ };
1247
+ yield {
1248
+ type: "done",
1249
+ usage,
1250
+ providerMetadata: responseMetadata(terminalResponse)
1251
+ };
842
1252
  }
843
1253
  async *stream(request) {
1254
+ throwIfAborted(request.signal);
844
1255
  if (this.shouldUseResponsesApi(request)) {
845
1256
  const messageId2 = generateMessageId();
846
1257
  yield { type: "message:start", id: messageId2 };
@@ -848,47 +1259,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
848
1259
  yield* this.streamWithResponses(request);
849
1260
  return;
850
1261
  } catch (error) {
851
- yield {
852
- type: "error",
853
- message: error instanceof Error ? error.message : "Unknown error",
854
- code: "OPENAI_RESPONSES_ERROR"
855
- };
1262
+ yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
856
1263
  return;
857
1264
  }
858
1265
  }
859
1266
  const client = await this.getClient();
860
1267
  let messages;
861
1268
  if (request.rawMessages && request.rawMessages.length > 0) {
862
- const processedMessages = request.rawMessages.map((msg) => {
863
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
864
- return { ...msg, content: null };
865
- }
866
- const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
867
- if (hasAttachments) {
868
- const content = [];
869
- if (msg.content) {
870
- content.push({ type: "text", text: msg.content });
871
- }
872
- for (const attachment of msg.attachments) {
873
- if (attachment.type === "image") {
874
- let imageUrl;
875
- if (attachment.url) {
876
- imageUrl = attachment.url;
877
- } else if (attachment.data) {
878
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
879
- } else {
880
- continue;
881
- }
882
- content.push({
883
- type: "image_url",
884
- image_url: { url: imageUrl, detail: "auto" }
885
- });
886
- }
887
- }
888
- return { ...msg, content, attachments: void 0 };
889
- }
890
- return msg;
891
- });
1269
+ const processedMessages = this.formatRawMessages(request.rawMessages);
892
1270
  if (request.systemPrompt) {
893
1271
  const hasSystem = processedMessages.some((m) => m.role === "system");
894
1272
  if (!hasSystem) {
@@ -908,7 +1286,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
908
1286
  request.systemPrompt
909
1287
  );
910
1288
  }
911
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1289
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1290
+ type: "function",
1291
+ function: {
1292
+ name: tool.name,
1293
+ description: tool.description,
1294
+ parameters: normalizeObjectJsonSchema(
1295
+ tool.inputSchema
1296
+ )
1297
+ }
1298
+ })) : formatTools(request.actions ?? []);
912
1299
  const webSearchConfig = request.webSearch ?? this.config.webSearch;
913
1300
  if (webSearchConfig) {
914
1301
  const webSearchTool = {
@@ -937,26 +1324,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
937
1324
  tools: tools.length > 0 ? tools : void 0,
938
1325
  tool_choice: tools.length > 0 ? toolChoice : void 0,
939
1326
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
940
- ...buildOpenAITokenParams(
1327
+ ...buildOpenAIParameters(
941
1328
  modelIdForPayload,
942
1329
  request.config?.maxTokens ?? this.config.maxTokens,
943
- request.config?.temperature ?? this.config.temperature
1330
+ request.config?.temperature ?? this.config.temperature,
1331
+ this.parameterOptions(request)
944
1332
  ),
945
1333
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
946
1334
  stream: true,
947
1335
  stream_options: { include_usage: true }
948
1336
  };
949
1337
  logProviderPayload("openai", "request payload", payload, request.debug);
950
- const stream = await client.chat.completions.create(payload);
951
- let currentToolCall = null;
1338
+ const stream = await client.chat.completions.create(payload, {
1339
+ signal: request.signal
1340
+ });
1341
+ const toolCalls = /* @__PURE__ */ new Map();
1342
+ let finishReason;
952
1343
  const collectedCitations = [];
953
1344
  let citationIndex = 0;
954
1345
  let usage;
955
1346
  for await (const chunk of stream) {
956
1347
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
957
- if (request.signal?.aborted) {
958
- break;
959
- }
1348
+ throwIfAborted(request.signal);
960
1349
  const delta = chunk.choices[0]?.delta;
961
1350
  const choice = chunk.choices[0];
962
1351
  if (delta?.content) {
@@ -979,38 +1368,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
979
1368
  }
980
1369
  }
981
1370
  }
982
- if (delta?.tool_calls) {
983
- for (const toolCall of delta.tool_calls) {
984
- if (toolCall.id) {
985
- if (currentToolCall) {
986
- yield {
987
- type: "action:args",
988
- id: currentToolCall.id,
989
- args: currentToolCall.arguments
990
- };
991
- yield {
992
- type: "action:end",
993
- id: currentToolCall.id,
994
- name: currentToolCall.name
995
- };
996
- }
997
- const tcExtraContent = toolCall.extra_content;
998
- currentToolCall = {
999
- id: toolCall.id,
1000
- name: toolCall.function?.name || "",
1001
- arguments: toolCall.function?.arguments || "",
1002
- ...tcExtraContent ? { extra_content: tcExtraContent } : {}
1003
- };
1004
- yield {
1005
- type: "action:start",
1006
- id: currentToolCall.id,
1007
- name: currentToolCall.name,
1008
- ...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
1009
- };
1010
- } else if (currentToolCall && toolCall.function?.arguments) {
1011
- currentToolCall.arguments += toolCall.function.arguments;
1012
- }
1013
- }
1371
+ for (const part of delta?.tool_calls ?? []) {
1372
+ const index = part.index ?? 0;
1373
+ const call = toolCalls.get(index) ?? {
1374
+ id: "",
1375
+ name: "",
1376
+ arguments: ""
1377
+ };
1378
+ if (part.id) call.id = part.id;
1379
+ if (part.function?.name) call.name += part.function.name;
1380
+ if (part.function?.arguments)
1381
+ call.arguments += part.function.arguments;
1382
+ if (part.extra_content) call.extra_content = part.extra_content;
1383
+ toolCalls.set(index, call);
1014
1384
  }
1015
1385
  if (chunk.usage) {
1016
1386
  usage = {
@@ -1019,21 +1389,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
1019
1389
  total_tokens: chunk.usage.total_tokens
1020
1390
  };
1021
1391
  }
1022
- if (choice?.finish_reason) {
1023
- if (currentToolCall) {
1024
- yield {
1025
- type: "action:args",
1026
- id: currentToolCall.id,
1027
- args: currentToolCall.arguments
1028
- };
1029
- yield {
1030
- type: "action:end",
1031
- id: currentToolCall.id,
1032
- name: currentToolCall.name
1033
- };
1034
- currentToolCall = null;
1035
- }
1036
- }
1392
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
1393
+ }
1394
+ throwIfAborted(request.signal);
1395
+ if (!finishReason)
1396
+ throw new Error("OpenAI stream ended without a finish reason");
1397
+ if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
1398
+ throw new Error("OpenAI stream ended with incomplete tool calls");
1399
+ }
1400
+ for (const call of toolCalls.values()) {
1401
+ if (!call.id || !call.name)
1402
+ throw new Error("OpenAI stream contains an incomplete tool call");
1403
+ JSON.parse(call.arguments || "{}");
1404
+ }
1405
+ for (const call of toolCalls.values()) {
1406
+ yield {
1407
+ type: "action:start",
1408
+ id: call.id,
1409
+ name: call.name,
1410
+ ...call.extra_content ? { extra_content: call.extra_content } : {}
1411
+ };
1412
+ yield { type: "action:args", id: call.id, args: call.arguments };
1413
+ yield { type: "action:end", id: call.id, name: call.name };
1037
1414
  }
1038
1415
  if (collectedCitations.length > 0) {
1039
1416
  const uniqueCitations = deduplicateCitations(collectedCitations);
@@ -1042,26 +1419,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
1042
1419
  yield { type: "message:end" };
1043
1420
  yield { type: "done", usage };
1044
1421
  } catch (error) {
1045
- yield {
1046
- type: "error",
1047
- message: error instanceof Error ? error.message : "Unknown error",
1048
- code: `${this.provider.toUpperCase()}_ERROR`
1049
- };
1422
+ yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
1050
1423
  }
1051
1424
  }
1052
1425
  async complete(request) {
1426
+ throwIfAborted(request.signal);
1053
1427
  if (this.shouldUseResponsesApi(request)) {
1054
1428
  return this.completeWithResponses(request);
1055
1429
  }
1056
1430
  const client = await this.getClient();
1057
1431
  let messages;
1058
1432
  if (request.rawMessages && request.rawMessages.length > 0) {
1059
- const sanitized = request.rawMessages.map((msg) => {
1060
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
1061
- return { ...msg, content: null };
1062
- }
1063
- return msg;
1064
- });
1433
+ const sanitized = this.formatRawMessages(request.rawMessages);
1065
1434
  if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
1066
1435
  messages = [
1067
1436
  { role: "system", content: request.systemPrompt },
@@ -1076,7 +1445,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
1076
1445
  request.systemPrompt
1077
1446
  );
1078
1447
  }
1079
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1448
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1449
+ type: "function",
1450
+ function: {
1451
+ name: tool.name,
1452
+ description: tool.description,
1453
+ parameters: normalizeObjectJsonSchema(
1454
+ tool.inputSchema
1455
+ )
1456
+ }
1457
+ })) : formatTools(request.actions ?? []);
1080
1458
  const openaiToolOptions = request.providerToolOptions?.openai;
1081
1459
  const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
1082
1460
  type: "function",
@@ -1091,16 +1469,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1091
1469
  tools: tools.length > 0 ? tools : void 0,
1092
1470
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1093
1471
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1094
- ...buildOpenAITokenParams(
1472
+ ...buildOpenAIParameters(
1095
1473
  modelIdForCompletePayload,
1096
1474
  request.config?.maxTokens ?? this.config.maxTokens,
1097
- request.config?.temperature ?? this.config.temperature
1475
+ request.config?.temperature ?? this.config.temperature,
1476
+ this.parameterOptions(request)
1098
1477
  ),
1099
1478
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1100
1479
  stream: false
1101
1480
  };
1102
1481
  logProviderPayload("openai", "request payload", payload, request.debug);
1103
- const response = await client.chat.completions.create(payload);
1482
+ const response = await client.chat.completions.create(payload, {
1483
+ signal: request.signal
1484
+ });
1104
1485
  logProviderPayload("openai", "response payload", response, request.debug);
1105
1486
  const choice = response.choices?.[0];
1106
1487
  const message = choice?.message;