@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(
@@ -117,16 +168,6 @@ function normalizeObjectJsonSchema(schema) {
117
168
  }
118
169
  return normalized;
119
170
  }
120
- function isOpenAIReasoningModel(modelId) {
121
- if (!modelId) return false;
122
- return /^(o1|o3|o4|gpt-5)/i.test(modelId);
123
- }
124
- function buildOpenAITokenParams(modelId, maxTokens, temperature) {
125
- if (isOpenAIReasoningModel(modelId)) {
126
- return { max_completion_tokens: maxTokens };
127
- }
128
- return { max_tokens: maxTokens, temperature };
129
- }
130
171
  function stripSchemaKeys(schema, keysToDrop, options = {}) {
131
172
  if (Array.isArray(schema)) {
132
173
  return schema.map((item) => stripSchemaKeys(item, keysToDrop, options));
@@ -473,6 +514,28 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
473
514
  return formatted;
474
515
  }
475
516
 
517
+ // src/core/provider-error.ts
518
+ function providerErrorEvent(error, code) {
519
+ const details = error ?? {};
520
+ const event = {
521
+ type: "error",
522
+ message: error instanceof Error ? error.message : String(error),
523
+ code,
524
+ ...typeof details.status === "number" ? { status: details.status } : {},
525
+ ...typeof details.code === "string" ? { providerCode: details.code } : {},
526
+ ...typeof details.param === "string" ? { param: details.param } : {},
527
+ ...typeof details.request_id === "string" ? { requestId: details.request_id } : {}
528
+ };
529
+ Object.defineProperty(event, "cause", { value: error, enumerable: false });
530
+ return event;
531
+ }
532
+ function throwIfAborted(signal) {
533
+ if (!signal?.aborted) return;
534
+ const error = new Error("The operation was aborted");
535
+ error.name = "AbortError";
536
+ throw error;
537
+ }
538
+
476
539
  // src/core/utils.ts
477
540
  function generateId(prefix = "id") {
478
541
  return `${prefix}_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
@@ -504,39 +567,38 @@ var OpenAIAdapter = class _OpenAIAdapter {
504
567
  const { default: OpenAI } = await import('openai');
505
568
  this.client = new OpenAI({
506
569
  apiKey: this.config.apiKey,
507
- baseURL: this.config.baseUrl
570
+ baseURL: this.config.baseUrl,
571
+ organization: this.config.organization,
572
+ defaultHeaders: this.config.headers
508
573
  });
509
574
  }
510
575
  return this.client;
511
576
  }
577
+ parameterOptions(request) {
578
+ return {
579
+ ...this.config,
580
+ reasoningEffort: request.config?.reasoningEffort ?? this.config.reasoningEffort
581
+ };
582
+ }
583
+ toolDefinitions(request) {
584
+ if (request.toolDefinitions?.length) return request.toolDefinitions;
585
+ return formatTools(request.actions ?? []).map((tool) => ({
586
+ name: tool.function.name,
587
+ description: tool.function.description ?? "",
588
+ location: "server",
589
+ inputSchema: tool.function.parameters
590
+ }));
591
+ }
512
592
  shouldUseResponsesApi(request) {
513
- const hasTools = Array.isArray(request.toolDefinitions) && request.toolDefinitions.length > 0;
514
- if (!hasTools) return false;
515
- if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false) {
593
+ if (this.toolDefinitions(request).length === 0) return false;
594
+ if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
516
595
  return true;
517
- }
518
- return this.requiresResponsesApiForTools(
519
- request.config?.model || this.model
596
+ return requiresOpenAIResponses(
597
+ request.config?.model || this.model,
598
+ this.config.baseUrl,
599
+ this.parameterOptions(request)
520
600
  );
521
601
  }
522
- /**
523
- * Whether this model rejects function tools on /v1/chat/completions.
524
- *
525
- * Applies to OpenAI proper only — the adapter is reused for OpenAI-compatible
526
- * providers (Azure, xAI, Google, Fireworks) whose endpoints have no such
527
- * restriction and may not implement /v1/responses at all.
528
- */
529
- requiresResponsesApiForTools(modelId) {
530
- if (!modelId) return false;
531
- if (!/^gpt-5\.(?:[4-9]|\d{2,})/i.test(modelId)) return false;
532
- const baseUrl = this.config.baseUrl;
533
- if (!baseUrl) return true;
534
- try {
535
- return new URL(baseUrl).hostname === "api.openai.com";
536
- } catch {
537
- return false;
538
- }
539
- }
540
602
  /**
541
603
  * Convert one message's content to Responses content parts.
542
604
  *
@@ -567,7 +629,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
567
629
  });
568
630
  }
569
631
  buildResponsesInput(request) {
570
- const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? request.rawMessages : formatMessagesForOpenAI(request.messages, void 0);
632
+ const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
571
633
  const input = [];
572
634
  for (const message of sourceMessages) {
573
635
  if (message.role === "system") {
@@ -617,6 +679,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
617
679
  }
618
680
  return input;
619
681
  }
682
+ /** Preserve Copilot screenshot attachments on every OpenAI transport. */
683
+ formatRawMessages(messages) {
684
+ return messages.map((message) => {
685
+ const { attachments, ...rest } = message;
686
+ let content = message.content;
687
+ if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
688
+ content = null;
689
+ }
690
+ if (Array.isArray(attachments) && attachments.length > 0) {
691
+ const images = attachments.filter((attachment) => attachment && typeof attachment === "object").map(
692
+ (attachment) => attachmentToOpenAIImage(attachment)
693
+ ).filter((image) => image !== null);
694
+ if (images.length > 0) {
695
+ const parts = Array.isArray(content) ? content : content ? [{ type: "text", text: content }] : [];
696
+ content = [...parts, ...images];
697
+ }
698
+ }
699
+ return { ...rest, content };
700
+ });
701
+ }
620
702
  /**
621
703
  * Build the web_search tool for the Responses API, or undefined when web
622
704
  * search is off.
@@ -698,13 +780,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
698
780
  const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => ({
699
781
  id: item.call_id ?? item.id ?? generateToolCallId(),
700
782
  name: item.name,
701
- args: (() => {
702
- try {
703
- return JSON.parse(item.arguments ?? "{}");
704
- } catch {
705
- return {};
706
- }
707
- })()
783
+ args: JSON.parse(item.arguments ?? "{}")
708
784
  })) : [];
709
785
  return {
710
786
  content,
@@ -728,18 +804,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
728
804
  instructions: request.systemPrompt,
729
805
  input: this.buildResponsesInput(request),
730
806
  tools: this.buildResponsesTools(
731
- request.toolDefinitions ?? [],
807
+ this.toolDefinitions(request),
732
808
  request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true,
733
809
  this.buildResponsesWebSearchTool(request)
734
810
  ),
735
- tool_choice: openaiToolOptions?.toolChoice === "required" ? "required" : openaiToolOptions?.toolChoice === "auto" ? "auto" : void 0,
811
+ tool_choice: openaiToolOptions?.toolChoice,
736
812
  parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
737
- // Reasoning models reject `temperature` outright — sending it would swap one
738
- // 400 for another. isOpenAIReasoningModel already encodes that family test.
739
- ...isOpenAIReasoningModel(modelIdForPayload) ? {} : {
740
- temperature: request.config?.temperature ?? this.config.temperature
741
- },
742
- max_output_tokens: request.config?.maxTokens ?? this.config.maxTokens,
813
+ ...buildOpenAIParameters(
814
+ modelIdForPayload,
815
+ request.config?.maxTokens ?? this.config.maxTokens,
816
+ request.config?.temperature ?? this.config.temperature,
817
+ this.parameterOptions(request),
818
+ "responses"
819
+ ),
743
820
  ...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
744
821
  stream
745
822
  };
@@ -747,10 +824,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
747
824
  }
748
825
  async completeWithResponses(request) {
749
826
  const client = await this.getClient();
827
+ throwIfAborted(request.signal);
750
828
  const payload = this.buildResponsesPayload(request, false);
751
829
  logProviderPayload("openai", "request payload", payload, request.debug);
752
- const response = await client.responses.create(payload);
830
+ if (!client.responses?.create)
831
+ throw new Error(
832
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
833
+ );
834
+ const response = await client.responses.create(payload, {
835
+ signal: request.signal
836
+ });
837
+ throwIfAborted(request.signal);
753
838
  logProviderPayload("openai", "response payload", response, request.debug);
839
+ if (response.status && response.status !== "completed") {
840
+ throw Object.assign(
841
+ new Error(
842
+ response.error?.message ?? `Responses request ${response.status}`
843
+ ),
844
+ response.error
845
+ );
846
+ }
754
847
  return this.parseResponsesResult(response);
755
848
  }
756
849
  /**
@@ -768,13 +861,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
768
861
  */
769
862
  async *streamWithResponses(request) {
770
863
  const client = await this.getClient();
864
+ throwIfAborted(request.signal);
771
865
  const payload = this.buildResponsesPayload(request, true);
772
866
  logProviderPayload("openai", "request payload", payload, request.debug);
773
- const stream = await client.responses.create(payload);
867
+ if (!client.responses?.create)
868
+ throw new Error(
869
+ "This OpenAI client does not support Responses; install an openai version with Responses support."
870
+ );
871
+ const stream = await client.responses.create(payload, {
872
+ signal: request.signal
873
+ });
774
874
  const toolCalls = /* @__PURE__ */ new Map();
775
875
  let usage;
776
876
  const citations = [];
877
+ let completed = false;
777
878
  function* flushToolCalls() {
879
+ for (const call of toolCalls.values()) {
880
+ if (!call.name)
881
+ throw new Error("Responses tool call is missing its name");
882
+ JSON.parse(call.arguments || "{}");
883
+ }
778
884
  for (const call of toolCalls.values()) {
779
885
  yield { type: "action:start", id: call.id, name: call.name };
780
886
  yield { type: "action:args", id: call.id, args: call.arguments };
@@ -783,7 +889,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
783
889
  toolCalls.clear();
784
890
  }
785
891
  for await (const event of stream) {
786
- if (request.signal?.aborted) break;
892
+ throwIfAborted(request.signal);
787
893
  logProviderPayload("openai", "stream chunk", event, request.debug);
788
894
  const index = event?.output_index ?? 0;
789
895
  switch (event?.type) {
@@ -813,8 +919,8 @@ var OpenAIAdapter = class _OpenAIAdapter {
813
919
  }
814
920
  break;
815
921
  }
816
- case "response.completed":
817
- case "response.incomplete": {
922
+ case "response.completed": {
923
+ completed = true;
818
924
  const found = this.collectResponsesCitations(
819
925
  event.response?.output,
820
926
  citations.length
@@ -830,13 +936,27 @@ var OpenAIAdapter = class _OpenAIAdapter {
830
936
  }
831
937
  break;
832
938
  }
833
- case "error":
834
- case "response.failed":
939
+ case "response.incomplete":
835
940
  throw new Error(
836
- event.message ?? event.response?.error?.message ?? "Responses stream failed"
941
+ `Responses stream incomplete: ${event.response?.incomplete_details?.reason ?? "unknown reason"}`
942
+ );
943
+ case "error":
944
+ case "response.failed": {
945
+ const details = event.response?.error ?? event;
946
+ throw Object.assign(
947
+ new Error(details.message ?? "Responses stream failed"),
948
+ {
949
+ code: details.code,
950
+ param: details.param,
951
+ status: details.status
952
+ }
837
953
  );
954
+ }
838
955
  }
839
956
  }
957
+ throwIfAborted(request.signal);
958
+ if (!completed)
959
+ throw new Error("Responses stream ended without a completed response");
840
960
  yield* flushToolCalls();
841
961
  if (citations.length > 0) {
842
962
  yield { type: "citation", citations: deduplicateCitations(citations) };
@@ -845,6 +965,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
845
965
  yield { type: "done", usage };
846
966
  }
847
967
  async *stream(request) {
968
+ throwIfAborted(request.signal);
848
969
  if (this.shouldUseResponsesApi(request)) {
849
970
  const messageId2 = generateMessageId();
850
971
  yield { type: "message:start", id: messageId2 };
@@ -852,47 +973,14 @@ var OpenAIAdapter = class _OpenAIAdapter {
852
973
  yield* this.streamWithResponses(request);
853
974
  return;
854
975
  } catch (error) {
855
- yield {
856
- type: "error",
857
- message: error instanceof Error ? error.message : "Unknown error",
858
- code: "OPENAI_RESPONSES_ERROR"
859
- };
976
+ yield providerErrorEvent(error, "OPENAI_RESPONSES_ERROR");
860
977
  return;
861
978
  }
862
979
  }
863
980
  const client = await this.getClient();
864
981
  let messages;
865
982
  if (request.rawMessages && request.rawMessages.length > 0) {
866
- const processedMessages = request.rawMessages.map((msg) => {
867
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
868
- return { ...msg, content: null };
869
- }
870
- const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
871
- if (hasAttachments) {
872
- const content = [];
873
- if (msg.content) {
874
- content.push({ type: "text", text: msg.content });
875
- }
876
- for (const attachment of msg.attachments) {
877
- if (attachment.type === "image") {
878
- let imageUrl;
879
- if (attachment.url) {
880
- imageUrl = attachment.url;
881
- } else if (attachment.data) {
882
- imageUrl = attachment.data.startsWith("data:") ? attachment.data : `data:${attachment.mimeType || "image/png"};base64,${attachment.data}`;
883
- } else {
884
- continue;
885
- }
886
- content.push({
887
- type: "image_url",
888
- image_url: { url: imageUrl, detail: "auto" }
889
- });
890
- }
891
- }
892
- return { ...msg, content, attachments: void 0 };
893
- }
894
- return msg;
895
- });
983
+ const processedMessages = this.formatRawMessages(request.rawMessages);
896
984
  if (request.systemPrompt) {
897
985
  const hasSystem = processedMessages.some((m) => m.role === "system");
898
986
  if (!hasSystem) {
@@ -912,7 +1000,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
912
1000
  request.systemPrompt
913
1001
  );
914
1002
  }
915
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1003
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1004
+ type: "function",
1005
+ function: {
1006
+ name: tool.name,
1007
+ description: tool.description,
1008
+ parameters: normalizeObjectJsonSchema(
1009
+ tool.inputSchema
1010
+ )
1011
+ }
1012
+ })) : formatTools(request.actions ?? []);
916
1013
  const webSearchConfig = request.webSearch ?? this.config.webSearch;
917
1014
  if (webSearchConfig) {
918
1015
  const webSearchTool = {
@@ -941,26 +1038,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
941
1038
  tools: tools.length > 0 ? tools : void 0,
942
1039
  tool_choice: tools.length > 0 ? toolChoice : void 0,
943
1040
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
944
- ...buildOpenAITokenParams(
1041
+ ...buildOpenAIParameters(
945
1042
  modelIdForPayload,
946
1043
  request.config?.maxTokens ?? this.config.maxTokens,
947
- request.config?.temperature ?? this.config.temperature
1044
+ request.config?.temperature ?? this.config.temperature,
1045
+ this.parameterOptions(request)
948
1046
  ),
949
1047
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
950
1048
  stream: true,
951
1049
  stream_options: { include_usage: true }
952
1050
  };
953
1051
  logProviderPayload("openai", "request payload", payload, request.debug);
954
- const stream = await client.chat.completions.create(payload);
955
- let currentToolCall = null;
1052
+ const stream = await client.chat.completions.create(payload, {
1053
+ signal: request.signal
1054
+ });
1055
+ const toolCalls = /* @__PURE__ */ new Map();
1056
+ let finishReason;
956
1057
  const collectedCitations = [];
957
1058
  let citationIndex = 0;
958
1059
  let usage;
959
1060
  for await (const chunk of stream) {
960
1061
  logProviderPayload("openai", "stream chunk", chunk, request.debug);
961
- if (request.signal?.aborted) {
962
- break;
963
- }
1062
+ throwIfAborted(request.signal);
964
1063
  const delta = chunk.choices[0]?.delta;
965
1064
  const choice = chunk.choices[0];
966
1065
  if (delta?.content) {
@@ -983,38 +1082,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
983
1082
  }
984
1083
  }
985
1084
  }
986
- if (delta?.tool_calls) {
987
- for (const toolCall of delta.tool_calls) {
988
- if (toolCall.id) {
989
- if (currentToolCall) {
990
- yield {
991
- type: "action:args",
992
- id: currentToolCall.id,
993
- args: currentToolCall.arguments
994
- };
995
- yield {
996
- type: "action:end",
997
- id: currentToolCall.id,
998
- name: currentToolCall.name
999
- };
1000
- }
1001
- const tcExtraContent = toolCall.extra_content;
1002
- currentToolCall = {
1003
- id: toolCall.id,
1004
- name: toolCall.function?.name || "",
1005
- arguments: toolCall.function?.arguments || "",
1006
- ...tcExtraContent ? { extra_content: tcExtraContent } : {}
1007
- };
1008
- yield {
1009
- type: "action:start",
1010
- id: currentToolCall.id,
1011
- name: currentToolCall.name,
1012
- ...currentToolCall.extra_content ? { extra_content: currentToolCall.extra_content } : {}
1013
- };
1014
- } else if (currentToolCall && toolCall.function?.arguments) {
1015
- currentToolCall.arguments += toolCall.function.arguments;
1016
- }
1017
- }
1085
+ for (const part of delta?.tool_calls ?? []) {
1086
+ const index = part.index ?? 0;
1087
+ const call = toolCalls.get(index) ?? {
1088
+ id: "",
1089
+ name: "",
1090
+ arguments: ""
1091
+ };
1092
+ if (part.id) call.id = part.id;
1093
+ if (part.function?.name) call.name += part.function.name;
1094
+ if (part.function?.arguments)
1095
+ call.arguments += part.function.arguments;
1096
+ if (part.extra_content) call.extra_content = part.extra_content;
1097
+ toolCalls.set(index, call);
1018
1098
  }
1019
1099
  if (chunk.usage) {
1020
1100
  usage = {
@@ -1023,21 +1103,28 @@ var OpenAIAdapter = class _OpenAIAdapter {
1023
1103
  total_tokens: chunk.usage.total_tokens
1024
1104
  };
1025
1105
  }
1026
- if (choice?.finish_reason) {
1027
- if (currentToolCall) {
1028
- yield {
1029
- type: "action:args",
1030
- id: currentToolCall.id,
1031
- args: currentToolCall.arguments
1032
- };
1033
- yield {
1034
- type: "action:end",
1035
- id: currentToolCall.id,
1036
- name: currentToolCall.name
1037
- };
1038
- currentToolCall = null;
1039
- }
1040
- }
1106
+ if (choice?.finish_reason) finishReason = choice.finish_reason;
1107
+ }
1108
+ throwIfAborted(request.signal);
1109
+ if (!finishReason)
1110
+ throw new Error("OpenAI stream ended without a finish reason");
1111
+ if (toolCalls.size && !["tool_calls", "function_call"].includes(finishReason)) {
1112
+ throw new Error("OpenAI stream ended with incomplete tool calls");
1113
+ }
1114
+ for (const call of toolCalls.values()) {
1115
+ if (!call.id || !call.name)
1116
+ throw new Error("OpenAI stream contains an incomplete tool call");
1117
+ JSON.parse(call.arguments || "{}");
1118
+ }
1119
+ for (const call of toolCalls.values()) {
1120
+ yield {
1121
+ type: "action:start",
1122
+ id: call.id,
1123
+ name: call.name,
1124
+ ...call.extra_content ? { extra_content: call.extra_content } : {}
1125
+ };
1126
+ yield { type: "action:args", id: call.id, args: call.arguments };
1127
+ yield { type: "action:end", id: call.id, name: call.name };
1041
1128
  }
1042
1129
  if (collectedCitations.length > 0) {
1043
1130
  const uniqueCitations = deduplicateCitations(collectedCitations);
@@ -1046,26 +1133,18 @@ var OpenAIAdapter = class _OpenAIAdapter {
1046
1133
  yield { type: "message:end" };
1047
1134
  yield { type: "done", usage };
1048
1135
  } catch (error) {
1049
- yield {
1050
- type: "error",
1051
- message: error instanceof Error ? error.message : "Unknown error",
1052
- code: `${this.provider.toUpperCase()}_ERROR`
1053
- };
1136
+ yield providerErrorEvent(error, `${this.provider.toUpperCase()}_ERROR`);
1054
1137
  }
1055
1138
  }
1056
1139
  async complete(request) {
1140
+ throwIfAborted(request.signal);
1057
1141
  if (this.shouldUseResponsesApi(request)) {
1058
1142
  return this.completeWithResponses(request);
1059
1143
  }
1060
1144
  const client = await this.getClient();
1061
1145
  let messages;
1062
1146
  if (request.rawMessages && request.rawMessages.length > 0) {
1063
- const sanitized = request.rawMessages.map((msg) => {
1064
- if (msg.role === "assistant" && Array.isArray(msg.tool_calls) && msg.tool_calls.length > 0 && msg.content === "") {
1065
- return { ...msg, content: null };
1066
- }
1067
- return msg;
1068
- });
1147
+ const sanitized = this.formatRawMessages(request.rawMessages);
1069
1148
  if (request.systemPrompt && !sanitized.some((message2) => message2.role === "system")) {
1070
1149
  messages = [
1071
1150
  { role: "system", content: request.systemPrompt },
@@ -1080,7 +1159,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
1080
1159
  request.systemPrompt
1081
1160
  );
1082
1161
  }
1083
- const tools = request.actions?.length ? formatTools(request.actions) : [];
1162
+ const tools = request.toolDefinitions?.length ? request.toolDefinitions.filter((tool) => tool.available !== false).map((tool) => ({
1163
+ type: "function",
1164
+ function: {
1165
+ name: tool.name,
1166
+ description: tool.description,
1167
+ parameters: normalizeObjectJsonSchema(
1168
+ tool.inputSchema
1169
+ )
1170
+ }
1171
+ })) : formatTools(request.actions ?? []);
1084
1172
  const openaiToolOptions = request.providerToolOptions?.openai;
1085
1173
  const toolChoice = openaiToolOptions?.toolChoice && typeof openaiToolOptions.toolChoice === "object" ? {
1086
1174
  type: "function",
@@ -1095,16 +1183,19 @@ var OpenAIAdapter = class _OpenAIAdapter {
1095
1183
  tools: tools.length > 0 ? tools : void 0,
1096
1184
  tool_choice: tools.length > 0 ? toolChoice : void 0,
1097
1185
  parallel_tool_calls: tools.length > 0 ? openaiToolOptions?.parallelToolCalls : void 0,
1098
- ...buildOpenAITokenParams(
1186
+ ...buildOpenAIParameters(
1099
1187
  modelIdForCompletePayload,
1100
1188
  request.config?.maxTokens ?? this.config.maxTokens,
1101
- request.config?.temperature ?? this.config.temperature
1189
+ request.config?.temperature ?? this.config.temperature,
1190
+ this.parameterOptions(request)
1102
1191
  ),
1103
1192
  response_format: toOpenAIResponseFormat(request.config?.responseFormat),
1104
1193
  stream: false
1105
1194
  };
1106
1195
  logProviderPayload("openai", "request payload", payload, request.debug);
1107
- const response = await client.chat.completions.create(payload);
1196
+ const response = await client.chat.completions.create(payload, {
1197
+ signal: request.signal
1198
+ });
1108
1199
  logProviderPayload("openai", "response payload", response, request.debug);
1109
1200
  const choice = response.choices?.[0];
1110
1201
  const message = choice?.message;
@@ -1,10 +1,11 @@
1
- import { M as Message, A as ActionDefinition, d as ToolDefinition, R as ResponseFormat, W as WebSearchConfig, P as ProviderToolRuntimeOptions, g as StreamEvent, J as TokenUsage, X as LLMConfig, a6 as MessageAttachment } from './types-BkQCSiIt.js';
1
+ import { M as Message, A as ActionDefinition, d as ToolDefinition, O as OpenAIReasoningEffort, R as ResponseFormat, W as WebSearchConfig, P as ProviderToolRuntimeOptions, g as StreamEvent, J as TokenUsage, Y as LLMConfig, a8 as MessageAttachment } from './types-BW3csYo5.js';
2
2
 
3
3
  /**
4
4
  * Request-level LLM configuration overrides
5
5
  */
6
6
  interface RequestLLMConfig {
7
7
  model?: string;
8
+ reasoningEffort?: OpenAIReasoningEffort;
8
9
  temperature?: number;
9
10
  maxTokens?: number;
10
11
  responseFormat?: ResponseFormat;
@@ -1,10 +1,11 @@
1
- import { M as Message, A as ActionDefinition, d as ToolDefinition, R as ResponseFormat, W as WebSearchConfig, P as ProviderToolRuntimeOptions, g as StreamEvent, J as TokenUsage, X as LLMConfig, a6 as MessageAttachment } from './types-BkQCSiIt.mjs';
1
+ import { M as Message, A as ActionDefinition, d as ToolDefinition, O as OpenAIReasoningEffort, R as ResponseFormat, W as WebSearchConfig, P as ProviderToolRuntimeOptions, g as StreamEvent, J as TokenUsage, Y as LLMConfig, a8 as MessageAttachment } from './types-BW3csYo5.mjs';
2
2
 
3
3
  /**
4
4
  * Request-level LLM configuration overrides
5
5
  */
6
6
  interface RequestLLMConfig {
7
7
  model?: string;
8
+ reasoningEffort?: OpenAIReasoningEffort;
8
9
  temperature?: number;
9
10
  maxTokens?: number;
10
11
  responseFormat?: ResponseFormat;
@@ -1,7 +1,7 @@
1
- import { L as LLMAdapter } from '../base-tNgbBaSo.mjs';
2
- import { F as FallbackChainConfig, c as FallbackFailure, R as RoutingStore } from '../types-B6dhnguR.mjs';
3
- export { d as FallbackInfo, b as RetryBackoff, e as RetryInfo, a as RoutingStrategy } from '../types-B6dhnguR.mjs';
4
- import '../types-BkQCSiIt.mjs';
1
+ import { L as LLMAdapter } from '../base-CkeT7u-O.mjs';
2
+ import { F as FallbackChainConfig, c as FallbackFailure, R as RoutingStore } from '../types-BWRYIvl_.mjs';
3
+ export { d as FallbackInfo, b as RetryBackoff, e as RetryInfo, a as RoutingStrategy } from '../types-BWRYIvl_.mjs';
4
+ import '../types-BW3csYo5.mjs';
5
5
  import 'zod';
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
- import { L as LLMAdapter } from '../base-C58Dsr9p.js';
2
- import { F as FallbackChainConfig, c as FallbackFailure, R as RoutingStore } from '../types-CCxPmkmK.js';
3
- export { d as FallbackInfo, b as RetryBackoff, e as RetryInfo, a as RoutingStrategy } from '../types-CCxPmkmK.js';
4
- import '../types-BkQCSiIt.js';
1
+ import { L as LLMAdapter } from '../base-BdTpUAWI.js';
2
+ import { F as FallbackChainConfig, c as FallbackFailure, R as RoutingStore } from '../types-CpXcT-tY.js';
3
+ export { d as FallbackInfo, b as RetryBackoff, e as RetryInfo, a as RoutingStrategy } from '../types-CpXcT-tY.js';
4
+ import '../types-BW3csYo5.js';
5
5
  import 'zod';
6
6
 
7
7
  /**