@yourgpt/llm-sdk 2.6.0-beta.0 → 2.6.0-beta.1

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 (55) hide show
  1. package/README.md +77 -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 +255 -164
  5. package/dist/adapters/index.mjs +255 -164
  6. package/dist/{base-C58Dsr9p.d.ts → base-BdTpUAWI.d.ts} +2 -1
  7. package/dist/{base-tNgbBaSo.d.mts → base-CkeT7u-O.d.mts} +2 -1
  8. package/dist/fallback/index.d.mts +4 -4
  9. package/dist/fallback/index.d.ts +4 -4
  10. package/dist/fallback/index.js +75 -39
  11. package/dist/fallback/index.mjs +75 -39
  12. package/dist/index.d.mts +8 -7
  13. package/dist/index.d.ts +8 -7
  14. package/dist/index.js +75 -28
  15. package/dist/index.mjs +75 -28
  16. package/dist/providers/anthropic/index.d.mts +3 -3
  17. package/dist/providers/anthropic/index.d.ts +3 -3
  18. package/dist/providers/azure/index.d.mts +3 -3
  19. package/dist/providers/azure/index.d.ts +3 -3
  20. package/dist/providers/fireworks/index.d.mts +3 -3
  21. package/dist/providers/fireworks/index.d.ts +3 -3
  22. package/dist/providers/fireworks/index.js +255 -164
  23. package/dist/providers/fireworks/index.mjs +255 -164
  24. package/dist/providers/google/index.d.mts +3 -3
  25. package/dist/providers/google/index.d.ts +3 -3
  26. package/dist/providers/google/index.js +255 -164
  27. package/dist/providers/google/index.mjs +255 -164
  28. package/dist/providers/ollama/index.d.mts +4 -4
  29. package/dist/providers/ollama/index.d.ts +4 -4
  30. package/dist/providers/openai/index.d.mts +6 -23
  31. package/dist/providers/openai/index.d.ts +6 -23
  32. package/dist/providers/openai/index.js +656 -450
  33. package/dist/providers/openai/index.mjs +656 -450
  34. package/dist/providers/openrouter/index.d.mts +3 -3
  35. package/dist/providers/openrouter/index.d.ts +3 -3
  36. package/dist/providers/openrouter/index.js +255 -164
  37. package/dist/providers/openrouter/index.mjs +255 -164
  38. package/dist/providers/togetherai/index.d.mts +3 -3
  39. package/dist/providers/togetherai/index.d.ts +3 -3
  40. package/dist/providers/togetherai/index.js +255 -164
  41. package/dist/providers/togetherai/index.mjs +255 -164
  42. package/dist/providers/xai/index.d.mts +3 -3
  43. package/dist/providers/xai/index.d.ts +3 -3
  44. package/dist/providers/xai/index.js +255 -164
  45. package/dist/providers/xai/index.mjs +255 -164
  46. package/dist/{types-BkQCSiIt.d.mts → types-BW3csYo5.d.mts} +22 -1
  47. package/dist/{types-BkQCSiIt.d.ts → types-BW3csYo5.d.ts} +22 -1
  48. package/dist/{types-B6dhnguR.d.mts → types-BWRYIvl_.d.mts} +11 -4
  49. package/dist/{types-CCxPmkmK.d.ts → types-CpXcT-tY.d.ts} +11 -4
  50. package/dist/{types-BQ31QIsA.d.ts → types-DA54bSmX.d.ts} +3 -11
  51. package/dist/{types-BSSiJW2o.d.mts → types-NOswlhm9.d.mts} +3 -11
  52. package/dist/yourgpt/index.d.mts +1 -1
  53. package/dist/yourgpt/index.d.ts +1 -1
  54. package/package.json +115 -48
  55. package/LICENSE +0 -21
