@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" };
@@ -440,6 +481,28 @@ function formatMessages(messages) {
440
481
  });
441
482
  }
442
483
 
484
+ // src/core/provider-error.ts
485
+ function providerErrorEvent(error, code) {
486
+ const details = error ?? {};
487
+ const event = {
488
+ type: "error",
489
+ message: error instanceof Error ? error.message : String(error),
490
+ code,
491
+ ...typeof details.status === "number" ? { status: details.status } : {},
492
+ ...typeof details.code === "string" ? { providerCode: details.code } : {},
493
+ ...typeof details.param === "string" ? { param: details.param } : {},
494
+ ...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
495
+ };
496
+ Object.defineProperty(event, "cause", { value: error, enumerable: false });
497
+ return event;
498
+ }
499
+ function throwIfAborted(signal) {
500
+ if (!signal?.aborted) return;
501
+ const error = new Error("The operation was aborted");
502
+ error.name = "AbortError";
503
+ throw error;
504
+ }
505
+
443
506
  // src/core/utils.ts
444
507
  function generateId(prefix = "id") {
445
508
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -471,39 +534,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
471
534
  const { default: OpenAI } = await import('openai');
472
535
  this.client = new OpenAI({
473
536
  apiKey: this.config.apiKey,
474
- baseURL: this.config.baseUrl
537
+ baseURL: this.config.baseUrl,
538
+ organization: this.config.organization,
539
+ defaultHeaders: this.config.headers
475
540
  });
476
541
  }
477
542
  return this.client;
478
543
  }
544
+ parameterOptions(request) {
545
+ return {
546
+ ...this.config,
547
+ reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
548
+ };
549
+ }
550
+ toolDefinitions(request) {
551
+ if (request.toolDefinitions?.length) return request.toolDefinitions;
552
+ return formatTools(request.actions ?? []).map((tool) => ({
553
+ name: tool.function.name,
554
+ description: tool.function.description ?? "",
555
+ location: "server",
556
+ inputSchema: tool.function.parameters
557
+ }));
558
+ }
479
559
  shouldUseResponsesApi(request) {
480
- const hasTools = Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
481
- if (!hasTools) return false;
482
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
560
+ if (this.toolDefinitions(request).length === 0) return false;
561
+ if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
483
562
  return true;
484
- }
485
- return this.requiresResponsesApiForTools(
486
- request.config?.model || this.model
563
+ return requiresOpenAIResponses(
564
+ request.config?.model || this.model,
565
+ this.config.baseUrl,
566
+ this.parameterOptions(request)
487
567
  );
488
568
  }
