@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" };
@@ -520,6 +561,28 @@ function formatMessagesForGoogle(messages) {
520
561
  });
521
562
  }
522
563
 
564
+ // src/core/provider-error.ts
565
+ function providerErrorEvent(error, code) {
566
+ const details = error ?? {};
567
+ const event = {
568
+ type: "error",
569
+ message: error instanceof Error ? error.message : String(error),
570
+ code,
571
+ ...typeof details.status === "number" ? { status: details.status } : {},
572
+ ...typeof details.code === "string" ? { providerCode: details.code } : {},
573
+ ...typeof details.param === "string" ? { param: details.param } : {},
574
+ ...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
575
+ };
576
+ Object.defineProperty(event, "cause", { value: error, enumerable: false });
577
+ return event;
578
+ }
579
+ function throwIfAborted(signal) {
580
+ if (!signal?.aborted) return;
581
+ const error = new Error("The operation was aborted");
582
+ error.name = "AbortError";
583
+ throw error;
584
+ }
585
+
523
586
  // src/core/utils.ts
524
587
  function generateId(prefix = "id") {
525
588
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -551,39 +614,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
551
614
  const { default: OpenAI } = await import('openai');
552
615
  this.client = new OpenAI({
553
616
  apiKey: this.config.apiKey,
554
- baseURL: this.config.baseUrl
617
+ baseURL: this.config.baseUrl,
618
+ organization: this.config.organization,
619
+ defaultHeaders: this.config.headers
555
620
  });
556
621
  }
557
622
  return this.client;
558
623
  }
624
+ parameterOptions(request) {
625
+ return {
626
+ ...this.config,
627
+ reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
628
+ };
629
+ }
630
+ toolDefinitions(request) {
631
+ if (request.toolDefinitions?.length) return request.toolDefinitions;
632
+ return formatTools(request.actions ?? []).map((tool) => ({
633
+ name: tool.function.name,
634
+ description: tool.function.description ?? "",
635
+ location: "server",
636
+ inputSchema: tool.function.parameters
637
+ }));
638
+ }
559
639
  shouldUseResponsesApi(request) {
560
- const hasTools = Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
561
- if (!hasTools) return false;
562
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
640
+ if (this.toolDefinitions(request).length === 0) return false;
641
+ if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
563
642
  return true;
564
- }
565
- return this.requiresResponsesApiForTools(
566
- request.config?.model || this.model
643
+ return requiresOpenAIResponses(
644
+ request.config?.model || this.model,
645
+ this.config.baseUrl,
646
+ this.parameterOptions(request)
567
647
  );
568
648
  }