@@ -1,3 +1,54 @@
1
+ // src/core/openai-parameters.ts
2
+ function capabilities(model) {
3
+ const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
4
+ const major = Number(gpt?.[1] ?? 0);
5
+ const minor = Number(gpt?.[2] ?? 0);
6
+ const chat = gpt?.[3]?.startsWith("chat") ?? false;
7
+ const reasoning = /^o\d+(?:-|$)/i.test(model) || major >= 5 && !chat;
8
+ const supportsNone = major === 5 && minor >= 1 && !chat || /^gpt-6-(?:sol|luna)(?:-\d{4}-\d{2}-\d{2})?$/i.test(model);
9
+ return { major, minor, reasoning, supportsNone };
10
+ }
11
+ function requiresOpenAIResponses(model, baseUrl, options = {}) {
12
+ if (options.parameterPolicy === "passthrough") return false;
13
+ const c = capabilities(model);
14
+ if (!c.reasoning || options.reasoningEffort === "none") return false;
15
+ if (!(c.major >= 6 || c.major === 5 && c.minor >= 4)) return false;
16
+ if (!baseUrl) return true;
17
+ try {
18
+ return new URL(baseUrl).hostname === "api.openai.com";
19
+ } catch {
20
+ return false;
21
+ }
22
+ }
23
+ function buildOpenAIParameters(model, maxTokens, temperature, options = {}, api = "chat") {
24
+ const c = capabilities(model ?? "");
25
+ const normalize = options.parameterPolicy !== "passthrough";
26
+ const effort = options.reasoningEffort;
27
+ if (normalize && c.reasoning && effort === "none" && !c.supportsNone) {
28
+ throw new Error(`${model} does not support reasoningEffort: none`);
29
+ }
30
+ if (normalize && c.major >= 6 && effort === "minimal") {
31
+ throw new Error(`${model} does not support reasoningEffort: minimal`);
32
+ }
33
+ const result = {
34
+ [api === "responses" ? "max_output_tokens" : normalize && c.reasoning ? "max_completion_tokens" : "max_tokens"]: maxTokens
35
+ };
36
+ if (effort !== void 0) {
37
+ if (api === "responses") result.reasoning = { effort };
38
+ else result.reasoning_effort = effort;
39
+ }
40
+ if (temperature !== void 0) {
41
+ if (!normalize || !c.reasoning || effort === "none" && c.supportsNone) {
42
+ result.temperature = temperature;
43
+ } else {
44
+ (options.onWarning ?? console.warn)(
45
+ `[llm-sdk] ${model}: omitted temperature because reasoning is enabled.`
46
+ );
47
+ }
48
+ }
49
+ return result;
50
+ }
51
+
1
52
  // src/adapters/base.ts
2
53
  function stringifyForDebug(value) {
3
54
  return JSON.stringify(
@@ -104,16 +155,6 @@ function normalizeObjectJsonSchema(schema) {
104
155
  }
105
156
  return normalized;
106
157
  }
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
158
  function toOpenAIResponseFormat(rf) {
118
159
  if (!rf) return void 0;
119
160
  if (rf.type === "json_object") return { type: "json_object" };
@@ -445,6 +486,28 @@ function formatMessages(messages) {
445
486
  });
446
487
  }
447
488
 
489
+ // src/core/provider-error.ts
490
+ function providerErrorEvent(error, code) {
491
+ const details = error ?? {};
492
+ const event = {
493
+ type: "error",
494
+ message: error instanceof Error ? error.message : String(error),
495
+ code,
496
+ ...typeof details.status === "number" ? { status: details.status } : {},
497
+ ...typeof details.code === "string" ? { providerCode: details.code } : {},
498
+ ...typeof details.param === "string" ? { param: details.param } : {},
499
+ ...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
500
+ };
501
+ Object.defineProperty(event, "cause", { value: error, enumerable: false });
502
+ return event;
503
+ }
504
+ function throwIfAborted(signal) {
505
+ if (!signal?.aborted) return;
506
+ const error = new Error("The operation was aborted");
507
+ error.name = "AbortError";
508
+ throw error;
509
+ }
510
+
448
511
  // src/core/utils.ts
