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