@yourgpt/llm-sdk 2.6.0-beta.1 → 2.6.0-beta.2
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 +112 -0
- package/dist/adapters/index.d.mts +5 -5
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/index.js +372 -39
- package/dist/adapters/index.mjs +372 -39
- package/dist/audio-BBSwnjo8.d.mts +92 -0
- package/dist/audio-BBSwnjo8.d.ts +92 -0
- package/dist/{base-CkeT7u-O.d.mts → base-BICaQaRS.d.mts} +7 -3
- package/dist/{base-BdTpUAWI.d.ts → base-CpRPB8u8.d.ts} +7 -3
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/index.d.mts +17 -35
- package/dist/index.d.ts +17 -35
- package/dist/index.js +229 -60
- package/dist/index.mjs +227 -61
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/anthropic/index.js +123 -7
- package/dist/providers/anthropic/index.mjs +123 -7
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/azure/index.js +101 -4
- package/dist/providers/azure/index.mjs +101 -4
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +321 -31
- package/dist/providers/fireworks/index.mjs +321 -31
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +321 -31
- package/dist/providers/google/index.mjs +321 -31
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/ollama/index.js +87 -2
- package/dist/providers/ollama/index.mjs +87 -2
- package/dist/providers/openai/index.d.mts +25 -6
- package/dist/providers/openai/index.d.ts +25 -6
- package/dist/providers/openai/index.js +750 -40
- package/dist/providers/openai/index.mjs +749 -41
- package/dist/providers/openrouter/index.d.mts +3 -3
- package/dist/providers/openrouter/index.d.ts +3 -3
- package/dist/providers/openrouter/index.js +321 -31
- package/dist/providers/openrouter/index.mjs +321 -31
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +321 -31
- package/dist/providers/togetherai/index.mjs +321 -31
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +321 -31
- package/dist/providers/xai/index.mjs +321 -31
- package/dist/{types-BWRYIvl_.d.mts → types-C3RgRbEC.d.mts} +1 -1
- package/dist/{types-CpXcT-tY.d.ts → types-DCFqkJAy.d.ts} +1 -1
- package/dist/{types-NOswlhm9.d.mts → types-DHQEMFHA.d.mts} +3 -3
- package/dist/{types-BW3csYo5.d.mts → types-Dg1Bcg1k.d.mts} +106 -3
- package/dist/{types-BW3csYo5.d.ts → types-Dg1Bcg1k.d.ts} +106 -3
- package/dist/{types-DA54bSmX.d.ts → types-Dikj3En4.d.ts} +3 -3
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/docs/multimodal-and-audio.md +170 -0
- package/package.json +3 -2
|
@@ -1,5 +1,108 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
// src/core/tool-output.ts
|
|
4
|
+
var imageTypes = /* @__PURE__ */ new Set([
|
|
5
|
+
"image/png",
|
|
6
|
+
"image/jpeg",
|
|
7
|
+
"image/webp",
|
|
8
|
+
"image/gif"
|
|
9
|
+
]);
|
|
10
|
+
function normalizeToolOutput(value) {
|
|
11
|
+
const output = value;
|
|
12
|
+
if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
|
|
13
|
+
throw new Error("Tool model output must contain a nonempty content array");
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
type: "content",
|
|
17
|
+
content: output.content.map((part) => {
|
|
18
|
+
if (part?.type === "text" && typeof part.text === "string")
|
|
19
|
+
return { type: "text", text: part.text };
|
|
20
|
+
if (part?.type !== "image")
|
|
21
|
+
throw new Error("Unsupported tool output content type");
|
|
22
|
+
const sources = ["data", "url", "fileId"].filter((key) => key in part);
|
|
23
|
+
if (sources.length !== 1)
|
|
24
|
+
throw new Error(
|
|
25
|
+
"Tool image requires exactly one of data, url, or fileId"
|
|
26
|
+
);
|
|
27
|
+
if ("fileId" in part) {
|
|
28
|
+
if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
|
|
29
|
+
throw new Error(
|
|
30
|
+
"Tool image file references must name the openai provider and fileId"
|
|
31
|
+
);
|
|
32
|
+
return { type: "image", fileId: part.fileId, provider: "openai" };
|
|
33
|
+
}
|
|
34
|
+
if ("url" in part) {
|
|
35
|
+
let url;
|
|
36
|
+
try {
|
|
37
|
+
url = new URL(part.url);
|
|
38
|
+
} catch {
|
|
39
|
+
throw new Error("Invalid tool image URL");
|
|
40
|
+
}
|
|
41
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
|
|
42
|
+
throw new Error(
|
|
43
|
+
"Tool image URL must use HTTP(S) without credentials"
|
|
44
|
+
);
|
|
45
|
+
return { type: "image", url: url.href };
|
|
46
|
+
}
|
|
47
|
+
if (!("data" in part) || !imageTypes.has(part.mediaType))
|
|
48
|
+
throw new Error("Unsupported tool image media type");
|
|
49
|
+
let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
|
|
50
|
+
if (typeof data !== "string")
|
|
51
|
+
throw new Error("Tool image data must be base64 or bytes");
|
|
52
|
+
if (data.startsWith("data:")) {
|
|
53
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
|
|
54
|
+
if (!match || match[1] !== part.mediaType)
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Tool image data URL media type does not match mediaType"
|
|
57
|
+
);
|
|
58
|
+
data = match[2];
|
|
59
|
+
}
|
|
60
|
+
if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
|
|
61
|
+
throw new Error("Invalid tool image base64 data");
|
|
62
|
+
if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
|
|
63
|
+
throw new Error("Tool image exceeds 20 MiB");
|
|
64
|
+
if (Buffer.from(data, "base64").toString("base64") !== data)
|
|
65
|
+
throw new Error("Invalid tool image base64 data");
|
|
66
|
+
return { type: "image", data, mediaType: part.mediaType };
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function toolOutputForProvider(value, provider) {
|
|
71
|
+
const output = normalizeToolOutput(value);
|
|
72
|
+
return output.content.map((part) => {
|
|
73
|
+
if (part.type === "text")
|
|
74
|
+
return {
|
|
75
|
+
type: provider === "responses" ? "input_text" : "text",
|
|
76
|
+
text: part.text
|
|
77
|
+
};
|
|
78
|
+
if (provider === "unsupported")
|
|
79
|
+
throw new Error(
|
|
80
|
+
"Image tool results require OpenAI Responses or Anthropic; this endpoint is not supported"
|
|
81
|
+
);
|
|
82
|
+
if ("fileId" in part) {
|
|
83
|
+
if (provider !== "responses")
|
|
84
|
+
throw new Error(
|
|
85
|
+
"OpenAI image file references cannot be sent to another provider"
|
|
86
|
+
);
|
|
87
|
+
return { type: "input_image", file_id: part.fileId, detail: "auto" };
|
|
88
|
+
}
|
|
89
|
+
if (provider === "responses")
|
|
90
|
+
return {
|
|
91
|
+
type: "input_image",
|
|
92
|
+
image_url: "url" in part ? part.url : `data:${part.mediaType};base64,${part.data}`,
|
|
93
|
+
detail: "auto"
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
type: "image",
|
|
97
|
+
source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
|
|
98
|
+
};
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function textToolOutput(value, fallback) {
|
|
102
|
+
if (value === void 0) return fallback;
|
|
103
|
+
return toolOutputForProvider(value, "unsupported").map((part) => part.text).join("\n");
|
|
104
|
+
}
|
|
105
|
+
|
|
3
106
|
// src/core/openai-parameters.ts
|
|
4
107
|
function capabilities(model) {
|
|
5
108
|
const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
|
|
@@ -241,7 +344,7 @@ function messageToOpenAIContent(message) {
|
|
|
241
344
|
}
|
|
242
345
|
return blocks;
|
|
243
346
|
}
|
|
244
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
347
|
+
function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
|
|
245
348
|
const formatted = [];
|
|
246
349
|
if (systemPrompt) {
|
|
247
350
|
formatted.push({ role: "system", content: systemPrompt });
|
|
@@ -259,7 +362,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
259
362
|
const assistantMsg = {
|
|
260
363
|
role: "assistant",
|
|
261
364
|
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
262
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
365
|
+
content: hasToolCalls ? msg.content || null : msg.content,
|
|
366
|
+
...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
|
|
263
367
|
};
|
|
264
368
|
if (hasToolCalls) {
|
|
265
369
|
assistantMsg.tool_calls = msg.tool_calls;
|
|
@@ -268,7 +372,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
268
372
|
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
269
373
|
formatted.push({
|
|
270
374
|
role: "tool",
|
|
271
|
-
content: msg.content ?? "",
|
|
375
|
+
content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
|
|
376
|
+
...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
|
|
272
377
|
tool_call_id: msg.tool_call_id
|
|
273
378
|
});
|
|
274
379
|
}
|
|
@@ -555,7 +660,7 @@ function formatMessagesForGoogle(messages) {
|
|
|
555
660
|
return {
|
|
556
661
|
role: "tool",
|
|
557
662
|
tool_call_id: msg.toolCallId,
|
|
558
|
-
content: msg.content
|
|
663
|
+
content: textToolOutput(msg.modelOutput, msg.content)
|
|
559
664
|
};
|
|
560
665
|
default:
|
|
561
666
|
return msg;
|
|
@@ -563,6 +668,64 @@ function formatMessagesForGoogle(messages) {
|
|
|
563
668
|
});
|
|
564
669
|
}
|
|
565
670
|
|
|
671
|
+
// src/core/openai-responses.ts
|
|
672
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
673
|
+
return {
|
|
674
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
675
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
679
|
+
const api = transport.api ?? "auto";
|
|
680
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
681
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
682
|
+
}
|
|
683
|
+
if (api === "chat") {
|
|
684
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
685
|
+
throw new Error(
|
|
686
|
+
"Responses options and native tool search require the Responses API"
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
return false;
|
|
690
|
+
}
|
|
691
|
+
let officialEndpoint = !baseURL;
|
|
692
|
+
try {
|
|
693
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
694
|
+
} catch {
|
|
695
|
+
}
|
|
696
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
697
|
+
}
|
|
698
|
+
function responseMetadata(response) {
|
|
699
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
700
|
+
return {
|
|
701
|
+
openai: {
|
|
702
|
+
response: {
|
|
703
|
+
id: response?.id,
|
|
704
|
+
model: response?.model,
|
|
705
|
+
status: response?.status,
|
|
706
|
+
output,
|
|
707
|
+
usage: response?.usage,
|
|
708
|
+
store: response?.store,
|
|
709
|
+
refusals: output.flatMap(
|
|
710
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
711
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
712
|
+
).map((part) => part.refusal) : []
|
|
713
|
+
)
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
function getResponseReplay(metadata) {
|
|
719
|
+
const response = metadata?.openai?.response;
|
|
720
|
+
if (response === void 0) return void 0;
|
|
721
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
722
|
+
throw new Error(
|
|
723
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
724
|
+
);
|
|
725
|
+
}
|
|
726
|
+
return response.output;
|
|
727
|
+
}
|
|
728
|
+
|
|
566
729
|
// src/core/provider-error.ts
|
|
567
730
|
function providerErrorEvent(error, code) {
|
|
568
731
|
const details = error ?? {};
|
|
@@ -639,13 +802,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
639
802
|
}));
|
|
640
803
|
}
|
|
641
804
|
shouldUseResponsesApi(request) {
|
|
642
|
-
|
|
643
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
644
|
-
return true;
|
|
645
|
-
return requiresOpenAIResponses(
|
|
805
|
+
return useOpenAIResponses(
|
|
646
806
|
request.config?.model || this.model,
|
|
647
807
|
this.config.baseUrl,
|
|
648
|
-
this.parameterOptions(request)
|
|
808
|
+
this.parameterOptions(request),
|
|
809
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
810
|
+
this.toolDefinitions(request).length > 0,
|
|
811
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
812
|
+
(message) => message.providerMetadata?.openai?.response
|
|
813
|
+
),
|
|
814
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
649
815
|
);
|
|
650
816
|
}
|
|
651
817
|
/**
|
|
@@ -678,11 +844,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
678
844
|
});
|
|
679
845
|
}
|
|
680
846
|
buildResponsesInput(request) {
|
|
681
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
847
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
682
848
|
const input = [];
|
|
683
849
|
for (const message of sourceMessages) {
|
|
684
850
|
if (message.role === "system") {
|
|
685
|
-
if (
|
|
851
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
686
852
|
input.push({
|
|
687
853
|
type: "message",
|
|
688
854
|
role: "developer",
|
|
@@ -692,6 +858,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
692
858
|
continue;
|
|
693
859
|
}
|
|
694
860
|
if (message.role === "assistant") {
|
|
861
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
862
|
+
if (replay) {
|
|
863
|
+
input.push(...replay);
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
695
866
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
696
867
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
697
868
|
input.push({
|
|
@@ -715,7 +886,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
715
886
|
input.push({
|
|
716
887
|
type: "function_call_output",
|
|
717
888
|
call_id: message.tool_call_id,
|
|
718
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
889
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
719
890
|
});
|
|
720
891
|
continue;
|
|
721
892
|
}
|
|
@@ -729,10 +900,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
729
900
|
return input;
|
|
730
901
|
}
|
|
731
902
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
732
|
-
formatRawMessages(messages) {
|
|
903
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
733
904
|
return messages.map((message) => {
|
|
734
|
-
const { attachments, ...rest } = message;
|
|
735
|
-
let content = message.content;
|
|
905
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
906
|
+
let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
|
|
907
|
+
if (preserveProviderMetadata && modelOutput)
|
|
908
|
+
rest.modelOutput = modelOutput;
|
|
736
909
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
737
910
|
content = null;
|
|
738
911
|
}
|
|
@@ -745,7 +918,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
745
918
|
content = [...parts, ...images];
|
|
746
919
|
}
|
|
747
920
|
}
|
|
748
|
-
return {
|
|
921
|
+
return {
|
|
922
|
+
...rest,
|
|
923
|
+
content,
|
|
924
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
925
|
+
};
|
|
749
926
|
});
|
|
750
927
|
}
|
|
751
928
|
/**
|
|
@@ -826,14 +1003,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
826
1003
|
).map((part) => part.text) : []
|
|
827
1004
|
).join("") : "";
|
|
828
1005
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
name
|
|
832
|
-
|
|
833
|
-
|
|
1006
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
1007
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
1008
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
1009
|
+
throw new Error("Responses contains an incomplete function call");
|
|
1010
|
+
}
|
|
1011
|
+
if (seenCallIds.has(item.call_id))
|
|
1012
|
+
throw new Error("Responses contains duplicate function call IDs");
|
|
1013
|
+
seenCallIds.add(item.call_id);
|
|
1014
|
+
const args = JSON.parse(item.arguments);
|
|
1015
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1016
|
+
throw new Error(
|
|
1017
|
+
"Responses function arguments must be a JSON object"
|
|
1018
|
+
);
|
|
1019
|
+
return { id: item.call_id, name: item.name, args };
|
|
1020
|
+
}) : [];
|
|
834
1021
|
return {
|
|
835
1022
|
content,
|
|
836
1023
|
toolCalls,
|
|
1024
|
+
providerMetadata: responseMetadata(response),
|
|
837
1025
|
usage: response?.usage ? {
|
|
838
1026
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
839
1027
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -844,6 +1032,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
844
1032
|
}
|
|
845
1033
|
buildResponsesPayload(request, stream) {
|
|
846
1034
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1035
|
+
const options = resolveOpenAITransport(
|
|
1036
|
+
this.config,
|
|
1037
|
+
request.config?.openai
|
|
1038
|
+
).responses;
|
|
1039
|
+
const parameters = buildOpenAIParameters(
|
|
1040
|
+
request.config?.model || this.model,
|
|
1041
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1042
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1043
|
+
this.parameterOptions(request),
|
|
1044
|
+
"responses"
|
|
1045
|
+
);
|
|
847
1046
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
848
1047
|
request.config?.responseFormat
|
|
849
1048
|
);
|
|
@@ -859,13 +1058,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
859
1058
|
),
|
|
860
1059
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
861
1060
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
862
|
-
...
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1061
|
+
...parameters,
|
|
1062
|
+
...options?.reasoningSummary ? {
|
|
1063
|
+
reasoning: {
|
|
1064
|
+
...parameters.reasoning,
|
|
1065
|
+
summary: options.reasoningSummary
|
|
1066
|
+
}
|
|
1067
|
+
} : {},
|
|
1068
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1069
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1070
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1071
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1072
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1073
|
+
...options?.store === false || options?.include ? {
|
|
1074
|
+
include: [
|
|
1075
|
+
.../* @__PURE__ */ new Set([
|
|
1076
|
+
...options?.include ?? [],
|
|
1077
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1078
|
+
])
|
|
1079
|
+
]
|
|
1080
|
+
} : {},
|
|
869
1081
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
870
1082
|
stream
|
|
871
1083
|
};
|
|
@@ -924,6 +1136,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
924
1136
|
let usage;
|
|
925
1137
|
const citations = [];
|
|
926
1138
|
let completed = false;
|
|
1139
|
+
let terminalResponse;
|
|
1140
|
+
let responseIdentity = {};
|
|
1141
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1142
|
+
let streamedText = "";
|
|
927
1143
|
function* flushToolCalls() {
|
|
928
1144
|
for (const call of toolCalls.values()) {
|
|
929
1145
|
if (!call.name)
|
|
@@ -940,17 +1156,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
940
1156
|
for await (const event of stream) {
|
|
941
1157
|
throwIfAborted(request.signal);
|
|
942
1158
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1159
|
+
if (completed)
|
|
1160
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
943
1161
|
const index = event?.output_index ?? 0;
|
|
944
1162
|
switch (event?.type) {
|
|
1163
|
+
case "response.created":
|
|
1164
|
+
responseIdentity = {
|
|
1165
|
+
id: event.response?.id,
|
|
1166
|
+
model: event.response?.model
|
|
1167
|
+
};
|
|
1168
|
+
break;
|
|
1169
|
+
case "response.output_item.done":
|
|
1170
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1171
|
+
if (event.item?.type === "function_call") {
|
|
1172
|
+
toolCalls.set(index, {
|
|
1173
|
+
id: event.item.call_id,
|
|
1174
|
+
name: event.item.name,
|
|
1175
|
+
arguments: event.item.arguments
|
|
1176
|
+
});
|
|
1177
|
+
}
|
|
1178
|
+
break;
|
|
945
1179
|
case "response.output_text.delta":
|
|
946
1180
|
if (event.delta) {
|
|
1181
|
+
streamedText += event.delta;
|
|
947
1182
|
yield { type: "message:delta", content: event.delta };
|
|
948
1183
|
}
|
|
949
1184
|
break;
|
|
950
1185
|
case "response.output_item.added":
|
|
951
1186
|
if (event.item?.type === "function_call") {
|
|
952
1187
|
toolCalls.set(index, {
|
|
953
|
-
id: event.item.call_id ??
|
|
1188
|
+
id: event.item.call_id ?? "",
|
|
954
1189
|
name: event.item.name ?? "",
|
|
955
1190
|
arguments: event.item.arguments ?? ""
|
|
956
1191
|
});
|
|
@@ -969,7 +1204,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
969
1204
|
break;
|
|
970
1205
|
}
|
|
971
1206
|
case "response.completed": {
|
|
1207
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1208
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
972
1209
|
completed = true;
|
|
1210
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
973
1211
|
const found = this.collectResponsesCitations(
|
|
974
1212
|
event.response?.output,
|
|
975
1213
|
citations.length
|
|
@@ -1006,12 +1244,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1006
1244
|
throwIfAborted(request.signal);
|
|
1007
1245
|
if (!completed)
|
|
1008
1246
|
throw new Error("Responses stream ended without a completed response");
|
|
1247
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1248
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1249
|
+
toolCalls.clear();
|
|
1250
|
+
for (const [index, item] of output.entries()) {
|
|
1251
|
+
if (item.type === "function_call") {
|
|
1252
|
+
toolCalls.set(index, {
|
|
1253
|
+
id: item.call_id,
|
|
1254
|
+
name: item.name,
|
|
1255
|
+
arguments: item.arguments
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1260
|
+
for (const call of toolCalls.values()) {
|
|
1261
|
+
if (!call.id || !call.name)
|
|
1262
|
+
throw new Error("Responses stream contains an incomplete tool call");
|
|
1263
|
+
uniqueCalls.set(call.id, call);
|
|
1264
|
+
}
|
|
1265
|
+
toolCalls.clear();
|
|
1266
|
+
[...uniqueCalls.values()].forEach(
|
|
1267
|
+
(call, index) => toolCalls.set(index, call)
|
|
1268
|
+
);
|
|
1269
|
+
if (!output.length && toolCalls.size) {
|
|
1270
|
+
for (const call of toolCalls.values())
|
|
1271
|
+
output.push({
|
|
1272
|
+
type: "function_call",
|
|
1273
|
+
call_id: call.id,
|
|
1274
|
+
name: call.name,
|
|
1275
|
+
arguments: call.arguments
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
if (!output.length && streamedText)
|
|
1279
|
+
output.push({
|
|
1280
|
+
type: "message",
|
|
1281
|
+
role: "assistant",
|
|
1282
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1283
|
+
});
|
|
1284
|
+
terminalResponse.output = output;
|
|
1285
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1286
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1287
|
+
yield {
|
|
1288
|
+
type: "message:delta",
|
|
1289
|
+
content: finalText.slice(streamedText.length)
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1009
1292
|
yield* flushToolCalls();
|
|
1010
1293
|
if (citations.length > 0) {
|
|
1011
1294
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
1012
1295
|
}
|
|
1013
|
-
yield {
|
|
1014
|
-
|
|
1296
|
+
yield {
|
|
1297
|
+
type: "message:end",
|
|
1298
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1299
|
+
};
|
|
1300
|
+
yield {
|
|
1301
|
+
type: "done",
|
|
1302
|
+
usage,
|
|
1303
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1304
|
+
};
|
|
1015
1305
|
}
|
|
1016
1306
|
async *stream(request) {
|
|
1017
1307
|
throwIfAborted(request.signal);
|