449
512
  function generateId(prefix = "id") {
450
513
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -476,39 +539,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
476
539
  const { default: OpenAI } = await import('openai');
477
540
  this.client = new OpenAI({
478
541
  apiKey: this.config.apiKey,
479
- baseURL: this.config.baseUrl
542
+ baseURL: this.config.baseUrl,
543
+ organization: this.config.organization,
544
+ defaultHeaders: this.config.headers
480
545
  });
481
546
  }
482
547
  return this.client;
483
548
  }
549
+ parameterOptions(request) {
550
+ return {
551
+ ...this.config,
552
+ reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
553
+ };
554
+ }
555
+ toolDefinitions(request) {
556
+ if (request.toolDefinitions?.length) return request.toolDefinitions;
557
+ return formatTools(request.actions ?? []).map((tool) => ({
558
+ name: tool.function.name,
559
+ description: tool.function.description ?? "",
560
+ location: "server",
561
+ inputSchema: tool.function.parameters
562
+ }));
563
+ }
484
564
  shouldUseResponsesApi(request) {
485
- const hasTools = Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
486
- if (!hasTools) return false;
487
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
565
+ if (this.toolDefinitions(request).length === 0) return false;
566
+ if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
488
567
  return true;
489
- }
490
- return this.requiresResponsesApiForTools(
491
- request.config?.model || this.model
568
+ return requiresOpenAIResponses(
569
+ request.config?.model || this.model,
570
+ this.config.baseUrl,
571
+ this.parameterOptions(request)
492
572
  );
493
573
  }
494
- /**
495
- * Whether this model rejects function tools on /v1/chat/completions.
496
- *
497
- * Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
498
- * providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
499
- * restriction and may not implement /v1/responses at all.
500
- */
501
- requiresResponsesApiForTools(modelId) {
502
- if (!modelId) return false;
503
- if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
504
- const baseUrl = this.config.baseUrl;
505
- if (!baseUrl) return true;
506
- try {
507
- return new URL(baseUrl).hostname === "api.openai.com";
508
- } catch {
509
- return false;
510
- }
511
- }
512
574
  /**
513
575
  * Convert one message's content to Responses content parts.
514
576
  *
@@ -539,7 +601,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
539
601
  });
540
602
  }
541
603
  buildResponsesInput(request) {
542
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
604
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
543
605
  const input = [];
544
606
  for (const message of sourceMessages) {
545
607
  if (message.role === "system") {
@@ -589,6 +651,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
589
651
  }
590
652
  return input;
591
653
  }
654
+ /** Preserve Copilot screenshot attachments on every OpenAI transport. */
655
+ formatRawMessages(messages) {
656
+ return messages.map((message) => {
657
+ const { attachments, ...rest } = message;
658
+ let content = message.content;
659
+ if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
660
+ content = null;
661
+ }
662
+ if (Array.isArray(attachments) && attachments.length > 0) {
663
+ const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
664
+ (attachment) => attachmentToOpenAIImage(attachment)
665
+ ).filter((image) => image !== null);
666
+ if (images.length > 0) {
667
+ const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
668
+ content = [...parts, ...images];
669
+ }
670
+ }
671
+ return { ...rest, content };
672
+ });
673
+ }
592
674
  /**
593
675
  * Build the web_search tool for the Responses API, or undefined when web
594
676
  * search is off.
@@ -670,13 +752,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
670
752
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
671
753
  id: item.call_id ?? item.id ?? generateToolCallId(),
672
754
  name: item.name,
673
- args: (() => {
674
- try {
675
- return JSON.parse(item.arguments ?? "{}");
676
- } catch {
677
- return {};
678
- }
679
- })()
755
+ args: JSON.parse(item.arguments ?? "{}")
680
756
  })) : [];
681
757
  return {
682
758
  content,
@@ -700,18 +776,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
700
776
  instructions: request.systemPrompt,
701
777
  input: this.buildResponsesInput(request),
702
778
  tools: this.buildResponsesTools(
703
- request.toolDefinitions ?? [],
779
+ this.toolDefinitions(request),
704
780
  request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
705
781
  this.buildResponsesWebSearchTool(request)
706
782
  ),
707
- tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
783
+ tool_choice: openaiToolOptions?.toolChoice,
708
784
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
709
- // Reasoning models reject `temperature` outright — sending it would swap one
710
- // 400 for another. isOpenAIReasoningModel already encodes that family test.
711
- ...isOpenAIReasoningModel(modelIdForPayload) ? {} : {
712
- temperature: request.config?.temperature ?? this.config.temperature
713
- },
714
- max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
785
+ ...buildOpenAIParameters(
786
+ modelIdForPayload,
787
+ request.config?.maxTokens ?? this.config.maxTokens,
788
+ request.config?.temperature ?? this.config.temperature,
789
+ this.parameterOptions(request),
790
+ "responses"
791
+ ),
715
792
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
716
793
  stream
717
794
  };
@@ -719,10 +796,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
719
796
  }
720
797
  async completeWithResponses(request) {
721
798
  const client = await this.getClient();
799
+ throwIfAborted(request.signal);
722
800
  const payload = this.buildResponsesPayload(request, false);
723
801
  logProviderPayload("openai", "request payload", payload, request.debug);
724
- const response = await client.responses.create(payload);
802
+ if (!client.responses?.create)
803
+ throw new Error(
804
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
805
+ );
806
+ const response = await client.responses.create(payload, {
807
+ signal: request.signal
808
+ });
809
+ throwIfAborted(request.signal);
725
810
  logProviderPayload("openai", "response payload", response, request.debug);
811
+ if (response.status && response.status !== "completed") {
812
+ throw Object.assign(
813
+ new Error(
814
+ response.error?.message ?? `Responses request ${response.status}`
815
+ ),
816
+ response.error
817
+ );
818
+ }
726
819
  return this.parseResponsesResult(response);
727
820
  }
728
821
  /**
@@ -740,13 +833,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
740
833
  */
