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