@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,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-Dg1Bcg1k.mjs';
|
|
2
|
+
import { A as AIProvider } from '../../types-DHQEMFHA.mjs';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-BICaQaRS.mjs';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* OpenRouter Provider - Modern Pattern
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-Dg1Bcg1k.js';
|
|
2
|
+
import { A as AIProvider } from '../../types-Dikj3En4.js';
|
|
3
3
|
import 'zod';
|
|
4
|
-
import '../../base-
|
|
4
|
+
import '../../base-CpRPB8u8.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* OpenRouter Provider - Modern Pattern
|
|
@@ -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
|
}
|
|
@@ -505,7 +610,7 @@ function formatMessagesForOpenRouter(messages) {
|
|
|
505
610
|
return {
|
|
506
611
|
role: "tool",
|
|
507
612
|
tool_call_id: msg.toolCallId,
|
|
508
|
-
content: msg.content
|
|
613
|
+
content: textToolOutput(msg.modelOutput, msg.content)
|
|
509
614
|
};
|
|
510
615
|
default:
|
|
511
616
|
return msg;
|
|
@@ -536,6 +641,64 @@ async function searchOpenRouterModels(query, apiKey) {
|
|
|
536
641
|
);
|
|
537
642
|
}
|
|
538
643
|
|
|
644
|
+
// src/core/openai-responses.ts
|
|
645
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
646
|
+
return {
|
|
647
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
648
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
652
|
+
const api = transport.api ?? "auto";
|
|
653
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
654
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
655
|
+
}
|
|
656
|
+
if (api === "chat") {
|
|
657
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
658
|
+
throw new Error(
|
|
659
|
+
"Responses options and native tool search require the Responses API"
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
let officialEndpoint = !baseURL;
|
|
665
|
+
try {
|
|
666
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
669
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
670
|
+
}
|
|
671
|
+
function responseMetadata(response) {
|
|
672
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
673
|
+
return {
|
|
674
|
+
openai: {
|
|
675
|
+
response: {
|
|
676
|
+
id: response?.id,
|
|
677
|
+
model: response?.model,
|
|
678
|
+
status: response?.status,
|
|
679
|
+
output,
|
|
680
|
+
usage: response?.usage,
|
|
681
|
+
store: response?.store,
|
|
682
|
+
refusals: output.flatMap(
|
|
683
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
684
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
685
|
+
).map((part) => part.refusal) : []
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
function getResponseReplay(metadata) {
|
|
692
|
+
const response = metadata?.openai?.response;
|
|
693
|
+
if (response === void 0) return void 0;
|
|
694
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
695
|
+
throw new Error(
|
|
696
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
return response.output;
|
|
700
|
+
}
|
|
701
|
+
|
|
539
702
|
// src/core/provider-error.ts
|
|
540
703
|
function providerErrorEvent(error, code) {
|
|
541
704
|
const details = error ?? {};
|
|
@@ -612,13 +775,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
612
775
|
}));
|
|
613
776
|
}
|
|
614
777
|
shouldUseResponsesApi(request) {
|
|
615
|
-
|
|
616
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
617
|
-
return true;
|
|
618
|
-
return requiresOpenAIResponses(
|
|
778
|
+
return useOpenAIResponses(
|
|
619
779
|
request.config?.model || this.model,
|
|
620
780
|
this.config.baseUrl,
|
|
621
|
-
this.parameterOptions(request)
|
|
781
|
+
this.parameterOptions(request),
|
|
782
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
783
|
+
this.toolDefinitions(request).length > 0,
|
|
784
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
785
|
+
(message) => message.providerMetadata?.openai?.response
|
|
786
|
+
),
|
|
787
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
622
788
|
);
|
|
623
789
|
}
|
|
624
790
|
/**
|
|
@@ -651,11 +817,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
651
817
|
});
|
|
652
818
|
}
|
|
653
819
|
buildResponsesInput(request) {
|
|
654
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
820
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
655
821
|
const input = [];
|
|
656
822
|
for (const message of sourceMessages) {
|
|
657
823
|
if (message.role === "system") {
|
|
658
|
-
if (
|
|
824
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
659
825
|
input.push({
|
|
660
826
|
type: "message",
|
|
661
827
|
role: "developer",
|
|
@@ -665,6 +831,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
665
831
|
continue;
|
|
666
832
|
}
|
|
667
833
|
if (message.role === "assistant") {
|
|
834
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
835
|
+
if (replay) {
|
|
836
|
+
input.push(...replay);
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
668
839
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
669
840
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
670
841
|
input.push({
|
|
@@ -688,7 +859,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
688
859
|
input.push({
|
|
689
860
|
type: "function_call_output",
|
|
690
861
|
call_id: message.tool_call_id,
|
|
691
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
862
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
692
863
|
});
|
|
693
864
|
continue;
|
|
694
865
|
}
|
|
@@ -702,10 +873,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
702
873
|
return input;
|
|
703
874
|
}
|
|
704
875
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
705
|
-
formatRawMessages(messages) {
|
|
876
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
706
877
|
return messages.map((message) => {
|
|
707
|
-
const { attachments, ...rest } = message;
|
|
708
|
-
let content = message.content;
|
|
878
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
879
|
+
let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
|
|
880
|
+
if (preserveProviderMetadata && modelOutput)
|
|
881
|
+
rest.modelOutput = modelOutput;
|
|
709
882
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
710
883
|
content = null;
|
|
711
884
|
}
|
|
@@ -718,7 +891,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
718
891
|
content = [...parts, ...images];
|
|
719
892
|
}
|
|
720
893
|
}
|
|
721
|
-
return {
|
|
894
|
+
return {
|
|
895
|
+
...rest,
|
|
896
|
+
content,
|
|
897
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
898
|
+
};
|
|
722
899
|
});
|
|
723
900
|
}
|
|
724
901
|
/**
|
|
@@ -799,14 +976,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
799
976
|
).map((part) => part.text) : []
|
|
800
977
|
).join("") : "";
|
|
801
978
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
name
|
|
805
|
-
|
|
806
|
-
|
|
979
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
980
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
981
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
982
|
+
throw new Error("Responses contains an incomplete function call");
|
|
983
|
+
}
|
|
984
|
+
if (seenCallIds.has(item.call_id))
|
|
985
|
+
throw new Error("Responses contains duplicate function call IDs");
|
|
986
|
+
seenCallIds.add(item.call_id);
|
|
987
|
+
const args = JSON.parse(item.arguments);
|
|
988
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
989
|
+
throw new Error(
|
|
990
|
+
"Responses function arguments must be a JSON object"
|
|
991
|
+
);
|
|
992
|
+
return { id: item.call_id, name: item.name, args };
|
|
993
|
+
}) : [];
|
|
807
994
|
return {
|
|
808
995
|
content,
|
|
809
996
|
toolCalls,
|
|
997
|
+
providerMetadata: responseMetadata(response),
|
|
810
998
|
usage: response?.usage ? {
|
|
811
999
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
812
1000
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -817,6 +1005,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
817
1005
|
}
|
|
818
1006
|
buildResponsesPayload(request, stream) {
|
|
819
1007
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1008
|
+
const options = resolveOpenAITransport(
|
|
1009
|
+
this.config,
|
|
1010
|
+
request.config?.openai
|
|
1011
|
+
).responses;
|
|
1012
|
+
const parameters = buildOpenAIParameters(
|
|
1013
|
+
request.config?.model || this.model,
|
|
1014
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1015
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1016
|
+
this.parameterOptions(request),
|
|
1017
|
+
"responses"
|
|
1018
|
+
);
|
|
820
1019
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
821
1020
|
request.config?.responseFormat
|
|
822
1021
|
);
|
|
@@ -832,13 +1031,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
832
1031
|
),
|
|
833
1032
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
834
1033
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
835
|
-
...
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1034
|
+
...parameters,
|
|
1035
|
+
...options?.reasoningSummary ? {
|
|
1036
|
+
reasoning: {
|
|
1037
|
+
...parameters.reasoning,
|
|
1038
|
+
summary: options.reasoningSummary
|
|
1039
|
+
}
|
|
1040
|
+
} : {},
|
|
1041
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1042
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1043
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1044
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1045
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1046
|
+
...options?.store === false || options?.include ? {
|
|
1047
|
+
include: [
|
|
1048
|
+
.../* @__PURE__ */ new Set([
|
|
1049
|
+
...options?.include ?? [],
|
|
1050
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1051
|
+
])
|
|
1052
|
+
]
|
|
1053
|
+
} : {},
|
|
842
1054
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
843
1055
|
stream
|
|
844
1056
|
};
|
|
@@ -897,6 +1109,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
897
1109
|
let usage;
|
|
898
1110
|
const citations = [];
|
|
899
1111
|
let completed = false;
|
|
1112
|
+
let terminalResponse;
|
|
1113
|
+
let responseIdentity = {};
|
|
1114
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1115
|
+
let streamedText = "";
|
|
900
1116
|
function* flushToolCalls() {
|
|
901
1117
|
for (const call of toolCalls.values()) {
|
|
902
1118
|
if (!call.name)
|
|
@@ -913,17 +1129,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
913
1129
|
for await (const event of stream) {
|
|
914
1130
|
throwIfAborted(request.signal);
|
|
915
1131
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1132
|
+
if (completed)
|
|
1133
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
916
1134
|
const index = event?.output_index ?? 0;
|
|
917
1135
|
switch (event?.type) {
|
|
1136
|
+
case "response.created":
|
|
1137
|
+
responseIdentity = {
|
|
1138
|
+
id: event.response?.id,
|
|
1139
|
+
model: event.response?.model
|
|
1140
|
+
};
|
|
1141
|
+
break;
|
|
1142
|
+
case "response.output_item.done":
|
|
1143
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1144
|
+
if (event.item?.type === "function_call") {
|
|
1145
|
+
toolCalls.set(index, {
|
|
1146
|
+
id: event.item.call_id,
|
|
1147
|
+
name: event.item.name,
|
|
1148
|
+
arguments: event.item.arguments
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
break;
|
|
918
1152
|
case "response.output_text.delta":
|
|
919
1153
|
if (event.delta) {
|
|
1154
|
+
streamedText += event.delta;
|
|
920
1155
|
yield { type: "message:delta", content: event.delta };
|
|
921
1156
|
}
|
|
922
1157
|
break;
|
|
923
1158
|
case "response.output_item.added":
|
|
924
1159
|
if (event.item?.type === "function_call") {
|
|
925
1160
|
toolCalls.set(index, {
|
|
926
|
-
id: event.item.call_id ??
|
|
1161
|
+
id: event.item.call_id ?? "",
|
|
927
1162
|
name: event.item.name ?? "",
|
|
928
1163
|
arguments: event.item.arguments ?? ""
|
|
929
1164
|
});
|
|
@@ -942,7 +1177,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
942
1177
|
break;
|
|
943
1178
|
}
|
|
944
1179
|
case "response.completed": {
|
|
1180
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1181
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
945
1182
|
completed = true;
|
|
1183
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
946
1184
|
const found = this.collectResponsesCitations(
|
|
947
1185
|
event.response?.output,
|
|
948
1186
|
citations.length
|
|
@@ -979,12 +1217,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
979
1217
|
throwIfAborted(request.signal);
|
|
980
1218
|
if (!completed)
|
|
981
1219
|
throw new Error("Responses stream ended without a completed response");
|
|
1220
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1221
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1222
|
+
toolCalls.clear();
|
|
1223
|
+
for (const [index, item] of output.entries()) {
|
|
1224
|
+
if (item.type === "function_call") {
|
|
1225
|
+
toolCalls.set(index, {
|
|
1226
|
+
id: item.call_id,
|
|
1227
|
+
name: item.name,
|
|
1228
|
+
arguments: item.arguments
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1233
|
+
for (const call of toolCalls.values()) {
|
|
1234
|
+
if (!call.id || !call.name)
|
|
1235
|
+
throw new Error("Responses stream contains an incomplete tool call");
|
|
1236
|
+
uniqueCalls.set(call.id, call);
|
|
1237
|
+
}
|
|
1238
|
+
toolCalls.clear();
|
|
1239
|
+
[...uniqueCalls.values()].forEach(
|
|
1240
|
+
(call, index) => toolCalls.set(index, call)
|
|
1241
|
+
);
|
|
1242
|
+
if (!output.length && toolCalls.size) {
|
|
1243
|
+
for (const call of toolCalls.values())
|
|
1244
|
+
output.push({
|
|
1245
|
+
type: "function_call",
|
|
1246
|
+
call_id: call.id,
|
|
1247
|
+
name: call.name,
|
|
1248
|
+
arguments: call.arguments
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
if (!output.length && streamedText)
|
|
1252
|
+
output.push({
|
|
1253
|
+
type: "message",
|
|
1254
|
+
role: "assistant",
|
|
1255
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1256
|
+
});
|
|
1257
|
+
terminalResponse.output = output;
|
|
1258
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1259
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1260
|
+
yield {
|
|
1261
|
+
type: "message:delta",
|
|
1262
|
+
content: finalText.slice(streamedText.length)
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
982
1265
|
yield* flushToolCalls();
|
|
983
1266
|
if (citations.length > 0) {
|
|
984
1267
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
985
1268
|
}
|
|
986
|
-
yield {
|
|
987
|
-
|
|
1269
|
+
yield {
|
|
1270
|
+
type: "message:end",
|
|
1271
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1272
|
+
};
|
|
1273
|
+
yield {
|
|
1274
|
+
type: "done",
|
|
1275
|
+
usage,
|
|
1276
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1277
|
+
};
|
|
988
1278
|
}
|
|
989
1279
|
async *stream(request) {
|
|
990
1280
|
throwIfAborted(request.signal);
|