741
834
  async *streamWithResponses(request) {
742
835
  const client = await this.getClient();
836
+ throwIfAborted(request.signal);
743
837
  const payload = this.buildResponsesPayload(request, true);
744
838
  logProviderPayload("openai", "request payload", payload, request.debug);
745
- const stream = await client.responses.create(payload);
839
+ if (!client.responses?.create)
840
+ throw new Error(
841
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
842
+ );
843
+ const stream = await client.responses.create(payload, {
844
+ signal: request.signal
845
+ });
746
846
  const toolCalls = /* @__PURE__ */ new Map();
747
847
  let usage;
748
848
  const citations = [];
849
+ let completed = false;
749
850
  function* flushToolCalls() {
851
+ for (const call of toolCalls.values()) {
852
+ if (!call.name)
853
+ throw new Error("Responses tool call is missing its name");
854
+ JSON.parse(call.arguments || "{}");
855
+ }
750
856
  for (const call of toolCalls.values()) {
751
857
  yield { type: "action:start", id: call.id, name: call.name };
752
858
  yield { type: "action:args", id: call.id, args: call.arguments };
@@ -755,7 +861,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
755
861
  toolCalls.clear();
756
862
  }
757
863
  for await (const event of stream) {
758
- if (request.signal?.aborted) break;
864
+ throwIfAborted(request.signal);
759
865
  logProviderPayload("openai", "stream chunk", event, request.debug);
760
866
  const index = event?.output_index ?? 0;
761
867
  switch (event?.type) {
@@ -785,8 +891,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
785
891
  }
786
892
  break;
787
893
  }
788
- case "response.completed":
789
- case "response.incomplete": {
894
+ case "response.completed": {
895
+ completed = true;
790
896
  const found = this.collectResponsesCitations(
791
897
  event.response?.output,
792
898
  citations.length
@@ -802,13 +908,27 @@ var OpenAIAdapter = class _OpenAIAdapter {
802
908
  }
803
909
  break;
804
910
  }
805
- case "error":
806
- case "response.failed":
911
+ case "response.incomplete":
807
912
  throw new Error(
808
- event.message ?? event.response?.error?.message ?? "Responses stream failed"
913
+ `Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
809
914
  );
915
+ case "error":
916
+ case "response.failed": {
917
+ const details = event.response?.error ?? event;
918
+ throw Object.assign(
919
+ new Error(details.message ?? "Responses stream failed"),
920
+ {
921
+ code: details.code,
922
+ param: details.param,
923
+ status: details.status
924
+ }
925
+ );
926
+ }
810
927
  }
811
928
  }
929
+ throwIfAborted(request.signal);
930
+ if (!completed)
931
+ throw new Error("Responses stream ended without a completed response");
812
932
  yield* flushToolCalls();
813
933
  if (citations.length > 0) {
814
934
  yield { type: "citation", citations: deduplicateCitations(citations) };
@@ -817,6 +937,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
817
937
  yield { type: "done", usage };
818
938
  }
819
939
  async *stream(request) {
940
+ throwIfAborted(request.signal);
820
941
  if (this.shouldUseResponsesApi(request)) {
821
942
  const messageId2 = generateMessageId();
822
943
  yield { type: "message:start", id: messageId2 };
@@ -824,47 +945,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
824
945
  yield* this.streamWithResponses(request);
825
946
  return;
826
947
  } catch (error) {
827
- yield {
828
- type: "error",
829
- message: error instanceof Error ? error.message : "Unknown error",
830
- code: "OPENAI_RESPONSES_ERROR"
831
- };
948
+ yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
832
949
  return;
833
950
  }
834
951
  }
835
952
  const client = await this.getClient();
836
953
  let messages;
837
954
  if (request.rawMessages && request.rawMessages.length > 0) {
838
- const processedMessages = request.rawMessages.map((msg) => {
839
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
840
- return { ...msg, content: null };
841
- }
842
- const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
843
- if (hasAttachments) {
844
- const content = [];
845
- if (msg.content) {
846
- content.push({ type: "text", text: msg.content });
847
- }
848
- for (const attachment of msg.attachments) {
849
- if (attachment.type === "image") {
850
- let imageUrl;
851
- if (attachment.url) {
852
- imageUrl = attachment.url;
853
- } else if (attachment.data) {
854
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
855
- } else {
856
- continue;
857
- }
858
- content.push({
859
- type: "image_url",
860
- image_url: { url: imageUrl, detail: "auto" }
861
- });
862
- }
863
- }
864
- return { ...msg, content, attachments: void 0 };
865
- }
866
- return msg;
867
- });
955
+ const processedMessages = this.formatRawMessages(request.rawMessages);
868
956
  if (request.systemPrompt) {
869
957
  const hasSystem = processedMessages.some((m) => m.role === "system");
870
958
  if (!hasSystem) {
@@ -884,7 +972,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
884
972
  request.systemPrompt
885
973
  );
886
974
  }
887
- const tools = request.actions?.length ? formatTools(request.actions) : [];
975
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
976
+ type: "function",
977
+ function: {
978
+ name: tool.name,
979
+ description: tool.description,
980
+ parameters: normalizeObjectJsonSchema(
981
+ tool.inputSchema
982
+ )
983
+ }
984
+ })) : formatTools(request.actions ?? []);
888
985
  const webSearchConfig = request.webSearch ?? this.config.webSearch;
889
986
  if (webSearchConfig) {
890
987
  const webSearchTool = {
@@ -913,26 +1010,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
913
1010
  tools: tools.length > 0 ? tools : void 0,
914
1011
  tool_choice: tools.length > 0 ? toolChoice : void 0,
915
1012
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
916
- ...buildOpenAITokenParams(
1013
+ ...buildOpenAIParameters(
917
1014
  modelIdForPayload,
918
1015
  request.config?.maxTokens ?? this.config.maxTokens,
919
- request.config?.temperature ?? this.config.temperature
1016
+ request.config?.temperature ?? this.config.temperature,
1017
+ this.parameterOptions(request)
920
1018
  ),
921
1019
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
922
1020
  stream: true,
923
1021
  stream_options: { include_usage: true }
924
1022
  };
925
1023
  logProviderPayload("openai", "request payload", payload, request.debug);
926
- const stream = await client.chat.completions.create(payload);
927
- let currentToolCall = null;
1024
+ const stream = await client.chat.completions.create(payload, {
1025
+ signal: request.signal
1026
+ });
1027
+ const toolCalls = /* @__PURE__ */ new Map();
1028
+ let finishReason;
928
1029
  const collectedCitations = [];
929
1030
  let citationIndex = 0;
930
1031
  let usage;
931
1032
  for await (const chunk of stream) {
932
1033
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
933
- if (request.signal?.aborted) {
934
- break;
935
- }
1034
+ throwIfAborted(request.signal);
936
1035
  const delta = chunk.choices[0]?.delta;
937
1036
  const choice = chunk.choices[0];
938
1037
  if (delta?.content) {
@@ -955,38 +1054,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
955
1054
  }
956
1055
  }
957
1056
  }
958
- if (delta?.tool_calls) {
959
- for (const toolCall of delta.tool_calls) {
960
- if (toolCall.id) {
961
- if (currentToolCall) {
962
- yield {
963
- type: "action:args",
964
- id: currentToolCall.id,
965
- args: currentToolCall.arguments
966
- };
967
- yield {
968
- type: "action:end",
969
- id: currentToolCall.id,
970
- name: currentToolCall.name
971
- };
972
- }
973
- const tcExtraContent = toolCall.extra_content;
974
- currentToolCall = {
975
- id: toolCall.id,
976
- name: toolCall.function?.name || "",
977
- arguments: toolCall.function?.arguments || "",
978
- ...tcExtraContent ? { extra_content: tcExtraContent } : {}
979
- };
980
- yield {
981
- type: "action:start",
982
- id: currentToolCall.id,
983
- name: currentToolCall.name,
984
- ...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
985
- };
986
- } else if (currentToolCall && toolCall.function?.arguments) {
987
- currentToolCall.arguments += toolCall.function.arguments;
988
- }
989
- }
1057
+ for (const part of delta?.tool_calls ?? []) {
1058
+ const index = part.index ?? 0;
1059
+ const call = toolCalls.get(index) ?? {
1060
+ id: "",
1061
+ name: "",
1062
+ arguments: ""
1063
+ };
1064
+ if (part.id) call.id = part.id;
1065
+ if (part.function?.name) call.name += part.function.name;
1066
+ if (part.function?.arguments)
1067
+ call.arguments += part.function.arguments;
1068
+ if (part.extra_content) call.extra_content = part.extra_content;
1069
+ toolCalls.set(index, call);
990
1070
  }
991
1071
  if (chunk.usage) {
992
1072
  usage = {
@@ -995,21 +1075,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
995
1075
  total_tokens: chunk.usage.total_tokens
996
1076
  };
997
1077
  }
998
- if (choice?.finish_reason) {
999
- if (currentToolCall) {
1000
- yield {
1001
- type: "action:args",
1002
- id: currentToolCall.id,
1003
- args: currentToolCall.arguments
1004
- };
1005
- yield {
1006
- type: "action:end",
1007
- id: currentToolCall.id,
1008
- name: currentToolCall.name
1009
- };
1010
- currentToolCall = null;
1011
- }
1012
- }
1078
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
1079
+ }
1080
+ throwIfAborted(request.signal);
1081
+ if (!finishReason)
1082
+ throw new Error("OpenAI stream ended without a finish reason");
1083
+ if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
1084
+ throw new Error("OpenAI stream ended with incomplete tool calls");
1085
+ }
1086
+ for (const call of toolCalls.values()) {
1087
+ if (!call.id || !call.name)
1088
+ throw new Error("OpenAI stream contains an incomplete tool call");
1089
+ JSON.parse(call.arguments || "{}");
1090
+ }
1091
+ for (const call of toolCalls.values()) {
1092
+ yield {
1093
+ type: "action:start",
1094
+ id: call.id,
1095
+ name: call.name,
1096
+ ...call.extra_content ? { extra_content: call.extra_content } : {}
1097
+ };
1098
+ yield { type: "action:args", id: call.id, args: call.arguments };
1099
+ yield { type: "action:end", id: call.id, name: call.name };
1013
1100
  }
1014
1101
  if (collectedCitations.length > 0) {
1015
1102
  const uniqueCitations = deduplicateCitations(collectedCitations);
@@ -1018,26 +1105,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
1018
1105
  yield { type: "message:end" };
1019
1106
  yield { type: "done", usage };
1020
1107
  } catch (error) {
1021
- yield {
1022
- type: "error",
1023
- message: error instanceof Error ? error.message : "Unknown error",
1024
- code: `${this.provider.toUpperCase()}_ERROR`
1025
- };
1108
+ yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
1026
1109
  }
1027
1110
  }
1028
1111
  async complete(request) {
1112
+ throwIfAborted(request.signal);
1029
1113
  if (this.shouldUseResponsesApi(request)) {
1030
1114
  return this.completeWithResponses(request);
1031
1115
  }
1032
1116
  const client = await this.getClient();
1033
1117
  let messages;
1034
1118
  if (request.rawMessages && request.rawMessages.length > 0) {
1035
- const sanitized = request.rawMessages.map((msg) => {
1036
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
1037
- return { ...msg, content: null };
1038
- }
1039
- return msg;
1040
- });
1119
+ const sanitized = this.formatRawMessages(request.rawMessages);
1041
1120
  if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
1042
1121
  messages = [
1043
1122
  { role: "system", content: request.systemPrompt },
@@ -1052,7 +1131,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
1052
1131
  request.systemPrompt
1053
1132
  );
1054
1133
  }
1055
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1134
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1135
+ type: "function",
1136
+ function: {
1137
+ name: tool.name,
1138
+ description: tool.description,
1139
+ parameters: normalizeObjectJsonSchema(
1140
+ tool.inputSchema
1141
+ )
1142
+ }
1143
+ })) : formatTools(request.actions ?? []);
1056
1144
  const openaiToolOptions = request.providerToolOptions?.openai;
1057
1145
  const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
1058
1146
  type: "function",
@@ -1067,16 +1155,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1067
1155
  tools: tools.length > 0 ? tools : void 0,
1068
1156
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1069
1157
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1070
- ...buildOpenAITokenParams(
1158
+ ...buildOpenAIParameters(
1071
1159
  modelIdForCompletePayload,
1072
1160
  request.config?.maxTokens ?? this.config.maxTokens,
1073
- request.config?.temperature ?? this.config.temperature
1161
+ request.config?.temperature ?? this.config.temperature,
1162
+ this.parameterOptions(request)
1074
1163
  ),
1075
1164
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1076
1165
  stream: false
1077
1166
  };
1078
1167
  logProviderPayload("openai", "request payload", payload, request.debug);
1079
- const response = await client.chat.completions.create(payload);
1168
+ const response = await client.chat.completions.create(payload, {
1169
+ signal: request.signal
1170
+ });
1080
1171
  logProviderPayload("openai", "response payload", response, request.debug);
1081
1172
  const choice = response.choices?.[0];
1082
1173
  const message = choice?.message;
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BkQCSiIt.mjs';
2
- import { X as XAIProviderConfig, A as AIProvider } from '../../types-BSSiJW2o.mjs';
1
+ import { L as LanguageModel } from '../../types-BW3csYo5.mjs';
2
+ import { X as XAIProviderConfig, A as AIProvider } from '../../types-NOswlhm9.mjs';
3
3
  import 'zod';
4
- import '../../base-tNgbBaSo.mjs';
4
+ import '../../base-CkeT7u-O.mjs';
5
5
 
6
6
  /**
7
7
  * xAI Provider - Modern Pattern
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BkQCSiIt.js';
2
- import { X as XAIProviderConfig, A as AIProvider } from '../../types-BQ31QIsA.js';
1
+ import { L as LanguageModel } from '../../types-BW3csYo5.js';
2
+ import { X as XAIProviderConfig, A as AIProvider } from '../../types-DA54bSmX.js';
3
3
  import 'zod';
4
- import '../../base-C58Dsr9p.js';
4
+ import '../../base-BdTpUAWI.js';
5
5
 
6
6
  /**
7
7
  * xAI Provider - Modern Pattern