489
- /**
490
- * Whether this model rejects function tools on /v1/chat/completions.
491
- *
492
- * Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
493
- * providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
494
- * restriction and may not implement /v1/responses at all.
495
- */
496
- requiresResponsesApiForTools(modelId) {
497
- if (!modelId) return false;
498
- if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
499
- const baseUrl = this.config.baseUrl;
500
- if (!baseUrl) return true;
501
- try {
502
- return new URL(baseUrl).hostname === "api.openai.com";
503
- } catch {
504
- return false;
505
- }
506
- }
507
569
  /**
508
570
  * Convert one message's content to Responses content parts.
509
571
  *
@@ -534,7 +596,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
534
596
  });
535
597
  }
536
598
  buildResponsesInput(request) {
537
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
599
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
538
600
  const input = [];
539
601
  for (const message of sourceMessages) {
540
602
  if (message.role === "system") {
@@ -584,6 +646,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
584
646
  }
585
647
  return input;
586
648
  }
649
+ /** Preserve Copilot screenshot attachments on every OpenAI transport. */
650
+ formatRawMessages(messages) {
651
+ return messages.map((message) => {
652
+ const { attachments, ...rest } = message;
653
+ let content = message.content;
654
+ if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
655
+ content = null;
656
+ }
657
+ if (Array.isArray(attachments) && attachments.length > 0) {
658
+ const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
659
+ (attachment) => attachmentToOpenAIImage(attachment)
660
+ ).filter((image) => image !== null);
661
+ if (images.length > 0) {
662
+ const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
663
+ content = [...parts, ...images];
664
+ }
665
+ }
666
+ return { ...rest, content };
667
+ });
668
+ }
587
669
  /**
588
670
  * Build the web_search tool for the Responses API, or undefined when web
589
671
  * search is off.
@@ -665,13 +747,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
665
747
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
666
748
  id: item.call_id ?? item.id ?? generateToolCallId(),
667
749
  name: item.name,
668
- args: (() => {
669
- try {
670
- return JSON.parse(item.arguments ?? "{}");
671
- } catch {
672
- return {};
673
- }
674
- })()
750
+ args: JSON.parse(item.arguments ?? "{}")
675
751
  })) : [];
676
752
  return {
677
753
  content,
@@ -695,18 +771,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
695
771
  instructions: request.systemPrompt,
696
772
  input: this.buildResponsesInput(request),
697
773
  tools: this.buildResponsesTools(
698
- request.toolDefinitions ?? [],
774
+ this.toolDefinitions(request),
699
775
  request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
700
776
  this.buildResponsesWebSearchTool(request)
701
777
  ),
702
- tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
778
+ tool_choice: openaiToolOptions?.toolChoice,
703
779
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
704
- // Reasoning models reject `temperature` outright — sending it would swap one
705
- // 400 for another. isOpenAIReasoningModel already encodes that family test.
706
- ...isOpenAIReasoningModel(modelIdForPayload) ? {} : {
707
- temperature: request.config?.temperature ?? this.config.temperature
708
- },
709
- max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
780
+ ...buildOpenAIParameters(
781
+ modelIdForPayload,
782
+ request.config?.maxTokens ?? this.config.maxTokens,
783
+ request.config?.temperature ?? this.config.temperature,
784
+ this.parameterOptions(request),
785
+ "responses"
786
+ ),
710
787
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
711
788
  stream
712
789
  };
@@ -714,10 +791,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
714
791
  }
715
792
  async completeWithResponses(request) {
716
793
  const client = await this.getClient();
794
+ throwIfAborted(request.signal);
717
795
  const payload = this.buildResponsesPayload(request, false);
718
796
  logProviderPayload("openai", "request payload", payload, request.debug);
719
- const response = await client.responses.create(payload);
797
+ if (!client.responses?.create)
798
+ throw new Error(
799
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
800
+ );
801
+ const response = await client.responses.create(payload, {
802
+ signal: request.signal
803
+ });
804
+ throwIfAborted(request.signal);
720
805
  logProviderPayload("openai", "response payload", response, request.debug);
806
+ if (response.status && response.status !== "completed") {
807
+ throw Object.assign(
808
+ new Error(
809
+ response.error?.message ?? `Responses request ${response.status}`
810
+ ),
811
+ response.error
812
+ );
813
+ }
721
814
  return this.parseResponsesResult(response);
722
815
  }
723
816
  /**
@@ -735,13 +828,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
735
828
  */
