@yourgpt/llm-sdk 2.6.0-beta.1 → 2.6.0-beta.3
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 +146 -0
- package/dist/adapters/index.d.mts +5 -5
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/index.js +437 -39
- package/dist/adapters/index.mjs +437 -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 +20 -36
- package/dist/index.d.ts +20 -36
- package/dist/index.js +327 -69
- package/dist/index.mjs +325 -70
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/anthropic/index.js +116 -7
- package/dist/providers/anthropic/index.mjs +116 -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 +393 -31
- package/dist/providers/fireworks/index.mjs +393 -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 +393 -31
- package/dist/providers/google/index.mjs +393 -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 +822 -40
- package/dist/providers/openai/index.mjs +821 -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 +393 -31
- package/dist/providers/openrouter/index.mjs +393 -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 +393 -31
- package/dist/providers/togetherai/index.mjs +393 -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 +393 -31
- package/dist/providers/xai/index.mjs +393 -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,7 +668,120 @@ 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 responseReplayMetadata(metadata) {
|
|
719
|
+
const response = metadata?.openai?.response;
|
|
720
|
+
if (!response) return metadata;
|
|
721
|
+
const output = response.output.map((item) => {
|
|
722
|
+
const fields = ["type", "id", "status"];
|
|
723
|
+
switch (item.type) {
|
|
724
|
+
case "reasoning":
|
|
725
|
+
fields.push("encrypted_content");
|
|
726
|
+
break;
|
|
727
|
+
case "message":
|
|
728
|
+
fields.push("role", "phase");
|
|
729
|
+
break;
|
|
730
|
+
case "function_call":
|
|
731
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
732
|
+
break;
|
|
733
|
+
case "tool_search_call":
|
|
734
|
+
fields.push("call_id", "execution", "arguments");
|
|
735
|
+
break;
|
|
736
|
+
case "tool_search_output":
|
|
737
|
+
fields.push("call_id", "tools");
|
|
738
|
+
break;
|
|
739
|
+
case "web_search_call":
|
|
740
|
+
fields.push("action");
|
|
741
|
+
break;
|
|
742
|
+
default:
|
|
743
|
+
return stripItemDiagnostics(item);
|
|
744
|
+
}
|
|
745
|
+
const replay = Object.fromEntries(
|
|
746
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
747
|
+
);
|
|
748
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
749
|
+
if (item.type === "message")
|
|
750
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
751
|
+
(part) => part?.type === "output_text" && typeof part.text === "string" ? [{ type: "output_text", text: part.text, annotations: [] }] : part?.type === "refusal" && typeof part.refusal === "string" ? [{ type: "refusal", refusal: part.refusal }] : []
|
|
752
|
+
) : [];
|
|
753
|
+
return stripItemDiagnostics(replay);
|
|
754
|
+
});
|
|
755
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
756
|
+
}
|
|
757
|
+
function stripItemDiagnostics(item) {
|
|
758
|
+
const {
|
|
759
|
+
usage: _usage,
|
|
760
|
+
logprobs: _logprobs,
|
|
761
|
+
metadata: _metadata,
|
|
762
|
+
...state
|
|
763
|
+
} = item;
|
|
764
|
+
return state;
|
|
765
|
+
}
|
|
766
|
+
function getResponseReplay(metadata) {
|
|
767
|
+
const response = metadata?.openai?.response;
|
|
768
|
+
if (response === void 0) return void 0;
|
|
769
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
770
|
+
throw new Error(
|
|
771
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
775
|
+
}
|
|
776
|
+
|
|
566
777
|
// src/core/provider-error.ts
|
|
778
|
+
function invalidProviderResponse(message) {
|
|
779
|
+
return Object.assign(new Error(message), {
|
|
780
|
+
name: "InvalidProviderResponseError",
|
|
781
|
+
status: 502,
|
|
782
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
783
|
+
});
|
|
784
|
+
}
|
|
567
785
|
function providerErrorEvent(error, code) {
|
|
568
786
|
const details = error ?? {};
|
|
569
787
|
const event = {
|
|
@@ -639,13 +857,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
639
857
|
}));
|
|
640
858
|
}
|
|
641
859
|
shouldUseResponsesApi(request) {
|
|
642
|
-
|
|
643
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
644
|
-
return true;
|
|
645
|
-
return requiresOpenAIResponses(
|
|
860
|
+
return useOpenAIResponses(
|
|
646
861
|
request.config?.model || this.model,
|
|
647
862
|
this.config.baseUrl,
|
|
648
|
-
this.parameterOptions(request)
|
|
863
|
+
this.parameterOptions(request),
|
|
864
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
865
|
+
this.toolDefinitions(request).length > 0,
|
|
866
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
867
|
+
(message) => message.providerMetadata?.openai?.response
|
|
868
|
+
),
|
|
869
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
649
870
|
);
|
|
650
871
|
}
|
|
651
872
|
/**
|
|
@@ -678,11 +899,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
678
899
|
});
|
|
679
900
|
}
|
|
680
901
|
buildResponsesInput(request) {
|
|
681
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
902
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
682
903
|
const input = [];
|
|
683
904
|
for (const message of sourceMessages) {
|
|
684
905
|
if (message.role === "system") {
|
|
685
|
-
if (
|
|
906
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
686
907
|
input.push({
|
|
687
908
|
type: "message",
|
|
688
909
|
role: "developer",
|
|
@@ -692,6 +913,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
692
913
|
continue;
|
|
693
914
|
}
|
|
694
915
|
if (message.role === "assistant") {
|
|
916
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
917
|
+
if (replay) {
|
|
918
|
+
input.push(...replay);
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
695
921
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
696
922
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
697
923
|
input.push({
|
|
@@ -715,7 +941,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
715
941
|
input.push({
|
|
716
942
|
type: "function_call_output",
|
|
717
943
|
call_id: message.tool_call_id,
|
|
718
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
944
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
719
945
|
});
|
|
720
946
|
continue;
|
|
721
947
|
}
|
|
@@ -729,10 +955,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
729
955
|
return input;
|
|
730
956
|
}
|
|
731
957
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
732
|
-
formatRawMessages(messages) {
|
|
958
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
733
959
|
return messages.map((message) => {
|
|
734
|
-
const { attachments, ...rest } = message;
|
|
735
|
-
let content = message.content;
|
|
960
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
961
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
962
|
+
if (preserveProviderMetadata && modelOutput)
|
|
963
|
+
rest.modelOutput = modelOutput;
|
|
736
964
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
737
965
|
content = null;
|
|
738
966
|
}
|
|
@@ -745,7 +973,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
745
973
|
content = [...parts, ...images];
|
|
746
974
|
}
|
|
747
975
|
}
|
|
748
|
-
return {
|
|
976
|
+
return {
|
|
977
|
+
...rest,
|
|
978
|
+
content,
|
|
979
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
980
|
+
};
|
|
749
981
|
});
|
|
750
982
|
}
|
|
751
983
|
/**
|
|
@@ -826,14 +1058,40 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
826
1058
|
).map((part) => part.text) : []
|
|
827
1059
|
).join("") : "";
|
|
828
1060
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
name
|
|
832
|
-
|
|
833
|
-
|
|
1061
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
1062
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
1063
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
1064
|
+
throw invalidProviderResponse(
|
|
1065
|
+
"Responses contains an incomplete function call"
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
if (seenCallIds.has(item.call_id))
|
|
1069
|
+
throw invalidProviderResponse(
|
|
1070
|
+
"Responses contains duplicate function call IDs"
|
|
1071
|
+
);
|
|
1072
|
+
seenCallIds.add(item.call_id);
|
|
1073
|
+
let args;
|
|
1074
|
+
try {
|
|
1075
|
+
args = JSON.parse(item.arguments);
|
|
1076
|
+
} catch {
|
|
1077
|
+
throw invalidProviderResponse(
|
|
1078
|
+
"Responses function arguments must be valid JSON"
|
|
1079
|
+
);
|
|
1080
|
+
}
|
|
1081
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1082
|
+
throw invalidProviderResponse(
|
|
1083
|
+
"Responses function arguments must be a JSON object"
|
|
1084
|
+
);
|
|
1085
|
+
return {
|
|
1086
|
+
id: item.call_id,
|
|
1087
|
+
name: item.name,
|
|
1088
|
+
args
|
|
1089
|
+
};
|
|
1090
|
+
}) : [];
|
|
834
1091
|
return {
|
|
835
1092
|
content,
|
|
836
1093
|
toolCalls,
|
|
1094
|
+
providerMetadata: responseMetadata(response),
|
|
837
1095
|
usage: response?.usage ? {
|
|
838
1096
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
839
1097
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -844,6 +1102,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
844
1102
|
}
|
|
845
1103
|
buildResponsesPayload(request, stream) {
|
|
846
1104
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1105
|
+
const options = resolveOpenAITransport(
|
|
1106
|
+
this.config,
|
|
1107
|
+
request.config?.openai
|
|
1108
|
+
).responses;
|
|
1109
|
+
const parameters = buildOpenAIParameters(
|
|
1110
|
+
request.config?.model || this.model,
|
|
1111
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1112
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1113
|
+
this.parameterOptions(request),
|
|
1114
|
+
"responses"
|
|
1115
|
+
);
|
|
847
1116
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
848
1117
|
request.config?.responseFormat
|
|
849
1118
|
);
|
|
@@ -859,13 +1128,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
859
1128
|
),
|
|
860
1129
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
861
1130
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
862
|
-
...
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1131
|
+
...parameters,
|
|
1132
|
+
...options?.reasoningSummary ? {
|
|
1133
|
+
reasoning: {
|
|
1134
|
+
...parameters.reasoning,
|
|
1135
|
+
summary: options.reasoningSummary
|
|
1136
|
+
}
|
|
1137
|
+
} : {},
|
|
1138
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1139
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1140
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1141
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1142
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1143
|
+
...options?.store === false || options?.include ? {
|
|
1144
|
+
include: [
|
|
1145
|
+
.../* @__PURE__ */ new Set([
|
|
1146
|
+
...options?.include ?? [],
|
|
1147
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1148
|
+
])
|
|
1149
|
+
]
|
|
1150
|
+
} : {},
|
|
869
1151
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
870
1152
|
stream
|
|
871
1153
|
};
|
|
@@ -924,6 +1206,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
924
1206
|
let usage;
|
|
925
1207
|
const citations = [];
|
|
926
1208
|
let completed = false;
|
|
1209
|
+
let terminalResponse;
|
|
1210
|
+
let responseIdentity = {};
|
|
1211
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1212
|
+
let streamedText = "";
|
|
927
1213
|
function* flushToolCalls() {
|
|
928
1214
|
for (const call of toolCalls.values()) {
|
|
929
1215
|
if (!call.name)
|
|
@@ -940,17 +1226,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
940
1226
|
for await (const event of stream) {
|
|
941
1227
|
throwIfAborted(request.signal);
|
|
942
1228
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1229
|
+
if (completed)
|
|
1230
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
943
1231
|
const index = event?.output_index ?? 0;
|
|
944
1232
|
switch (event?.type) {
|
|
1233
|
+
case "response.created":
|
|
1234
|
+
responseIdentity = {
|
|
1235
|
+
id: event.response?.id,
|
|
1236
|
+
model: event.response?.model
|
|
1237
|
+
};
|
|
1238
|
+
break;
|
|
1239
|
+
case "response.output_item.done":
|
|
1240
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1241
|
+
if (event.item?.type === "function_call") {
|
|
1242
|
+
toolCalls.set(index, {
|
|
1243
|
+
id: event.item.call_id,
|
|
1244
|
+
name: event.item.name,
|
|
1245
|
+
arguments: event.item.arguments
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
break;
|
|
945
1249
|
case "response.output_text.delta":
|
|
946
1250
|
if (event.delta) {
|
|
1251
|
+
streamedText += event.delta;
|
|
947
1252
|
yield { type: "message:delta", content: event.delta };
|
|
948
1253
|
}
|
|
949
1254
|
break;
|
|
950
1255
|
case "response.output_item.added":
|
|
951
1256
|
if (event.item?.type === "function_call") {
|
|
952
1257
|
toolCalls.set(index, {
|
|
953
|
-
id: event.item.call_id ??
|
|
1258
|
+
id: event.item.call_id ?? "",
|
|
954
1259
|
name: event.item.name ?? "",
|
|
955
1260
|
arguments: event.item.arguments ?? ""
|
|
956
1261
|
});
|
|
@@ -969,7 +1274,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
969
1274
|
break;
|
|
970
1275
|
}
|
|
971
1276
|
case "response.completed": {
|
|
1277
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1278
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
972
1279
|
completed = true;
|
|
1280
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
973
1281
|
const found = this.collectResponsesCitations(
|
|
974
1282
|
event.response?.output,
|
|
975
1283
|
citations.length
|
|
@@ -1006,12 +1314,66 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
1006
1314
|
throwIfAborted(request.signal);
|
|
1007
1315
|
if (!completed)
|
|
1008
1316
|
throw new Error("Responses stream ended without a completed response");
|
|
1317
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1318
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1319
|
+
toolCalls.clear();
|
|
1320
|
+
for (const [index, item] of output.entries()) {
|
|
1321
|
+
if (item.type === "function_call") {
|
|
1322
|
+
toolCalls.set(index, {
|
|
1323
|
+
id: item.call_id,
|
|
1324
|
+
name: item.name,
|
|
1325
|
+
arguments: item.arguments
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1330
|
+
for (const call of toolCalls.values()) {
|
|
1331
|
+
if (!call.id || !call.name)
|
|
1332
|
+
throw invalidProviderResponse(
|
|
1333
|
+
"Responses stream contains an incomplete tool call"
|
|
1334
|
+
);
|
|
1335
|
+
uniqueCalls.set(call.id, call);
|
|
1336
|
+
}
|
|
1337
|
+
toolCalls.clear();
|
|
1338
|
+
[...uniqueCalls.values()].forEach(
|
|
1339
|
+
(call, index) => toolCalls.set(index, call)
|
|
1340
|
+
);
|
|
1341
|
+
if (!output.length && toolCalls.size) {
|
|
1342
|
+
for (const call of toolCalls.values())
|
|
1343
|
+
output.push({
|
|
1344
|
+
type: "function_call",
|
|
1345
|
+
call_id: call.id,
|
|
1346
|
+
name: call.name,
|
|
1347
|
+
arguments: call.arguments
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
if (!output.length && streamedText)
|
|
1351
|
+
output.push({
|
|
1352
|
+
type: "message",
|
|
1353
|
+
role: "assistant",
|
|
1354
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1355
|
+
});
|
|
1356
|
+
terminalResponse.output = output;
|
|
1357
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1358
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1359
|
+
yield {
|
|
1360
|
+
type: "message:delta",
|
|
1361
|
+
content: finalText.slice(streamedText.length)
|
|
1362
|
+
};
|
|
1363
|
+
}
|
|
1009
1364
|
yield* flushToolCalls();
|
|
1010
1365
|
if (citations.length > 0) {
|
|
1011
1366
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
1012
1367
|
}
|
|
1013
|
-
yield {
|
|
1014
|
-
|
|
1368
|
+
yield {
|
|
1369
|
+
type: "message:end",
|
|
1370
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1371
|
+
};
|
|
1372
|
+
yield {
|
|
1373
|
+
type: "done",
|
|
1374
|
+
usage,
|
|
1375
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1376
|
+
};
|
|
1015
1377
|
}
|
|
1016
1378
|
async *stream(request) {
|
|
1017
1379
|
throwIfAborted(request.signal);
|