569
- /**
570
- * Whether this model rejects function tools on /v1/chat/completions.
571
- *
572
- * Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
573
- * providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
574
- * restriction and may not implement /v1/responses at all.
575
- */
576
- requiresResponsesApiForTools(modelId) {
577
- if (!modelId) return false;
578
- if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
579
- const baseUrl = this.config.baseUrl;
580
- if (!baseUrl) return true;
581
- try {
582
- return new URL(baseUrl).hostname === "api.openai.com";
583
- } catch {
584
- return false;
585
- }
586
- }
587
649
  /**
588
650
  * Convert one message's content to Responses content parts.
589
651
  *
@@ -614,7 +676,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
614
676
  });
615
677
  }
616
678
  buildResponsesInput(request) {
617
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
679
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
618
680
  const input = [];
619
681
  for (const message of sourceMessages) {
620
682
  if (message.role === "system") {
@@ -664,6 +726,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
664
726
  }
665
727
  return input;
666
728
  }
729
+ /** Preserve Copilot screenshot attachments on every OpenAI transport. */
730
+ formatRawMessages(messages) {
731
+ return messages.map((message) => {
732
+ const { attachments, ...rest } = message;
733
+ let content = message.content;
734
+ if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
735
+ content = null;
736
+ }
737
+ if (Array.isArray(attachments) && attachments.length > 0) {
738
+ const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
739
+ (attachment) => attachmentToOpenAIImage(attachment)
740
+ ).filter((image) => image !== null);
741
+ if (images.length > 0) {
742
+ const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
743
+ content = [...parts, ...images];
744
+ }
745
+ }
746
+ return { ...rest, content };
747
+ });
748
+ }
667
749
  /**
668
750
  * Build the web_search tool for the Responses API, or undefined when web
669
751
  * search is off.
@@ -745,13 +827,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
745
827
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
746
828
  id: item.call_id ?? item.id ?? generateToolCallId(),
747
829
  name: item.name,
748
- args: (() => {
749
- try {
750
- return JSON.parse(item.arguments ?? "{}");
751
- } catch {
752
- return {};
753
- }
754
- })()
830
+ args: JSON.parse(item.arguments ?? "{}")
755
831
  })) : [];
756
832
  return {
757
833
  content,
@@ -775,18 +851,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
775
851
  instructions: request.systemPrompt,
776
852
  input: this.buildResponsesInput(request),
777
853
  tools: this.buildResponsesTools(
778
- request.toolDefinitions ?? [],
854
+ this.toolDefinitions(request),
779
855
  request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
780
856
  this.buildResponsesWebSearchTool(request)
781
857
  ),
782
- tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
858
+ tool_choice: openaiToolOptions?.toolChoice,
783
859
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
784
- // Reasoning models reject `temperature` outright — sending it would swap one
785
- // 400 for another. isOpenAIReasoningModel already encodes that family test.
786
- ...isOpenAIReasoningModel(modelIdForPayload) ? {} : {
787
- temperature: request.config?.temperature ?? this.config.temperature
788
- },
789
- max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
860
+ ...buildOpenAIParameters(
861
+ modelIdForPayload,
862
+ request.config?.maxTokens ?? this.config.maxTokens,
863
+ request.config?.temperature ?? this.config.temperature,
864
+ this.parameterOptions(request),
865
+ "responses"
866
+ ),
790
867
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
791
868
  stream
792
869
  };
@@ -794,10 +871,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
794
871
  }
795
872
  async completeWithResponses(request) {
796
873
  const client = await this.getClient();
874
+ throwIfAborted(request.signal);
797
875
  const payload = this.buildResponsesPayload(request, false);
798
876
  logProviderPayload("openai", "request payload", payload, request.debug);
799
- const response = await client.responses.create(payload);
877
+ if (!client.responses?.create)
878
+ throw new Error(
879
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
880
+ );
881
+ const response = await client.responses.create(payload, {
882
+ signal: request.signal
883
+ });
884
+ throwIfAborted(request.signal);
800
885
  logProviderPayload("openai", "response payload", response, request.debug);
886
+ if (response.status && response.status !== "completed") {
887
+ throw Object.assign(
888
+ new Error(
889
+ response.error?.message ?? `Responses request ${response.status}`
890
+ ),
891
+ response.error
892
+ );
893
+ }
801
894
  return this.parseResponsesResult(response);
802
895
  }
803
896
  /**
@@ -815,13 +908,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
815
908
  */
