@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,5 +1,159 @@
1
1
  'use strict';
2
2
 
3
+ // src/core/tool-output.ts
4
+ var imageTypes = /* @__PURE__ */ new Set([
5
+ "image/png",
6
+ "image/jpeg",
7
+ "image/webp",
8
+ "image/gif"
9
+ ]);
10
+ function normalizeToolOutput(value) {
11
+ const output = value;
12
+ if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
13
+ throw new Error("Tool model output must contain a nonempty content array");
14
+ }
15
+ return {
16
+ type: "content",
17
+ content: output.content.map((part) => {
18
+ if (part?.type === "text" && typeof part.text === "string")
19
+ return { type: "text", text: part.text };
20
+ if (part?.type !== "image")
21
+ throw new Error("Unsupported tool output content type");
22
+ const sources = ["data", "url", "fileId"].filter((key) => key in part);
23
+ if (sources.length !== 1)
24
+ throw new Error(
25
+ "Tool image requires exactly one of data, url, or fileId"
26
+ );
27
+ if ("fileId" in part) {
28
+ if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
29
+ throw new Error(
30
+ "Tool image file references must name the openai provider and fileId"
31
+ );
32
+ return { type: "image", fileId: part.fileId, provider: "openai" };
33
+ }
34
+ if ("url" in part) {
35
+ let url;
36
+ try {
37
+ url = new URL(part.url);
38
+ } catch {
39
+ throw new Error("Invalid tool image URL");
40
+ }
41
+ if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
42
+ throw new Error(
43
+ "Tool image URL must use HTTP(S) without credentials"
44
+ );
45
+ return { type: "image", url: url.href };
46
+ }
47
+ if (!("data" in part) || !imageTypes.has(part.mediaType))
48
+ throw new Error("Unsupported tool image media type");
49
+ let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
50
+ if (typeof data !== "string")
51
+ throw new Error("Tool image data must be base64 or bytes");
52
+ if (data.startsWith("data:")) {
53
+ const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
54
+ if (!match || match[1] !== part.mediaType)
55
+ throw new Error(
56
+ "Tool image data URL media type does not match mediaType"
57
+ );
58
+ data = match[2];
59
+ }
60
+ if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
61
+ throw new Error("Invalid tool image base64 data");
62
+ if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
63
+ throw new Error("Tool image exceeds 20 MiB");
64
+ if (Buffer.from(data, "base64").toString("base64") !== data)
65
+ throw new Error("Invalid tool image base64 data");
66
+ return { type: "image", data, mediaType: part.mediaType };
67
+ })
68
+ };
69
+ }
70
+ function toolOutputForProvider(value, provider) {
71
+ const output = normalizeToolOutput(value);
72
+ return output.content.map((part) => {
73
+ if (part.type === "text")
74
+ return {
75
+ type: provider === "responses" ? "input_text" : "text",
76
+ text: part.text
77
+ };
78
+ if (provider === "unsupported")
79
+ throw new Error(
80
+ "Image tool results require OpenAI Responses or Anthropic; this endpoint is not supported"
81
+ );
82
+ if ("fileId" in part) {
83
+ if (provider !== "responses")
84
+ throw new Error(
85
+ "OpenAI image file references cannot be sent to another provider"
86
+ );
87
+ return { type: "input_image", file_id: part.fileId, detail: "auto" };
88
+ }
89
+ if (provider === "responses")
90
+ return {
91
+ type: "input_image",
92
+ image_url: "url" in part ? part.url : `data:${part.mediaType};base64,${part.data}`,
93
+ detail: "auto"
94
+ };
95
+ return {
96
+ type: "image",
97
+ source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
98
+ };
99
+ });
100
+ }
101
+ function textToolOutput(value, fallback) {
102
+ if (value === void 0) return fallback;
103
+ return toolOutputForProvider(value, "unsupported").map((part) => part.text).join("\n");
104
+ }
105
+
106
+ // src/core/openai-parameters.ts
107
+ function capabilities(model) {
108
+ const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
109
+ const major = Number(gpt?.[1] ?? 0);
110
+ const minor = Number(gpt?.[2] ?? 0);
111
+ const chat = gpt?.[3]?.startsWith("chat") ?? false;
112
+ const reasoning = /^o\d+(?:-|$)/i.test(model) || major >= 5 && !chat;
113
+ const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
114
+ return { major, minor, reasoning, supportsNone };
115
+ }
116
+ function requiresOpenAIResponses(model, baseUrl, options = {}) {
117
+ if (options.parameterPolicy === "passthrough") return false;
118
+ const c = capabilities(model);
119
+ if (!c.reasoning || options.reasoningEffort === "none") return false;
120
+ if (!(c.major >= 6 || c.major === 5 && c.minor >= 4)) return false;
121
+ if (!baseUrl) return true;
122
+ try {
123
+ return new URL(baseUrl).hostname === "api.openai.com";
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+ function buildOpenAIParameters(model, maxTokens, temperature, options = {}, api = "chat") {
129
+ const c = capabilities(model ?? "");
130
+ const normalize = options.parameterPolicy !== "passthrough";
131
+ const effort = options.reasoningEffort;
132
+ if (normalize && c.reasoning && effort === "none" && !c.supportsNone) {
133
+ throw new Error(`${model} does not support reasoningEffort: none`);
134
+ }
135
+ if (normalize && c.major >= 6 && effort === "minimal") {
136
+ throw new Error(`${model} does not support reasoningEffort: minimal`);
137
+ }
138
+ const result = {
139
+ [api === "responses" ? "max_output_tokens" : normalize && c.reasoning ? "max_completion_tokens" : "max_tokens"]: maxTokens
140
+ };
141
+ if (effort !== void 0) {
142
+ if (api === "responses") result.reasoning = { effort };
143
+ else result.reasoning_effort = effort;
144
+ }
145
+ if (temperature !== void 0) {
146
+ if (!normalize || !c.reasoning || effort === "none" && c.supportsNone) {
147
+ result.temperature = temperature;
148
+ } else {
149
+ (options.onWarning ?? console.warn)(
150
+ `[llm-sdk] ${model}: omitted temperature because reasoning is enabled.`
151
+ );
152
+ }
153
+ }
154
+ return result;
155
+ }
156
+
3
157
  // src/adapters/base.ts
4
158
  function stringifyForDebug(value) {
5
159
  return JSON.stringify(
@@ -106,16 +260,6 @@ function normalizeObjectJsonSchema(schema) {
106
260
  }
107
261
  return normalized;
108
262
  }
109
- function isOpenAIReasoningModel(modelId) {
110
- if (!modelId) return false;
111
- return /^(o1|o3|o4|gpt-5)/i.test(modelId);
112
- }
113
- function buildOpenAITokenParams(modelId, maxTokens, temperature) {
114
- if (isOpenAIReasoningModel(modelId)) {
115
- return { max_completion_tokens: maxTokens };
116
- }
117
- return { max_tokens: maxTokens, temperature };
118
- }
119
263
  function toOpenAIResponseFormat(rf) {
120
264
  if (!rf) return void 0;
121
265
  if (rf.type === "json_object") return { type: "json_object" };
@@ -200,7 +344,7 @@ function messageToOpenAIContent(message) {
200
344
  }
201
345
  return blocks;
202
346
  }
203
- function formatMessagesForOpenAI(messages, systemPrompt) {
347
+ function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
204
348
  const formatted = [];
205
349
  if (systemPrompt) {
206
350
  formatted.push({ role: "system", content: systemPrompt });
@@ -218,7 +362,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
218
362
  const assistantMsg = {
219
363
  role: "assistant",
220
364
  // Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
221
- content: hasToolCalls ? msg.content || null : msg.content
365
+ content: hasToolCalls ? msg.content || null : msg.content,
366
+ ...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
222
367
  };
223
368
  if (hasToolCalls) {
224
369
  assistantMsg.tool_calls = msg.tool_calls;
@@ -227,7 +372,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
227
372
  } else if (msg.role === "tool" && msg.tool_call_id) {
228
373
  formatted.push({
229
374
  role: "tool",
230
- content: msg.content ?? "",
375
+ content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
376
+ ...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
231
377
  tool_call_id: msg.tool_call_id
232
378
  });
233
379
  }
@@ -514,7 +660,7 @@ function formatMessagesForGoogle(messages) {
514
660
  return {
515
661
  role: "tool",
516
662
  tool_call_id: msg.toolCallId,
517
- content: msg.content
663
+ content: textToolOutput(msg.modelOutput, msg.content)
518
664
  };
519
665
  default:
520
666
  return msg;
@@ -522,6 +668,86 @@ function formatMessagesForGoogle(messages) {
522
668
  });
523
669
  }
524
670
 
671
+ // src/core/openai-responses.ts
672
+ function resolveOpenAITransport(defaults, overrides) {
673
+ return {
674
+ api: overrides?.api ?? defaults.api ?? "auto",
675
+ responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
676
+ };
677
+ }
678
+ function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
679
+ const api = transport.api ?? "auto";
680
+ if (!["auto", "chat", "responses"].includes(api)) {
681
+ throw new Error(`Unknown OpenAI API selection: ${api}`);
682
+ }
683
+ if (api === "chat") {
684
+ if (transport.responses !== void 0 || nativeToolSearch) {
685
+ throw new Error(
686
+ "Responses options and native tool search require the Responses API"
687
+ );
688
+ }
689
+ return false;
690
+ }
691
+ let officialEndpoint = !baseURL;
692
+ try {
693
+ officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
694
+ } catch {
695
+ }
696
+ return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
697
+ }
698
+ function responseMetadata(response) {
699
+ const output = Array.isArray(response?.output) ? response.output : [];
700
+ return {
701
+ openai: {
702
+ response: {
703
+ id: response?.id,
704
+ model: response?.model,
705
+ status: response?.status,
706
+ output,
707
+ usage: response?.usage,
708
+ store: response?.store,
709
+ refusals: output.flatMap(
710
+ (item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
711
+ (part) => part?.type === "refusal" && typeof part.refusal === "string"
712
+ ).map((part) => part.refusal) : []
713
+ )
714
+ }
715
+ }
716
+ };
717
+ }
718
+ function getResponseReplay(metadata) {
719
+ const response = metadata?.openai?.response;
720
+ if (response === void 0) return void 0;
721
+ if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
722
+ throw new Error(
723
+ "Invalid OpenAI Responses replay metadata: output must contain typed items"
724
+ );
725
+ }
726
+ return response.output;
727
+ }
728
+
729
+ // src/core/provider-error.ts
730
+ function providerErrorEvent(error, code) {
731
+ const details = error ?? {};
732
+ const event = {
733
+ type: "error",
734
+ message: error instanceof Error ? error.message : String(error),
735
+ code,
736
+ ...typeof details.status === "number" ? { status: details.status } : {},
737
+ ...typeof details.code === "string" ? { providerCode: details.code } : {},
738
+ ...typeof details.param === "string" ? { param: details.param } : {},
739
+ ...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
740
+ };
741
+ Object.defineProperty(event, "cause", { value: error, enumerable: false });
742
+ return event;
743
+ }
744
+ function throwIfAborted(signal) {
745
+ if (!signal?.aborted) return;
746
+ const error = new Error("The operation was aborted");
747
+ error.name = "AbortError";
748
+ throw error;
749
+ }
750
+
525
751
  // src/core/utils.ts
526
752
  function generateId(prefix = "id") {
527
753
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -553,39 +779,41 @@ var OpenAIAdapter = class _OpenAIAdapter {
553
779
  const { default: OpenAI } = await import('openai');
554
780
  this.client = new OpenAI({
555
781
  apiKey: this.config.apiKey,
556
- baseURL: this.config.baseUrl
782
+ baseURL: this.config.baseUrl,
783
+ organization: this.config.organization,
784
+ defaultHeaders: this.config.headers
557
785
  });
558
786
  }
559
787
  return this.client;
560
788
  }
789
+ parameterOptions(request) {
790
+ return {
791
+ ...this.config,
792
+ reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
793
+ };
794
+ }
795
+ toolDefinitions(request) {
796
+ if (request.toolDefinitions?.length) return request.toolDefinitions;
797
+ return formatTools(request.actions ?? []).map((tool) => ({
798
+ name: tool.function.name,
799
+ description: tool.function.description ?? "",
800
+ location: "server",
801
+ inputSchema: tool.function.parameters
802
+ }));
803
+ }
561
804
  shouldUseResponsesApi(request) {
562
- const hasTools = Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
563
- if (!hasTools) return false;
564
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
565
- return true;
566
- }
567
- return this.requiresResponsesApiForTools(
568
- request.config?.model || this.model
805
+ return useOpenAIResponses(
806
+ request.config?.model || this.model,
807
+ this.config.baseUrl,
808
+ this.parameterOptions(request),
809
+ resolveOpenAITransport(this.config, request.config?.openai),
810
+ this.toolDefinitions(request).length > 0,
811
+ !!(request.rawMessages ?? request.messages)?.some(
812
+ (message) => message.providerMetadata?.openai?.response
813
+ ),
814
+ request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
569
815
  );
570
816
  }
571
- /**
572
- * Whether this model rejects function tools on /v1/chat/completions.
573
- *
574
- * Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
575
- * providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
576
- * restriction and may not implement /v1/responses at all.
577
- */
578
- requiresResponsesApiForTools(modelId) {
579
- if (!modelId) return false;
580
- if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
581
- const baseUrl = this.config.baseUrl;
582
- if (!baseUrl) return true;
583
- try {
584
- return new URL(baseUrl).hostname === "api.openai.com";
585
- } catch {
586
- return false;
587
- }
588
- }
589
817
  /**
590
818
  * Convert one message's content to Responses content parts.
591
819
  *
@@ -616,11 +844,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
616
844
  });
617
845
  }
618
846
  buildResponsesInput(request) {
619
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
847
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
620
848
  const input = [];
621
849
  for (const message of sourceMessages) {
622
850
  if (message.role === "system") {
623
- if (!request.systemPrompt && message.content) {
851
+ if (message.content && message.content !== request.systemPrompt) {
624
852
  input.push({
625
853
  type: "message",
626
854
  role: "developer",
@@ -630,6 +858,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
630
858
  continue;
631
859
  }
632
860
  if (message.role === "assistant") {
861
+ const replay = getResponseReplay(message.providerMetadata);
862
+ if (replay) {
863
+ input.push(...replay);
864
+ continue;
865
+ }
633
866
  const content = this.toResponsesContent(message.content, "assistant");
634
867
  if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
635
868
  input.push({
@@ -653,7 +886,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
653
886
  input.push({
654
887
  type: "function_call_output",
655
888
  call_id: message.tool_call_id,
656
- output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
889
+ output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
657
890
  });
658
891
  continue;
659
892
  }
@@ -666,6 +899,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
666
899
  }
667
900
  return input;
668
901
  }
902
+ /** Preserve Copilot screenshot attachments on every OpenAI transport. */
903
+ formatRawMessages(messages, preserveProviderMetadata = false) {
904
+ return messages.map((message) => {
905
+ const { attachments, providerMetadata, modelOutput, ...rest } = message;
906
+ let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
907
+ if (preserveProviderMetadata && modelOutput)
908
+ rest.modelOutput = modelOutput;
909
+ if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
910
+ content = null;
911
+ }
912
+ if (Array.isArray(attachments) && attachments.length > 0) {
913
+ const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
914
+ (attachment) => attachmentToOpenAIImage(attachment)
915
+ ).filter((image) => image !== null);
916
+ if (images.length > 0) {
917
+ const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
918
+ content = [...parts, ...images];
919
+ }
920
+ }
921
+ return {
922
+ ...rest,
923
+ content,
924
+ ...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
925
+ };
926
+ });
927
+ }
669
928
  /**
670
929
  * Build the web_search tool for the Responses API, or undefined when web
671
930
  * search is off.
@@ -744,20 +1003,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
744
1003
  ).map((part) => part.text) : []
745
1004
  ).join("") : "";
746
1005
  const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
747
- const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
748
- id: item.call_id ?? item.id ?? generateToolCallId(),
749
- name: item.name,
750
- args: (() => {
751
- try {
752
- return JSON.parse(item.arguments ?? "{}");
753
- } catch {
754
- return {};
755
- }
756
- })()
757
- })) : [];
1006
+ const seenCallIds = /* @__PURE__ */ new Set();
1007
+ const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
1008
+ if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
1009
+ throw new Error("Responses contains an incomplete function call");
1010
+ }
1011
+ if (seenCallIds.has(item.call_id))
1012
+ throw new Error("Responses contains duplicate function call IDs");
1013
+ seenCallIds.add(item.call_id);
1014
+ const args = JSON.parse(item.arguments);
1015
+ if (!args || typeof args !== "object" || Array.isArray(args))
1016
+ throw new Error(
1017
+ "Responses function arguments must be a JSON object"
1018
+ );
1019
+ return { id: item.call_id, name: item.name, args };
1020
+ }) : [];
758
1021
  return {
759
1022
  content,
760
1023
  toolCalls,
1024
+ providerMetadata: responseMetadata(response),
761
1025
  usage: response?.usage ? {
762
1026
  promptTokens: response.usage.input_tokens ?? 0,
763
1027
  completionTokens: response.usage.output_tokens ?? 0,
@@ -768,6 +1032,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
768
1032
  }
769
1033
  buildResponsesPayload(request, stream) {
770
1034
  const openaiToolOptions = request.providerToolOptions?.openai;
1035
+ const options = resolveOpenAITransport(
1036
+ this.config,
1037
+ request.config?.openai
1038
+ ).responses;
1039
+ const parameters = buildOpenAIParameters(
1040
+ request.config?.model || this.model,
1041
+ request.config?.maxTokens ?? this.config.maxTokens,
1042
+ request.config?.temperature ?? this.config.temperature,
1043
+ this.parameterOptions(request),
1044
+ "responses"
1045
+ );
771
1046
  const responsesTextFormat = toOpenAIResponsesTextFormat(
772
1047
  request.config?.responseFormat
773
1048
  );
@@ -777,18 +1052,32 @@ var OpenAIAdapter = class _OpenAIAdapter {
777
1052
  instructions: request.systemPrompt,
778
1053
  input: this.buildResponsesInput(request),
779
1054
  tools: this.buildResponsesTools(
780
- request.toolDefinitions ?? [],
1055
+ this.toolDefinitions(request),
781
1056
  request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
782
1057
  this.buildResponsesWebSearchTool(request)
783
1058
  ),
784
- tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
1059
+ tool_choice: openaiToolOptions?.toolChoice,
785
1060
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
786
- // Reasoning models reject `temperature` outright — sending it would swap one
787
- // 400 for another. isOpenAIReasoningModel already encodes that family test.
788
- ...isOpenAIReasoningModel(modelIdForPayload) ? {} : {
789
- temperature: request.config?.temperature ?? this.config.temperature
790
- },
791
- max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
1061
+ ...parameters,
1062
+ ...options?.reasoningSummary ? {
1063
+ reasoning: {
1064
+ ...parameters.reasoning,
1065
+ summary: options.reasoningSummary
1066
+ }
1067
+ } : {},
1068
+ ...options?.store !== void 0 ? { store: options.store } : {},
1069
+ ...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
1070
+ ...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
1071
+ ...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
1072
+ ...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
1073
+ ...options?.store === false || options?.include ? {
1074
+ include: [
1075
+ .../* @__PURE__ */ new Set([
1076
+ ...options?.include ?? [],
1077
+ ...options?.store === false ? ["reasoning.encrypted_content"] : []
1078
+ ])
1079
+ ]
1080
+ } : {},
792
1081
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
793
1082
  stream
794
1083
  };
@@ -796,10 +1085,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
796
1085
  }
797
1086
  async completeWithResponses(request) {
798
1087
  const client = await this.getClient();
1088
+ throwIfAborted(request.signal);
799
1089
  const payload = this.buildResponsesPayload(request, false);
800
1090
  logProviderPayload("openai", "request payload", payload, request.debug);
801
- const response = await client.responses.create(payload);
1091
+ if (!client.responses?.create)
1092
+ throw new Error(
1093
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
1094
+ );
1095
+ const response = await client.responses.create(payload, {
1096
+ signal: request.signal
1097
+ });
1098
+ throwIfAborted(request.signal);
802
1099
  logProviderPayload("openai", "response payload", response, request.debug);
1100
+ if (response.status && response.status !== "completed") {
1101
+ throw Object.assign(
1102
+ new Error(
1103
+ response.error?.message ?? `Responses request ${response.status}`
1104
+ ),
1105
+ response.error
1106
+ );
1107
+ }
803
1108
  return this.parseResponsesResult(response);
804
1109
  }
805
1110
  /**
@@ -817,13 +1122,30 @@ var OpenAIAdapter = class _OpenAIAdapter {
817
1122
  */
818
1123
  async *streamWithResponses(request) {
819
1124
  const client = await this.getClient();
1125
+ throwIfAborted(request.signal);
820
1126
  const payload = this.buildResponsesPayload(request, true);
821
1127
  logProviderPayload("openai", "request payload", payload, request.debug);
822
- const stream = await client.responses.create(payload);
1128
+ if (!client.responses?.create)
1129
+ throw new Error(
1130
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
1131
+ );
1132
+ const stream = await client.responses.create(payload, {
1133
+ signal: request.signal
1134
+ });
823
1135
  const toolCalls = /* @__PURE__ */ new Map();
824
1136
  let usage;
825
1137
  const citations = [];
1138
+ let completed = false;
1139
+ let terminalResponse;
1140
+ let responseIdentity = {};
1141
+ const outputItems = /* @__PURE__ */ new Map();
1142
+ let streamedText = "";
826
1143
  function* flushToolCalls() {
1144
+ for (const call of toolCalls.values()) {
1145
+ if (!call.name)
1146
+ throw new Error("Responses tool call is missing its name");
1147
+ JSON.parse(call.arguments || "{}");
1148
+ }
827
1149
  for (const call of toolCalls.values()) {
828
1150
  yield { type: "action:start", id: call.id, name: call.name };
829
1151
  yield { type: "action:args", id: call.id, args: call.arguments };
@@ -832,19 +1154,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
832
1154
  toolCalls.clear();
833
1155
  }
834
1156
  for await (const event of stream) {
835
- if (request.signal?.aborted) break;
1157
+ throwIfAborted(request.signal);
836
1158
  logProviderPayload("openai", "stream chunk", event, request.debug);
1159
+ if (completed)
1160
+ throw new Error("Responses stream emitted an event after completion");
837
1161
  const index = event?.output_index ?? 0;
838
1162
  switch (event?.type) {
1163
+ case "response.created":
1164
+ responseIdentity = {
1165
+ id: event.response?.id,
1166
+ model: event.response?.model
1167
+ };
1168
+ break;
1169
+ case "response.output_item.done":
1170
+ if (event.item) outputItems.set(index, event.item);
1171
+ if (event.item?.type === "function_call") {
1172
+ toolCalls.set(index, {
1173
+ id: event.item.call_id,
1174
+ name: event.item.name,
1175
+ arguments: event.item.arguments
1176
+ });
1177
+ }
1178
+ break;
839
1179
  case "response.output_text.delta":
840
1180
  if (event.delta) {
1181
+ streamedText += event.delta;
841
1182
  yield { type: "message:delta", content: event.delta };
842
1183
  }
843
1184
  break;
844
1185
  case "response.output_item.added":
845
1186
  if (event.item?.type === "function_call") {
846
1187
  toolCalls.set(index, {
847
- id: event.item.call_id ?? event.item.id ?? generateToolCallId(),
1188
+ id: event.item.call_id ?? "",
848
1189
  name: event.item.name ?? "",
849
1190
  arguments: event.item.arguments ?? ""
850
1191
  });
@@ -862,8 +1203,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
862
1203
  }
863
1204
  break;
864
1205
  }
865
- case "response.completed":
866
- case "response.incomplete": {
1206
+ case "response.completed": {
1207
+ if (event.response?.status && event.response.status !== "completed")
1208
+ throw new Error(`Responses stream ${event.response.status}`);
1209
+ completed = true;
1210
+ terminalResponse = { ...responseIdentity, ...event.response };
867
1211
  const found = this.collectResponsesCitations(
868
1212
  event.response?.output,
869
1213
  citations.length
@@ -879,21 +1223,88 @@ var OpenAIAdapter = class _OpenAIAdapter {
879
1223
  }
880
1224
  break;
881
1225
  }
882
- case "error":
883
- case "response.failed":
1226
+ case "response.incomplete":
884
1227
  throw new Error(
885
- event.message ?? event.response?.error?.message ?? "Responses stream failed"
1228
+ `Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
1229
+ );
1230
+ case "error":
1231
+ case "response.failed": {
1232
+ const details = event.response?.error ?? event;
1233
+ throw Object.assign(
1234
+ new Error(details.message ?? "Responses stream failed"),
1235
+ {
1236
+ code: details.code,
1237
+ param: details.param,
1238
+ status: details.status
1239
+ }
886
1240
  );
1241
+ }
1242
+ }
1243
+ }
1244
+ throwIfAborted(request.signal);
1245
+ if (!completed)
1246
+ throw new Error("Responses stream ended without a completed response");
1247
+ const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
1248
+ if (output.some((item) => item.type === "function_call"))
1249
+ toolCalls.clear();
1250
+ for (const [index, item] of output.entries()) {
1251
+ if (item.type === "function_call") {
1252
+ toolCalls.set(index, {
1253
+ id: item.call_id,
1254
+ name: item.name,
1255
+ arguments: item.arguments
1256
+ });
887
1257
  }
888
1258
  }
1259
+ const uniqueCalls = /* @__PURE__ */ new Map();
1260
+ for (const call of toolCalls.values()) {
1261
+ if (!call.id || !call.name)
1262
+ throw new Error("Responses stream contains an incomplete tool call");
1263
+ uniqueCalls.set(call.id, call);
1264
+ }
1265
+ toolCalls.clear();
1266
+ [...uniqueCalls.values()].forEach(
1267
+ (call, index) => toolCalls.set(index, call)
1268
+ );
1269
+ if (!output.length && toolCalls.size) {
1270
+ for (const call of toolCalls.values())
1271
+ output.push({
1272
+ type: "function_call",
1273
+ call_id: call.id,
1274
+ name: call.name,
1275
+ arguments: call.arguments
1276
+ });
1277
+ }
1278
+ if (!output.length && streamedText)
1279
+ output.push({
1280
+ type: "message",
1281
+ role: "assistant",
1282
+ content: [{ type: "output_text", text: streamedText, annotations: [] }]
1283
+ });
1284
+ terminalResponse.output = output;
1285
+ const finalText = this.parseResponsesResult(terminalResponse).content;
1286
+ if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
1287
+ yield {
1288
+ type: "message:delta",
1289
+ content: finalText.slice(streamedText.length)
1290
+ };
1291
+ }
889
1292
  yield* flushToolCalls();
890
1293
  if (citations.length > 0) {
891
1294
  yield { type: "citation", citations: deduplicateCitations(citations) };
892
1295
  }
893
- yield { type: "message:end" };
894
- yield { type: "done", usage };
1296
+ yield {
1297
+ type: "message:end",
1298
+ providerMetadata: responseMetadata(terminalResponse)
1299
+ };
1300
+ yield {
1301
+ type: "done",
1302
+ usage,
1303
+ providerMetadata: responseMetadata(terminalResponse)
1304
+ };
895
1305
  }
896
1306
  async *stream(request) {
1307
+ throwIfAborted(request.signal);
897
1308
  if (this.shouldUseResponsesApi(request)) {
898
1309
  const messageId2 = generateMessageId();
899
1310
  yield { type: "message:start", id: messageId2 };
@@ -901,47 +1312,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
901
1312
  yield* this.streamWithResponses(request);
902
1313
  return;
903
1314
  } catch (error) {
904
- yield {
905
- type: "error",
906
- message: error instanceof Error ? error.message : "Unknown error",
907
- code: "OPENAI_RESPONSES_ERROR"
908
- };
1315
+ yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
909
1316
  return;
910
1317
  }
911
1318
  }
912
1319
  const client = await this.getClient();
913
1320
  let messages;
914
1321
  if (request.rawMessages && request.rawMessages.length > 0) {
915
- const processedMessages = request.rawMessages.map((msg) => {
916
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
917
- return { ...msg, content: null };
918
- }
919
- const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
920
- if (hasAttachments) {
921
- const content = [];
922
- if (msg.content) {
923
- content.push({ type: "text", text: msg.content });
924
- }
925
- for (const attachment of msg.attachments) {
926
- if (attachment.type === "image") {
927
- let imageUrl;
928
- if (attachment.url) {
929
- imageUrl = attachment.url;
930
- } else if (attachment.data) {
931
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
932
- } else {
933
- continue;
934
- }
935
- content.push({
936
- type: "image_url",
937
- image_url: { url: imageUrl, detail: "auto" }
938
- });
939
- }
940
- }
941
- return { ...msg, content, attachments: void 0 };
942
- }
943
- return msg;
944
- });
1322
+ const processedMessages = this.formatRawMessages(request.rawMessages);
945
1323
  if (request.systemPrompt) {
946
1324
  const hasSystem = processedMessages.some((m) => m.role === "system");
947
1325
  if (!hasSystem) {
@@ -961,7 +1339,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
961
1339
  request.systemPrompt
962
1340
  );
963
1341
  }
964
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1342
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1343
+ type: "function",
1344
+ function: {
1345
+ name: tool.name,
1346
+ description: tool.description,
1347
+ parameters: normalizeObjectJsonSchema(
1348
+ tool.inputSchema
1349
+ )
1350
+ }
1351
+ })) : formatTools(request.actions ?? []);
965
1352
  const webSearchConfig = request.webSearch ?? this.config.webSearch;
966
1353
  if (webSearchConfig) {
967
1354
  const webSearchTool = {
@@ -990,26 +1377,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
990
1377
  tools: tools.length > 0 ? tools : void 0,
991
1378
  tool_choice: tools.length > 0 ? toolChoice : void 0,
992
1379
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
993
- ...buildOpenAITokenParams(
1380
+ ...buildOpenAIParameters(
994
1381
  modelIdForPayload,
995
1382
  request.config?.maxTokens ?? this.config.maxTokens,
996
- request.config?.temperature ?? this.config.temperature
1383
+ request.config?.temperature ?? this.config.temperature,
1384
+ this.parameterOptions(request)
997
1385
  ),
998
1386
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
999
1387
  stream: true,
1000
1388
  stream_options: { include_usage: true }
1001
1389
  };
1002
1390
  logProviderPayload("openai", "request payload", payload, request.debug);
1003
- const stream = await client.chat.completions.create(payload);
1004
- let currentToolCall = null;
1391
+ const stream = await client.chat.completions.create(payload, {
1392
+ signal: request.signal
1393
+ });
1394
+ const toolCalls = /* @__PURE__ */ new Map();
1395
+ let finishReason;
1005
1396
  const collectedCitations = [];
1006
1397
  let citationIndex = 0;
1007
1398
  let usage;
1008
1399
  for await (const chunk of stream) {
1009
1400
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
1010
- if (request.signal?.aborted) {
1011
- break;
1012
- }
1401
+ throwIfAborted(request.signal);
1013
1402
  const delta = chunk.choices[0]?.delta;
1014
1403
  const choice = chunk.choices[0];
1015
1404
  if (delta?.content) {
@@ -1032,38 +1421,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1032
1421
  }
1033
1422
  }
1034
1423
  }
1035
- if (delta?.tool_calls) {
1036
- for (const toolCall of delta.tool_calls) {
1037
- if (toolCall.id) {
1038
- if (currentToolCall) {
1039
- yield {
1040
- type: "action:args",
1041
- id: currentToolCall.id,
1042
- args: currentToolCall.arguments
1043
- };
1044
- yield {
1045
- type: "action:end",
1046
- id: currentToolCall.id,
1047
- name: currentToolCall.name
1048
- };
1049
- }
1050
- const tcExtraContent = toolCall.extra_content;
1051
- currentToolCall = {
1052
- id: toolCall.id,
1053
- name: toolCall.function?.name || "",
1054
- arguments: toolCall.function?.arguments || "",
1055
- ...tcExtraContent ? { extra_content: tcExtraContent } : {}
1056
- };
1057
- yield {
1058
- type: "action:start",
1059
- id: currentToolCall.id,
1060
- name: currentToolCall.name,
1061
- ...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
1062
- };
1063
- } else if (currentToolCall && toolCall.function?.arguments) {
1064
- currentToolCall.arguments += toolCall.function.arguments;
1065
- }
1066
- }
1424
+ for (const part of delta?.tool_calls ?? []) {
1425
+ const index = part.index ?? 0;
1426
+ const call = toolCalls.get(index) ?? {
1427
+ id: "",
1428
+ name: "",
1429
+ arguments: ""
1430
+ };
1431
+ if (part.id) call.id = part.id;
1432
+ if (part.function?.name) call.name += part.function.name;
1433
+ if (part.function?.arguments)
1434
+ call.arguments += part.function.arguments;
1435
+ if (part.extra_content) call.extra_content = part.extra_content;
1436
+ toolCalls.set(index, call);
1067
1437
  }
1068
1438
  if (chunk.usage) {
1069
1439
  usage = {
@@ -1072,21 +1442,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
1072
1442
  total_tokens: chunk.usage.total_tokens
1073
1443
  };
1074
1444
  }
1075
- if (choice?.finish_reason) {
1076
- if (currentToolCall) {
1077
- yield {
1078
- type: "action:args",
1079
- id: currentToolCall.id,
1080
- args: currentToolCall.arguments
1081
- };
1082
- yield {
1083
- type: "action:end",
1084
- id: currentToolCall.id,
1085
- name: currentToolCall.name
1086
- };
1087
- currentToolCall = null;
1088
- }
1089
- }
1445
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
1446
+ }
1447
+ throwIfAborted(request.signal);
1448
+ if (!finishReason)
1449
+ throw new Error("OpenAI stream ended without a finish reason");
1450
+ if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
1451
+ throw new Error("OpenAI stream ended with incomplete tool calls");
1452
+ }
1453
+ for (const call of toolCalls.values()) {
1454
+ if (!call.id || !call.name)
1455
+ throw new Error("OpenAI stream contains an incomplete tool call");
1456
+ JSON.parse(call.arguments || "{}");
1457
+ }
1458
+ for (const call of toolCalls.values()) {
1459
+ yield {
1460
+ type: "action:start",
1461
+ id: call.id,
1462
+ name: call.name,
1463
+ ...call.extra_content ? { extra_content: call.extra_content } : {}
1464
+ };
1465
+ yield { type: "action:args", id: call.id, args: call.arguments };
1466
+ yield { type: "action:end", id: call.id, name: call.name };
1090
1467
  }
1091
1468
  if (collectedCitations.length > 0) {
1092
1469
  const uniqueCitations = deduplicateCitations(collectedCitations);
@@ -1095,26 +1472,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
1095
1472
  yield { type: "message:end" };
1096
1473
  yield { type: "done", usage };
1097
1474
  } catch (error) {
1098
- yield {
1099
- type: "error",
1100
- message: error instanceof Error ? error.message : "Unknown error",
1101
- code: `${this.provider.toUpperCase()}_ERROR`
1102
- };
1475
+ yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
1103
1476
  }
1104
1477
  }
1105
1478
  async complete(request) {
1479
+ throwIfAborted(request.signal);
1106
1480
  if (this.shouldUseResponsesApi(request)) {
1107
1481
  return this.completeWithResponses(request);
1108
1482
  }
1109
1483
  const client = await this.getClient();
1110
1484
  let messages;
1111
1485
  if (request.rawMessages && request.rawMessages.length > 0) {
1112
- const sanitized = request.rawMessages.map((msg) => {
1113
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
1114
- return { ...msg, content: null };
1115
- }
1116
- return msg;
1117
- });
1486
+ const sanitized = this.formatRawMessages(request.rawMessages);
1118
1487
  if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
1119
1488
  messages = [
1120
1489
  { role: "system", content: request.systemPrompt },
@@ -1129,7 +1498,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
1129
1498
  request.systemPrompt
1130
1499
  );
1131
1500
  }
1132
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1501
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1502
+ type: "function",
1503
+ function: {
1504
+ name: tool.name,
1505
+ description: tool.description,
1506
+ parameters: normalizeObjectJsonSchema(
1507
+ tool.inputSchema
1508
+ )
1509
+ }
1510
+ })) : formatTools(request.actions ?? []);
1133
1511
  const openaiToolOptions = request.providerToolOptions?.openai;
1134
1512
  const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
1135
1513
  type: "function",
@@ -1144,16 +1522,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1144
1522
  tools: tools.length > 0 ? tools : void 0,
1145
1523
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1146
1524
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1147
- ...buildOpenAITokenParams(
1525
+ ...buildOpenAIParameters(
1148
1526
  modelIdForCompletePayload,
1149
1527
  request.config?.maxTokens ?? this.config.maxTokens,
1150
- request.config?.temperature ?? this.config.temperature
1528
+ request.config?.temperature ?? this.config.temperature,
1529
+ this.parameterOptions(request)
1151
1530
  ),
1152
1531
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1153
1532
  stream: false
1154
1533
  };
1155
1534
  logProviderPayload("openai", "request payload", payload, request.debug);
1156
- const response = await client.chat.completions.create(payload);
1535
+ const response = await client.chat.completions.create(payload, {
1536
+ signal: request.signal
1537
+ });
1157
1538
  logProviderPayload("openai", "response payload", response, request.debug);
1158
1539
  const choice = response.choices?.[0];
1159
1540
  const message = choice?.message;