@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,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,7 +641,120 @@ 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 responseReplayMetadata(metadata) {
|
|
692
|
+
const response = metadata?.openai?.response;
|
|
693
|
+
if (!response) return metadata;
|
|
694
|
+
const output = response.output.map((item) => {
|
|
695
|
+
const fields = ["type", "id", "status"];
|
|
696
|
+
switch (item.type) {
|
|
697
|
+
case "reasoning":
|
|
698
|
+
fields.push("encrypted_content");
|
|
699
|
+
break;
|
|
700
|
+
case "message":
|
|
701
|
+
fields.push("role", "phase");
|
|
702
|
+
break;
|
|
703
|
+
case "function_call":
|
|
704
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
705
|
+
break;
|
|
706
|
+
case "tool_search_call":
|
|
707
|
+
fields.push("call_id", "execution", "arguments");
|
|
708
|
+
break;
|
|
709
|
+
case "tool_search_output":
|
|
710
|
+
fields.push("call_id", "tools");
|
|
711
|
+
break;
|
|
712
|
+
case "web_search_call":
|
|
713
|
+
fields.push("action");
|
|
714
|
+
break;
|
|
715
|
+
default:
|
|
716
|
+
return stripItemDiagnostics(item);
|
|
717
|
+
}
|
|
718
|
+
const replay = Object.fromEntries(
|
|
719
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
720
|
+
);
|
|
721
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
722
|
+
if (item.type === "message")
|
|
723
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
724
|
+
(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 }] : []
|
|
725
|
+
) : [];
|
|
726
|
+
return stripItemDiagnostics(replay);
|
|
727
|
+
});
|
|
728
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
729
|
+
}
|
|
730
|
+
function stripItemDiagnostics(item) {
|
|
731
|
+
const {
|
|
732
|
+
usage: _usage,
|
|
733
|
+
logprobs: _logprobs,
|
|
734
|
+
metadata: _metadata,
|
|
735
|
+
...state
|
|
736
|
+
} = item;
|
|
737
|
+
return state;
|
|
738
|
+
}
|
|
739
|
+
function getResponseReplay(metadata) {
|
|
740
|
+
const response = metadata?.openai?.response;
|
|
741
|
+
if (response === void 0) return void 0;
|
|
742
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
743
|
+
throw new Error(
|
|
744
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
748
|
+
}
|
|
749
|
+
|
|
539
750
|
// src/core/provider-error.ts
|
|
751
|
+
function invalidProviderResponse(message) {
|
|
752
|
+
return Object.assign(new Error(message), {
|
|
753
|
+
name: "InvalidProviderResponseError",
|
|
754
|
+
status: 502,
|
|
755
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
756
|
+
});
|
|
757
|
+
}
|
|
540
758
|
function providerErrorEvent(error, code) {
|
|
541
759
|
const details = error ?? {};
|
|
542
760
|
const event = {
|
|
@@ -612,13 +830,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
612
830
|
}));
|
|
613
831
|
}
|
|
614
832
|
shouldUseResponsesApi(request) {
|
|
615
|
-
|
|
616
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
617
|
-
return true;
|
|
618
|
-
return requiresOpenAIResponses(
|
|
833
|
+
return useOpenAIResponses(
|
|
619
834
|
request.config?.model || this.model,
|
|
620
835
|
this.config.baseUrl,
|
|
621
|
-
this.parameterOptions(request)
|
|
836
|
+
this.parameterOptions(request),
|
|
837
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
838
|
+
this.toolDefinitions(request).length > 0,
|
|
839
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
840
|
+
(message) => message.providerMetadata?.openai?.response
|
|
841
|
+
),
|
|
842
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
622
843
|
);
|
|
623
844
|
}
|
|
624
845
|
/**
|
|
@@ -651,11 +872,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
651
872
|
});
|
|
652
873
|
}
|
|
653
874
|
buildResponsesInput(request) {
|
|
654
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
875
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
655
876
|
const input = [];
|
|
656
877
|
for (const message of sourceMessages) {
|
|
657
878
|
if (message.role === "system") {
|
|
658
|
-
if (
|
|
879
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
659
880
|
input.push({
|
|
660
881
|
type: "message",
|
|
661
882
|
role: "developer",
|
|
@@ -665,6 +886,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
665
886
|
continue;
|
|
666
887
|
}
|
|
667
888
|
if (message.role === "assistant") {
|
|
889
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
890
|
+
if (replay) {
|
|
891
|
+
input.push(...replay);
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
668
894
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
669
895
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
670
896
|
input.push({
|
|
@@ -688,7 +914,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
688
914
|
input.push({
|
|
689
915
|
type: "function_call_output",
|
|
690
916
|
call_id: message.tool_call_id,
|
|
691
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
917
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
692
918
|
});
|
|
693
919
|
continue;
|
|
694
920
|
}
|
|
@@ -702,10 +928,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
702
928
|
return input;
|
|
703
929
|
}
|
|
704
930
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
705
|
-
formatRawMessages(messages) {
|
|
931
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
706
932
|
return messages.map((message) => {
|
|
707
|
-
const { attachments, ...rest } = message;
|
|
708
|
-
let content = message.content;
|
|
933
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
934
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
935
|
+
if (preserveProviderMetadata && modelOutput)
|
|
936
|
+
rest.modelOutput = modelOutput;
|
|
709
937
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
710
938
|
content = null;
|
|
711
939
|
}
|
|
@@ -718,7 +946,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
718
946
|
content = [...parts, ...images];
|
|
719
947
|
}
|
|
720
948
|
}
|
|
721
|
-
return {
|
|
949
|
+
return {
|
|
950
|
+
...rest,
|
|
951
|
+
content,
|
|
952
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
953
|
+
};
|
|
722
954
|
});
|
|
723
955
|
}
|
|
724
956
|
/**
|
|
@@ -799,14 +1031,40 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
799
1031
|
).map((part) => part.text) : []
|
|
800
1032
|
).join("") : "";
|
|
801
1033
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
name
|
|
805
|
-
|
|
806
|
-
|
|
1034
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
1035
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
1036
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
1037
|
+
throw invalidProviderResponse(
|
|
1038
|
+
"Responses contains an incomplete function call"
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
if (seenCallIds.has(item.call_id))
|
|
1042
|
+
throw invalidProviderResponse(
|
|
1043
|
+
"Responses contains duplicate function call IDs"
|
|
1044
|
+
);
|
|
1045
|
+
seenCallIds.add(item.call_id);
|
|
1046
|
+
let args;
|
|
1047
|
+
try {
|
|
1048
|
+
args = JSON.parse(item.arguments);
|
|
1049
|
+
} catch {
|
|
1050
|
+
throw invalidProviderResponse(
|
|
1051
|
+
"Responses function arguments must be valid JSON"
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1054
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1055
|
+
throw invalidProviderResponse(
|
|
1056
|
+
"Responses function arguments must be a JSON object"
|
|
1057
|
+
);
|
|
1058
|
+
return {
|
|
1059
|
+
id: item.call_id,
|
|
1060
|
+
name: item.name,
|
|
1061
|
+
args
|
|
1062
|
+
};
|
|
1063
|
+
}) : [];
|
|
807
1064
|
return {
|
|
808
1065
|
content,
|
|
809
1066
|
toolCalls,
|
|
1067
|
+
providerMetadata: responseMetadata(response),
|
|
810
1068
|
usage: response?.usage ? {
|
|
811
1069
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
812
1070
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -817,6 +1075,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
817
1075
|
}
|
|
818
1076
|
buildResponsesPayload(request, stream) {
|
|
819
1077
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1078
|
+
const options = resolveOpenAITransport(
|
|
1079
|
+
this.config,
|
|
1080
|
+
request.config?.openai
|
|
1081
|
+
).responses;
|
|
1082
|
+
const parameters = buildOpenAIParameters(
|
|
1083
|
+
request.config?.model || this.model,
|
|
1084
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1085
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1086
|
+
this.parameterOptions(request),
|
|
1087
|
+
"responses"
|
|
1088
|
+
);
|
|
820
1089
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
821
1090
|
request.config?.responseFormat
|
|
822
1091
|
);
|
|
@@ -832,13 +1101,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
832
1101
|
),
|
|
833
1102
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
834
1103
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
835
|
-
...
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
1104
|
+
...parameters,
|
|
1105
|
+
...options?.reasoningSummary ? {
|
|
1106
|
+
reasoning: {
|
|
1107
|
+
...parameters.reasoning,
|
|
1108
|
+
summary: options.reasoningSummary
|
|
1109
|
+
}
|
|
1110
|
+
} : {},
|
|
1111
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1112
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1113
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1114
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1115
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1116
|
+
...options?.store === false || options?.include ? {
|
|
1117
|
+
include: [
|
|
1118
|
+
.../* @__PURE__ */ new Set([
|
|
1119
|
+
...options?.include ?? [],
|
|
1120
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1121
|
+
])
|
|
1122
|
+
]
|
|
1123
|
+
} : {},
|
|
842
1124
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
843
1125
|
stream
|
|
844
1126
|
};
|
|
@@ -897,6 +1179,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
897
1179
|
let usage;
|
|
898
1180
|
const citations = [];
|
|
899
1181
|
let completed = false;
|
|
1182
|
+
let terminalResponse;
|
|
1183
|
+
let responseIdentity = {};
|
|
1184
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1185
|
+
let streamedText = "";
|
|
900
1186
|
function* flushToolCalls() {
|
|
901
1187
|
for (const call of toolCalls.values()) {
|
|
902
1188
|
if (!call.name)
|
|
@@ -913,17 +1199,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
913
1199
|
for await (const event of stream) {
|
|
914
1200
|
throwIfAborted(request.signal);
|
|
915
1201
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1202
|
+
if (completed)
|
|
1203
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
916
1204
|
const index = event?.output_index ?? 0;
|
|
917
1205
|
switch (event?.type) {
|
|
1206
|
+
case "response.created":
|
|
1207
|
+
responseIdentity = {
|
|
1208
|
+
id: event.response?.id,
|
|
1209
|
+
model: event.response?.model
|
|
1210
|
+
};
|
|
1211
|
+
break;
|
|
1212
|
+
case "response.output_item.done":
|
|
1213
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1214
|
+
if (event.item?.type === "function_call") {
|
|
1215
|
+
toolCalls.set(index, {
|
|
1216
|
+
id: event.item.call_id,
|
|
1217
|
+
name: event.item.name,
|
|
1218
|
+
arguments: event.item.arguments
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
break;
|
|
918
1222
|
case "response.output_text.delta":
|
|
919
1223
|
if (event.delta) {
|
|
1224
|
+
streamedText += event.delta;
|
|
920
1225
|
yield { type: "message:delta", content: event.delta };
|
|
921
1226
|
}
|
|
922
1227
|
break;
|
|
923
1228
|
case "response.output_item.added":
|
|
924
1229
|
if (event.item?.type === "function_call") {
|
|
925
1230
|
toolCalls.set(index, {
|
|
926
|
-
id: event.item.call_id ??
|
|
1231
|
+
id: event.item.call_id ?? "",
|
|
927
1232
|
name: event.item.name ?? "",
|
|
928
1233
|
arguments: event.item.arguments ?? ""
|
|
929
1234
|
});
|
|
@@ -942,7 +1247,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
942
1247
|
break;
|
|
943
1248
|
}
|
|
944
1249
|
case "response.completed": {
|
|
1250
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1251
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
945
1252
|
completed = true;
|
|
1253
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
946
1254
|
const found = this.collectResponsesCitations(
|
|
947
1255
|
event.response?.output,
|
|
948
1256
|
citations.length
|
|
@@ -979,12 +1287,66 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
979
1287
|
throwIfAborted(request.signal);
|
|
980
1288
|
if (!completed)
|
|
981
1289
|
throw new Error("Responses stream ended without a completed response");
|
|
1290
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1291
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1292
|
+
toolCalls.clear();
|
|
1293
|
+
for (const [index, item] of output.entries()) {
|
|
1294
|
+
if (item.type === "function_call") {
|
|
1295
|
+
toolCalls.set(index, {
|
|
1296
|
+
id: item.call_id,
|
|
1297
|
+
name: item.name,
|
|
1298
|
+
arguments: item.arguments
|
|
1299
|
+
});
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1303
|
+
for (const call of toolCalls.values()) {
|
|
1304
|
+
if (!call.id || !call.name)
|
|
1305
|
+
throw invalidProviderResponse(
|
|
1306
|
+
"Responses stream contains an incomplete tool call"
|
|
1307
|
+
);
|
|
1308
|
+
uniqueCalls.set(call.id, call);
|
|
1309
|
+
}
|
|
1310
|
+
toolCalls.clear();
|
|
1311
|
+
[...uniqueCalls.values()].forEach(
|
|
1312
|
+
(call, index) => toolCalls.set(index, call)
|
|
1313
|
+
);
|
|
1314
|
+
if (!output.length && toolCalls.size) {
|
|
1315
|
+
for (const call of toolCalls.values())
|
|
1316
|
+
output.push({
|
|
1317
|
+
type: "function_call",
|
|
1318
|
+
call_id: call.id,
|
|
1319
|
+
name: call.name,
|
|
1320
|
+
arguments: call.arguments
|
|
1321
|
+
});
|
|
1322
|
+
}
|
|
1323
|
+
if (!output.length && streamedText)
|
|
1324
|
+
output.push({
|
|
1325
|
+
type: "message",
|
|
1326
|
+
role: "assistant",
|
|
1327
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1328
|
+
});
|
|
1329
|
+
terminalResponse.output = output;
|
|
1330
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1331
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1332
|
+
yield {
|
|
1333
|
+
type: "message:delta",
|
|
1334
|
+
content: finalText.slice(streamedText.length)
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
982
1337
|
yield* flushToolCalls();
|
|
983
1338
|
if (citations.length > 0) {
|
|
984
1339
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
985
1340
|
}
|
|
986
|
-
yield {
|
|
987
|
-
|
|
1341
|
+
yield {
|
|
1342
|
+
type: "message:end",
|
|
1343
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1344
|
+
};
|
|
1345
|
+
yield {
|
|
1346
|
+
type: "done",
|
|
1347
|
+
usage,
|
|
1348
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1349
|
+
};
|
|
988
1350
|
}
|
|
989
1351
|
async *stream(request) {
|
|
990
1352
|
throwIfAborted(request.signal);
|