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