816
909
  async *streamWithResponses(request) {
817
910
  const client = await this.getClient();
911
+ throwIfAborted(request.signal);
818
912
  const payload = this.buildResponsesPayload(request, true);
819
913
  logProviderPayload("openai", "request payload", payload, request.debug);
820
- const stream = await client.responses.create(payload);
914
+ if (!client.responses?.create)
915
+ throw new Error(
916
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
917
+ );
918
+ const stream = await client.responses.create(payload, {
919
+ signal: request.signal
920
+ });
821
921
  const toolCalls = /* @__PURE__ */ new Map();
822
922
  let usage;
823
923
  const citations = [];
924
+ let completed = false;
824
925
  function* flushToolCalls() {
926
+ for (const call of toolCalls.values()) {
927
+ if (!call.name)
928
+ throw new Error("Responses tool call is missing its name");
929
+ JSON.parse(call.arguments || "{}");
930
+ }
825
931
  for (const call of toolCalls.values()) {
826
932
  yield { type: "action:start", id: call.id, name: call.name };
827
933
  yield { type: "action:args", id: call.id, args: call.arguments };
@@ -830,7 +936,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
830
936
  toolCalls.clear();
831
937
  }
832
938
  for await (const event of stream) {
833
- if (request.signal?.aborted) break;
939
+ throwIfAborted(request.signal);
834
940
  logProviderPayload("openai", "stream chunk", event, request.debug);
835
941
  const index = event?.output_index ?? 0;
836
942
  switch (event?.type) {
@@ -860,8 +966,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
860
966
  }
861
967
  break;
862
968
  }
863
- case "response.completed":
864
- case "response.incomplete": {
969
+ case "response.completed": {
970
+ completed = true;
865
971
  const found = this.collectResponsesCitations(
866
972
  event.response?.output,
867
973
  citations.length
@@ -877,13 +983,27 @@ var OpenAIAdapter = class _OpenAIAdapter {
877
983
  }
878
984
  break;
879
985
  }
880
- case "error":
881
- case "response.failed":
986
+ case "response.incomplete":
882
987
  throw new Error(
883
- event.message ?? event.response?.error?.message ?? "Responses stream failed"
988
+ `Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
884
989
  );
990
+ case "error":
991
+ case "response.failed": {
992
+ const details = event.response?.error ?? event;
993
+ throw Object.assign(
994
+ new Error(details.message ?? "Responses stream failed"),
995
+ {
996
+ code: details.code,
997
+ param: details.param,
998
+ status: details.status
999
+ }
1000
+ );
1001
+ }
885
1002
  }
886
1003
  }
1004
+ throwIfAborted(request.signal);
1005
+ if (!completed)
1006
+ throw new Error("Responses stream ended without a completed response");
887
1007
  yield* flushToolCalls();
888
1008
  if (citations.length > 0) {
889
1009
  yield { type: "citation", citations: deduplicateCitations(citations) };
@@ -892,6 +1012,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
892
1012
  yield { type: "done", usage };
893
1013
  }
894
1014
  async *stream(request) {
1015
+ throwIfAborted(request.signal);
895
1016
  if (this.shouldUseResponsesApi(request)) {
896
1017
  const messageId2 = generateMessageId();
897
1018
  yield { type: "message:start", id: messageId2 };
@@ -899,47 +1020,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
899
1020
  yield* this.streamWithResponses(request);
900
1021
  return;
901
1022
  } catch (error) {
902
- yield {
903
- type: "error",
904
- message: error instanceof Error ? error.message : "Unknown error",
905
- code: "OPENAI_RESPONSES_ERROR"
906
- };
1023
+ yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
907
1024
  return;
908
1025
  }
909
1026
  }
910
1027
  const client = await this.getClient();
911
1028
  let messages;
912
1029
  if (request.rawMessages && request.rawMessages.length > 0) {
913
- const processedMessages = request.rawMessages.map((msg) => {
914
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
915
- return { ...msg, content: null };
916
- }
917
- const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
918
- if (hasAttachments) {
919
- const content = [];
920
- if (msg.content) {
921
- content.push({ type: "text", text: msg.content });
922
- }
923
- for (const attachment of msg.attachments) {
924
- if (attachment.type === "image") {
925
- let imageUrl;
926
- if (attachment.url) {
927
- imageUrl = attachment.url;
928
- } else if (attachment.data) {
929
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
930
- } else {
931
- continue;
932
- }
933
- content.push({
934
- type: "image_url",
935
- image_url: { url: imageUrl, detail: "auto" }
936
- });
937
- }
938
- }
939
- return { ...msg, content, attachments: void 0 };
940
- }
941
- return msg;
942
- });
1030
+ const processedMessages = this.formatRawMessages(request.rawMessages);
943
1031
  if (request.systemPrompt) {
944
1032
  const hasSystem = processedMessages.some((m) => m.role === "system");
945
1033
  if (!hasSystem) {
@@ -959,7 +1047,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
959
1047
  request.systemPrompt
960
1048
  );
961
1049
  }
962
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1050
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1051
+ type: "function",
1052
+ function: {
1053
+ name: tool.name,
1054
+ description: tool.description,
1055
+ parameters: normalizeObjectJsonSchema(
1056
+ tool.inputSchema
1057
+ )
1058
+ }
1059
+ })) : formatTools(request.actions ?? []);
963
1060
  const webSearchConfig = request.webSearch ?? this.config.webSearch;
964
1061
  if (webSearchConfig) {
965
1062
  const webSearchTool = {
@@ -988,26 +1085,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
988
1085
  tools: tools.length > 0 ? tools : void 0,
989
1086
  tool_choice: tools.length > 0 ? toolChoice : void 0,
990
1087
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
991
- ...buildOpenAITokenParams(
1088
+ ...buildOpenAIParameters(
992
1089
  modelIdForPayload,
993
1090
  request.config?.maxTokens ?? this.config.maxTokens,
994
- request.config?.temperature ?? this.config.temperature
1091
+ request.config?.temperature ?? this.config.temperature,
1092
+ this.parameterOptions(request)
995
1093
  ),
996
1094
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
997
1095
  stream: true,
998
1096
  stream_options: { include_usage: true }
999
1097
  };
1000
1098
  logProviderPayload("openai", "request payload", payload, request.debug);
1001
- const stream = await client.chat.completions.create(payload);
1002
- let currentToolCall = null;
1099
+ const stream = await client.chat.completions.create(payload, {
1100
+ signal: request.signal
1101
+ });
1102
+ const toolCalls = /* @__PURE__ */ new Map();
1103
+ let finishReason;
1003
1104
  const collectedCitations = [];
1004
1105
  let citationIndex = 0;
1005
1106
  let usage;
1006
1107
  for await (const chunk of stream) {
1007
1108
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
1008
- if (request.signal?.aborted) {
1009
- break;
1010
- }
1109
+ throwIfAborted(request.signal);
1011
1110
  const delta = chunk.choices[0]?.delta;
1012
1111
  const choice = chunk.choices[0];
1013
1112
  if (delta?.content) {
@@ -1030,38 +1129,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1030
1129
  }
1031
1130
  }
1032
1131
  }
1033
- if (delta?.tool_calls) {
1034
- for (const toolCall of delta.tool_calls) {
1035
- if (toolCall.id) {
1036
- if (currentToolCall) {
1037
- yield {
1038
- type: "action:args",
1039
- id: currentToolCall.id,
1040
- args: currentToolCall.arguments
1041
- };
1042
- yield {
1043
- type: "action:end",
1044
- id: currentToolCall.id,
1045
- name: currentToolCall.name
1046
- };
1047
- }
1048
- const tcExtraContent = toolCall.extra_content;
1049
- currentToolCall = {
1050
- id: toolCall.id,
1051
- name: toolCall.function?.name || "",
1052
- arguments: toolCall.function?.arguments || "",
1053
- ...tcExtraContent ? { extra_content: tcExtraContent } : {}
1054
- };
1055
- yield {
1056
- type: "action:start",
1057
- id: currentToolCall.id,
1058
- name: currentToolCall.name,
1059
- ...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
1060
- };
1061
- } else if (currentToolCall && toolCall.function?.arguments) {
1062
- currentToolCall.arguments += toolCall.function.arguments;
1063
- }
1064
- }
1132
+ for (const part of delta?.tool_calls ?? []) {
1133
+ const index = part.index ?? 0;
1134
+ const call = toolCalls.get(index) ?? {
1135
+ id: "",
1136
+ name: "",
1137
+ arguments: ""
1138
+ };
1139
+ if (part.id) call.id = part.id;
1140
+ if (part.function?.name) call.name += part.function.name;
1141
+ if (part.function?.arguments)
1142
+ call.arguments += part.function.arguments;
1143
+ if (part.extra_content) call.extra_content = part.extra_content;
1144
+ toolCalls.set(index, call);
1065
1145
  }
1066
1146
  if (chunk.usage) {
1067
1147
  usage = {
@@ -1070,21 +1150,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
1070
1150
  total_tokens: chunk.usage.total_tokens
1071
1151
  };
1072
1152
  }
1073
- if (choice?.finish_reason) {
1074
- if (currentToolCall) {
1075
- yield {
1076
- type: "action:args",
1077
- id: currentToolCall.id,
1078
- args: currentToolCall.arguments
1079
- };
1080
- yield {
1081
- type: "action:end",
1082
- id: currentToolCall.id,
1083
- name: currentToolCall.name
1084
- };
1085
- currentToolCall = null;
1086
- }
1087
- }
1153
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
1154
+ }
1155
+ throwIfAborted(request.signal);
1156
+ if (!finishReason)
1157
+ throw new Error("OpenAI stream ended without a finish reason");
1158
+ if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
1159
+ throw new Error("OpenAI stream ended with incomplete tool calls");
1160
+ }
1161
+ for (const call of toolCalls.values()) {
1162
+ if (!call.id || !call.name)
1163
+ throw new Error("OpenAI stream contains an incomplete tool call");
1164
+ JSON.parse(call.arguments || "{}");
1165
+ }
1166
+ for (const call of toolCalls.values()) {
1167
+ yield {
1168
+ type: "action:start",
1169
+ id: call.id,
1170
+ name: call.name,
1171
+ ...call.extra_content ? { extra_content: call.extra_content } : {}
1172
+ };
1173
+ yield { type: "action:args", id: call.id, args: call.arguments };
1174
+ yield { type: "action:end", id: call.id, name: call.name };
1088
1175
  }
1089
1176
  if (collectedCitations.length > 0) {
1090
1177
  const uniqueCitations = deduplicateCitations(collectedCitations);
@@ -1093,26 +1180,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
1093
1180
  yield { type: "message:end" };
1094
1181
  yield { type: "done", usage };
1095
1182
  } catch (error) {
1096
- yield {
1097
- type: "error",
1098
- message: error instanceof Error ? error.message : "Unknown error",
1099
- code: `${this.provider.toUpperCase()}_ERROR`
1100
- };
1183
+ yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
1101
1184
  }
1102
1185
  }
1103
1186
  async complete(request) {
1187
+ throwIfAborted(request.signal);
1104
1188
  if (this.shouldUseResponsesApi(request)) {
1105
1189
  return this.completeWithResponses(request);
1106
1190
  }
1107
1191
  const client = await this.getClient();
1108
1192
  let messages;
1109
1193
  if (request.rawMessages && request.rawMessages.length > 0) {
1110
- const sanitized = request.rawMessages.map((msg) => {
1111
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
1112
- return { ...msg, content: null };
1113
- }
1114
- return msg;
1115
- });
1194
+ const sanitized = this.formatRawMessages(request.rawMessages);
1116
1195
  if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
1117
1196
  messages = [
1118
1197
  { role: "system", content: request.systemPrompt },
@@ -1127,7 +1206,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
1127
1206
  request.systemPrompt
1128
1207
  );
1129
1208
  }
1130
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1209
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1210
+ type: "function",
1211
+ function: {
1212
+ name: tool.name,
1213
+ description: tool.description,
1214
+ parameters: normalizeObjectJsonSchema(
1215
+ tool.inputSchema
1216
+ )
1217
+ }
1218
+ })) : formatTools(request.actions ?? []);
1131
1219
  const openaiToolOptions = request.providerToolOptions?.openai;
1132
1220
  const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
1133
1221
  type: "function",
@@ -1142,16 +1230,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1142
1230
  tools: tools.length > 0 ? tools : void 0,
1143
1231
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1144
1232
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1145
- ...buildOpenAITokenParams(
1233
+ ...buildOpenAIParameters(
1146
1234
  modelIdForCompletePayload,
1147
1235
  request.config?.maxTokens ?? this.config.maxTokens,
1148
- request.config?.temperature ?? this.config.temperature
1236
+ request.config?.temperature ?? this.config.temperature,
1237
+ this.parameterOptions(request)
1149
1238
  ),
1150
1239
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1151
1240
  stream: false
1152
1241
  };
1153
1242
  logProviderPayload("openai", "request payload", payload, request.debug);
1154
- const response = await client.chat.completions.create(payload);
1243
+ const response = await client.chat.completions.create(payload, {
1244
+ signal: request.signal
1245
+ });
1155
1246
  logProviderPayload("openai", "response payload", response, request.debug);
1156
1247
  const choice = response.choices?.[0];
1157
1248
  const message = choice?.message;
@@ -1,8 +1,8 @@
1
- import { c as OllamaProviderConfig, A as AIProvider } from '../../types-BSSiJW2o.mjs';
2
- export { d as OllamaModelOptions } from '../../types-BSSiJW2o.mjs';
3
- import '../../types-BkQCSiIt.mjs';
1
+ import { c as OllamaProviderConfig, A as AIProvider } from '../../types-NOswlhm9.mjs';
2
+ export { d as OllamaModelOptions } from '../../types-NOswlhm9.mjs';
3
+ import '../../types-BW3csYo5.mjs';
4
4
  import 'zod';
5
- import '../../base-tNgbBaSo.mjs';
5
+ import '../../base-CkeT7u-O.mjs';
6
6
 
7
7
  /**
8
8
  * Ollama Provider
@@ -1,8 +1,8 @@
1
- import { c as OllamaProviderConfig, A as AIProvider } from '../../types-BQ31QIsA.js';
2
- export { d as OllamaModelOptions } from '../../types-BQ31QIsA.js';
3
- import '../../types-BkQCSiIt.js';
1
+ import { c as OllamaProviderConfig, A as AIProvider } from '../../types-DA54bSmX.js';
2
+ export { d as OllamaModelOptions } from '../../types-DA54bSmX.js';
3
+ import '../../types-BW3csYo5.js';
4
4
  import 'zod';
5
- import '../../base-C58Dsr9p.js';
5
+ import '../../base-BdTpUAWI.js';
6
6
 
7
7
  /**
8
8
  * Ollama Provider