736
829
  async *streamWithResponses(request) {
737
830
  const client = await this.getClient();
831
+ throwIfAborted(request.signal);
738
832
  const payload = this.buildResponsesPayload(request, true);
739
833
  logProviderPayload("openai", "request payload", payload, request.debug);
740
- const stream = await client.responses.create(payload);
834
+ if (!client.responses?.create)
835
+ throw new Error(
836
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
837
+ );
838
+ const stream = await client.responses.create(payload, {
839
+ signal: request.signal
840
+ });
741
841
  const toolCalls = /* @__PURE__ */ new Map();
742
842
  let usage;
743
843
  const citations = [];
844
+ let completed = false;
744
845
  function* flushToolCalls() {
846
+ for (const call of toolCalls.values()) {
847
+ if (!call.name)
848
+ throw new Error("Responses tool call is missing its name");
849
+ JSON.parse(call.arguments || "{}");
850
+ }
745
851
  for (const call of toolCalls.values()) {
746
852
  yield { type: "action:start", id: call.id, name: call.name };
747
853
  yield { type: "action:args", id: call.id, args: call.arguments };
@@ -750,7 +856,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
750
856
  toolCalls.clear();
751
857
  }
752
858
  for await (const event of stream) {
753
- if (request.signal?.aborted) break;
859
+ throwIfAborted(request.signal);
754
860
  logProviderPayload("openai", "stream chunk", event, request.debug);
755
861
  const index = event?.output_index ?? 0;
756
862
  switch (event?.type) {
@@ -780,8 +886,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
780
886
  }
781
887
  break;
782
888
  }
783
- case "response.completed":
784
- case "response.incomplete": {
889
+ case "response.completed": {
890
+ completed = true;
785
891
  const found = this.collectResponsesCitations(
786
892
  event.response?.output,
787
893
  citations.length
@@ -797,13 +903,27 @@ var OpenAIAdapter = class _OpenAIAdapter {
797
903
  }
798
904
  break;
799
905
  }
800
- case "error":
801
- case "response.failed":
906
+ case "response.incomplete":
802
907
  throw new Error(
803
- event.message ?? event.response?.error?.message ?? "Responses stream failed"
908
+ `Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
804
909
  );
910
+ case "error":
911
+ case "response.failed": {
912
+ const details = event.response?.error ?? event;
913
+ throw Object.assign(
914
+ new Error(details.message ?? "Responses stream failed"),
915
+ {
916
+ code: details.code,
917
+ param: details.param,
918
+ status: details.status
919
+ }
920
+ );
921
+ }
805
922
  }
806
923
  }
924
+ throwIfAborted(request.signal);
925
+ if (!completed)
926
+ throw new Error("Responses stream ended without a completed response");
807
927
  yield* flushToolCalls();
808
928
  if (citations.length > 0) {
809
929
  yield { type: "citation", citations: deduplicateCitations(citations) };
@@ -812,6 +932,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
812
932
  yield { type: "done", usage };
813
933
  }
814
934
  async *stream(request) {
935
+ throwIfAborted(request.signal);
815
936
  if (this.shouldUseResponsesApi(request)) {
816
937
  const messageId2 = generateMessageId();
817
938
  yield { type: "message:start", id: messageId2 };
@@ -819,47 +940,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
819
940
  yield* this.streamWithResponses(request);
820
941
  return;
821
942
  } catch (error) {
822
- yield {
823
- type: "error",
824
- message: error instanceof Error ? error.message : "Unknown error",
825
- code: "OPENAI_RESPONSES_ERROR"
826
- };
943
+ yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
827
944
  return;
828
945
  }
829
946
  }
830
947
  const client = await this.getClient();
831
948
  let messages;
832
949
  if (request.rawMessages && request.rawMessages.length > 0) {
833
- const processedMessages = request.rawMessages.map((msg) => {
834
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
835
- return { ...msg, content: null };
836
- }
837
- const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
838
- if (hasAttachments) {
839
- const content = [];
840
- if (msg.content) {
841
- content.push({ type: "text", text: msg.content });
842
- }
843
- for (const attachment of msg.attachments) {
844
- if (attachment.type === "image") {
845
- let imageUrl;
846
- if (attachment.url) {
847
- imageUrl = attachment.url;
848
- } else if (attachment.data) {
849
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
850
- } else {
851
- continue;
852
- }
853
- content.push({
854
- type: "image_url",
855
- image_url: { url: imageUrl, detail: "auto" }
856
- });
857
- }
858
- }
859
- return { ...msg, content, attachments: void 0 };
860
- }
861
- return msg;
862
- });
950
+ const processedMessages = this.formatRawMessages(request.rawMessages);
863
951
  if (request.systemPrompt) {
864
952
  const hasSystem = processedMessages.some((m) => m.role === "system");
865
953
  if (!hasSystem) {
@@ -879,7 +967,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
879
967
  request.systemPrompt
880
968
  );
881
969
  }
882
- const tools = request.actions?.length ? formatTools(request.actions) : [];
970
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
971
+ type: "function",
972
+ function: {
973
+ name: tool.name,
974
+ description: tool.description,
975
+ parameters: normalizeObjectJsonSchema(
976
+ tool.inputSchema
977
+ )
978
+ }
979
+ })) : formatTools(request.actions ?? []);
883
980
  const webSearchConfig = request.webSearch ?? this.config.webSearch;
884
981
  if (webSearchConfig) {
885
982
  const webSearchTool = {
@@ -908,26 +1005,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
908
1005
  tools: tools.length > 0 ? tools : void 0,
909
1006
  tool_choice: tools.length > 0 ? toolChoice : void 0,
910
1007
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
911
- ...buildOpenAITokenParams(
1008
+ ...buildOpenAIParameters(
912
1009
  modelIdForPayload,
913
1010
  request.config?.maxTokens ?? this.config.maxTokens,
914
- request.config?.temperature ?? this.config.temperature
1011
+ request.config?.temperature ?? this.config.temperature,
1012
+ this.parameterOptions(request)
915
1013
  ),
916
1014
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
917
1015
  stream: true,
918
1016
  stream_options: { include_usage: true }
919
1017
  };
920
1018
  logProviderPayload("openai", "request payload", payload, request.debug);
921
- const stream = await client.chat.completions.create(payload);
922
- let currentToolCall = null;
1019
+ const stream = await client.chat.completions.create(payload, {
1020
+ signal: request.signal
1021
+ });
1022
+ const toolCalls = /* @__PURE__ */ new Map();
1023
+ let finishReason;
923
1024
  const collectedCitations = [];
924
1025
  let citationIndex = 0;
925
1026
  let usage;
926
1027
  for await (const chunk of stream) {
927
1028
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
928
- if (request.signal?.aborted) {
929
- break;
930
- }
1029
+ throwIfAborted(request.signal);
931
1030
  const delta = chunk.choices[0]?.delta;
932
1031
  const choice = chunk.choices[0];
933
1032
  if (delta?.content) {
@@ -950,38 +1049,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
950
1049
  }
951
1050
  }
952
1051
  }
953
- if (delta?.tool_calls) {
954
- for (const toolCall of delta.tool_calls) {
955
- if (toolCall.id) {
956
- if (currentToolCall) {
957
- yield {
958
- type: "action:args",
959
- id: currentToolCall.id,
960
- args: currentToolCall.arguments
961
- };
962
- yield {
963
- type: "action:end",
964
- id: currentToolCall.id,
965
- name: currentToolCall.name
966
- };
967
- }
968
- const tcExtraContent = toolCall.extra_content;
969
- currentToolCall = {
970
- id: toolCall.id,
971
- name: toolCall.function?.name || "",
972
- arguments: toolCall.function?.arguments || "",
973
- ...tcExtraContent ? { extra_content: tcExtraContent } : {}
974
- };
975
- yield {
976
- type: "action:start",
977
- id: currentToolCall.id,
978
- name: currentToolCall.name,
979
- ...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
980
- };
981
- } else if (currentToolCall && toolCall.function?.arguments) {
982
- currentToolCall.arguments += toolCall.function.arguments;
983
- }
984
- }
1052
+ for (const part of delta?.tool_calls ?? []) {
1053
+ const index = part.index ?? 0;
1054
+ const call = toolCalls.get(index) ?? {
1055
+ id: "",
1056
+ name: "",
1057
+ arguments: ""
1058
+ };
1059
+ if (part.id) call.id = part.id;
1060
+ if (part.function?.name) call.name += part.function.name;
1061
+ if (part.function?.arguments)
1062
+ call.arguments += part.function.arguments;
1063
+ if (part.extra_content) call.extra_content = part.extra_content;
1064
+ toolCalls.set(index, call);
985
1065
  }
986
1066
  if (chunk.usage) {
987
1067
  usage = {
@@ -990,21 +1070,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
990
1070
  total_tokens: chunk.usage.total_tokens
991
1071
  };
992
1072
  }
993
- if (choice?.finish_reason) {
994
- if (currentToolCall) {
995
- yield {
996
- type: "action:args",
997
- id: currentToolCall.id,
998
- args: currentToolCall.arguments
999
- };
1000
- yield {
1001
- type: "action:end",
1002
- id: currentToolCall.id,
1003
- name: currentToolCall.name
1004
- };
1005
- currentToolCall = null;
1006
- }
1007
- }
1073
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
1074
+ }
1075
+ throwIfAborted(request.signal);
1076
+ if (!finishReason)
1077
+ throw new Error("OpenAI stream ended without a finish reason");
1078
+ if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
1079
+ throw new Error("OpenAI stream ended with incomplete tool calls");
1080
+ }
1081
+ for (const call of toolCalls.values()) {
1082
+ if (!call.id || !call.name)
1083
+ throw new Error("OpenAI stream contains an incomplete tool call");
1084
+ JSON.parse(call.arguments || "{}");
1085
+ }
1086
+ for (const call of toolCalls.values()) {
1087
+ yield {
1088
+ type: "action:start",
1089
+ id: call.id,
1090
+ name: call.name,
1091
+ ...call.extra_content ? { extra_content: call.extra_content } : {}
1092
+ };
1093
+ yield { type: "action:args", id: call.id, args: call.arguments };
1094
+ yield { type: "action:end", id: call.id, name: call.name };
1008
1095
  }
1009
1096
  if (collectedCitations.length > 0) {
1010
1097
  const uniqueCitations = deduplicateCitations(collectedCitations);
@@ -1013,26 +1100,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
1013
1100
  yield { type: "message:end" };
1014
1101
  yield { type: "done", usage };
1015
1102
  } catch (error) {
1016
- yield {
1017
- type: "error",
1018
- message: error instanceof Error ? error.message : "Unknown error",
1019
- code: `${this.provider.toUpperCase()}_ERROR`
1020
- };
1103
+ yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
1021
1104
  }
1022
1105
  }
1023
1106
  async complete(request) {
1107
+ throwIfAborted(request.signal);
1024
1108
  if (this.shouldUseResponsesApi(request)) {
1025
1109
  return this.completeWithResponses(request);
1026
1110
  }
1027
1111
  const client = await this.getClient();
1028
1112
  let messages;
1029
1113
  if (request.rawMessages && request.rawMessages.length > 0) {
1030
- const sanitized = request.rawMessages.map((msg) => {
1031
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
1032
- return { ...msg, content: null };
1033
- }
1034
- return msg;
1035
- });
1114
+ const sanitized = this.formatRawMessages(request.rawMessages);
1036
1115
  if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
1037
1116
  messages = [
1038
1117
  { role: "system", content: request.systemPrompt },
@@ -1047,7 +1126,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
1047
1126
  request.systemPrompt
1048
1127
  );
1049
1128
  }
1050
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1129
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1130
+ type: "function",
1131
+ function: {
1132
+ name: tool.name,
1133
+ description: tool.description,
1134
+ parameters: normalizeObjectJsonSchema(
1135
+ tool.inputSchema
1136
+ )
1137
+ }
1138
+ })) : formatTools(request.actions ?? []);
1051
1139
  const openaiToolOptions = request.providerToolOptions?.openai;
1052
1140
  const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
1053
1141
  type: "function",
@@ -1062,16 +1150,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1062
1150
  tools: tools.length > 0 ? tools : void 0,
1063
1151
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1064
1152
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1065
- ...buildOpenAITokenParams(
1153
+ ...buildOpenAIParameters(
1066
1154
  modelIdForCompletePayload,
1067
1155
  request.config?.maxTokens ?? this.config.maxTokens,
1068
- request.config?.temperature ?? this.config.temperature
1156
+ request.config?.temperature ?? this.config.temperature,
1157
+ this.parameterOptions(request)
1069
1158
  ),
1070
1159
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1071
1160
  stream: false
1072
1161
  };
1073
1162
  logProviderPayload("openai", "request payload", payload, request.debug);
1074
- const response = await client.chat.completions.create(payload);
1163
+ const response = await client.chat.completions.create(payload, {
1164
+ signal: request.signal
1165
+ });
1075
1166
  logProviderPayload("openai", "response payload", response, request.debug);
1076
1167
  const choice = response.choices?.[0];
1077
1168
  const message = choice?.message;
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BkQCSiIt.mjs';
2
- import { G as GoogleProviderConfig, A as AIProvider } from '../../types-BSSiJW2o.mjs';
1
+ import { L as LanguageModel } from '../../types-BW3csYo5.mjs';
2
+ import { G as GoogleProviderConfig, 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
  * Google Provider - OpenAI-Compatible
@@ -1,7 +1,7 @@
1
- import { L as LanguageModel } from '../../types-BkQCSiIt.js';
2
- import { G as GoogleProviderConfig, A as AIProvider } from '../../types-BQ31QIsA.js';
1
+ import { L as LanguageModel } from '../../types-BW3csYo5.js';
2
+ import { G as GoogleProviderConfig, 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
  * Google Provider - OpenAI-Compatible