@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,3 +1,106 @@
|
|
|
1
|
+
// src/core/tool-output.ts
|
|
2
|
+
var imageTypes = /* @__PURE__ */ new Set([
|
|
3
|
+
"image/png",
|
|
4
|
+
"image/jpeg",
|
|
5
|
+
"image/webp",
|
|
6
|
+
"image/gif"
|
|
7
|
+
]);
|
|
8
|
+
function normalizeToolOutput(value) {
|
|
9
|
+
const output = value;
|
|
10
|
+
if (output?.type !== "content" || !Array.isArray(output.content) || !output.content.length) {
|
|
11
|
+
throw new Error("Tool model output must contain a nonempty content array");
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
type: "content",
|
|
15
|
+
content: output.content.map((part) => {
|
|
16
|
+
if (part?.type === "text" && typeof part.text === "string")
|
|
17
|
+
return { type: "text", text: part.text };
|
|
18
|
+
if (part?.type !== "image")
|
|
19
|
+
throw new Error("Unsupported tool output content type");
|
|
20
|
+
const sources = ["data", "url", "fileId"].filter((key) => key in part);
|
|
21
|
+
if (sources.length !== 1)
|
|
22
|
+
throw new Error(
|
|
23
|
+
"Tool image requires exactly one of data, url, or fileId"
|
|
24
|
+
);
|
|
25
|
+
if ("fileId" in part) {
|
|
26
|
+
if (part.provider !== "openai" || typeof part.fileId !== "string" || !part.fileId.trim())
|
|
27
|
+
throw new Error(
|
|
28
|
+
"Tool image file references must name the openai provider and fileId"
|
|
29
|
+
);
|
|
30
|
+
return { type: "image", fileId: part.fileId, provider: "openai" };
|
|
31
|
+
}
|
|
32
|
+
if ("url" in part) {
|
|
33
|
+
let url;
|
|
34
|
+
try {
|
|
35
|
+
url = new URL(part.url);
|
|
36
|
+
} catch {
|
|
37
|
+
throw new Error("Invalid tool image URL");
|
|
38
|
+
}
|
|
39
|
+
if (!["https:", "http:"].includes(url.protocol) || url.username || url.password)
|
|
40
|
+
throw new Error(
|
|
41
|
+
"Tool image URL must use HTTP(S) without credentials"
|
|
42
|
+
);
|
|
43
|
+
return { type: "image", url: url.href };
|
|
44
|
+
}
|
|
45
|
+
if (!("data" in part) || !imageTypes.has(part.mediaType))
|
|
46
|
+
throw new Error("Unsupported tool image media type");
|
|
47
|
+
let data = part.data instanceof Uint8Array ? Buffer.from(part.data).toString("base64") : part.data;
|
|
48
|
+
if (typeof data !== "string")
|
|
49
|
+
throw new Error("Tool image data must be base64 or bytes");
|
|
50
|
+
if (data.startsWith("data:")) {
|
|
51
|
+
const match = /^data:([^;,]+);base64,(.+)$/.exec(data);
|
|
52
|
+
if (!match || match[1] !== part.mediaType)
|
|
53
|
+
throw new Error(
|
|
54
|
+
"Tool image data URL media type does not match mediaType"
|
|
55
|
+
);
|
|
56
|
+
data = match[2];
|
|
57
|
+
}
|
|
58
|
+
if (!data.length || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(data))
|
|
59
|
+
throw new Error("Invalid tool image base64 data");
|
|
60
|
+
if (Buffer.byteLength(data, "base64") > 20 * 1024 * 1024)
|
|
61
|
+
throw new Error("Tool image exceeds 20 MiB");
|
|
62
|
+
if (Buffer.from(data, "base64").toString("base64") !== data)
|
|
63
|
+
throw new Error("Invalid tool image base64 data");
|
|
64
|
+
return { type: "image", data, mediaType: part.mediaType };
|
|
65
|
+
})
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function toolOutputForProvider(value, provider) {
|
|
69
|
+
const output = normalizeToolOutput(value);
|
|
70
|
+
return output.content.map((part) => {
|
|
71
|
+
if (part.type === "text")
|
|
72
|
+
return {
|
|
73
|
+
type: provider === "responses" ? "input_text" : "text",
|
|
74
|
+
text: part.text
|
|
75
|
+
};
|
|
76
|
+
if (provider === "unsupported")
|
|
77
|
+
throw new Error(
|
|
78
|
+
"Image tool results require OpenAI Responses or Anthropic; this endpoint is not supported"
|
|
79
|
+
);
|
|
80
|
+
if ("fileId" in part) {
|
|
81
|
+
if (provider !== "responses")
|
|
82
|
+
throw new Error(
|
|
83
|
+
"OpenAI image file references cannot be sent to another provider"
|
|
84
|
+
);
|
|
85
|
+
return { type: "input_image", file_id: part.fileId, detail: "auto" };
|
|
86
|
+
}
|
|
87
|
+
if (provider === "responses")
|
|
88
|
+
return {
|
|
89
|
+
type: "input_image",
|
|
90
|
+
image_url: "url" in part ? part.url : `data:${part.mediaType};base64,${part.data}`,
|
|
91
|
+
detail: "auto"
|
|
92
|
+
};
|
|
93
|
+
return {
|
|
94
|
+
type: "image",
|
|
95
|
+
source: "url" in part ? { type: "url", url: part.url } : { type: "base64", media_type: part.mediaType, data: part.data }
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function textToolOutput(value, fallback) {
|
|
100
|
+
if (value === void 0) return fallback;
|
|
101
|
+
return toolOutputForProvider(value, "unsupported").map((part) => part.text).join("\n");
|
|
102
|
+
}
|
|
103
|
+
|
|
1
104
|
// src/core/openai-parameters.ts
|
|
2
105
|
function capabilities(model) {
|
|
3
106
|
const gpt = /^gpt-(\d+)(?:\.(\d+))?(?:-(.+))?$/i.exec(model);
|
|
@@ -239,7 +342,7 @@ function messageToOpenAIContent(message) {
|
|
|
239
342
|
}
|
|
240
343
|
return blocks;
|
|
241
344
|
}
|
|
242
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
345
|
+
function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
|
|
243
346
|
const formatted = [];
|
|
244
347
|
if (systemPrompt) {
|
|
245
348
|
formatted.push({ role: "system", content: systemPrompt });
|
|
@@ -257,7 +360,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
257
360
|
const assistantMsg = {
|
|
258
361
|
role: "assistant",
|
|
259
362
|
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
260
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
363
|
+
content: hasToolCalls ? msg.content || null : msg.content,
|
|
364
|
+
...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
|
|
261
365
|
};
|
|
262
366
|
if (hasToolCalls) {
|
|
263
367
|
assistantMsg.tool_calls = msg.tool_calls;
|
|
@@ -266,7 +370,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
266
370
|
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
267
371
|
formatted.push({
|
|
268
372
|
role: "tool",
|
|
269
|
-
content: msg.content ?? "",
|
|
373
|
+
content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
|
|
374
|
+
...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
|
|
270
375
|
tool_call_id: msg.tool_call_id
|
|
271
376
|
});
|
|
272
377
|
}
|
|
@@ -473,7 +578,7 @@ function formatMessages(messages) {
|
|
|
473
578
|
return {
|
|
474
579
|
role: "tool",
|
|
475
580
|
tool_call_id: msg.toolCallId,
|
|
476
|
-
content: msg.content
|
|
581
|
+
content: textToolOutput(msg.modelOutput, msg.content)
|
|
477
582
|
};
|
|
478
583
|
default:
|
|
479
584
|
return msg;
|
|
@@ -481,7 +586,120 @@ function formatMessages(messages) {
|
|
|
481
586
|
});
|
|
482
587
|
}
|
|
483
588
|
|
|
589
|
+
// src/core/openai-responses.ts
|
|
590
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
591
|
+
return {
|
|
592
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
593
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
597
|
+
const api = transport.api ?? "auto";
|
|
598
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
599
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
600
|
+
}
|
|
601
|
+
if (api === "chat") {
|
|
602
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
603
|
+
throw new Error(
|
|
604
|
+
"Responses options and native tool search require the Responses API"
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
let officialEndpoint = !baseURL;
|
|
610
|
+
try {
|
|
611
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
612
|
+
} catch {
|
|
613
|
+
}
|
|
614
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
615
|
+
}
|
|
616
|
+
function responseMetadata(response) {
|
|
617
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
618
|
+
return {
|
|
619
|
+
openai: {
|
|
620
|
+
response: {
|
|
621
|
+
id: response?.id,
|
|
622
|
+
model: response?.model,
|
|
623
|
+
status: response?.status,
|
|
624
|
+
output,
|
|
625
|
+
usage: response?.usage,
|
|
626
|
+
store: response?.store,
|
|
627
|
+
refusals: output.flatMap(
|
|
628
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
629
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
630
|
+
).map((part) => part.refusal) : []
|
|
631
|
+
)
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
function responseReplayMetadata(metadata) {
|
|
637
|
+
const response = metadata?.openai?.response;
|
|
638
|
+
if (!response) return metadata;
|
|
639
|
+
const output = response.output.map((item) => {
|
|
640
|
+
const fields = ["type", "id", "status"];
|
|
641
|
+
switch (item.type) {
|
|
642
|
+
case "reasoning":
|
|
643
|
+
fields.push("encrypted_content");
|
|
644
|
+
break;
|
|
645
|
+
case "message":
|
|
646
|
+
fields.push("role", "phase");
|
|
647
|
+
break;
|
|
648
|
+
case "function_call":
|
|
649
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
650
|
+
break;
|
|
651
|
+
case "tool_search_call":
|
|
652
|
+
fields.push("call_id", "execution", "arguments");
|
|
653
|
+
break;
|
|
654
|
+
case "tool_search_output":
|
|
655
|
+
fields.push("call_id", "tools");
|
|
656
|
+
break;
|
|
657
|
+
case "web_search_call":
|
|
658
|
+
fields.push("action");
|
|
659
|
+
break;
|
|
660
|
+
default:
|
|
661
|
+
return stripItemDiagnostics(item);
|
|
662
|
+
}
|
|
663
|
+
const replay = Object.fromEntries(
|
|
664
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
665
|
+
);
|
|
666
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
667
|
+
if (item.type === "message")
|
|
668
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
669
|
+
(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 }] : []
|
|
670
|
+
) : [];
|
|
671
|
+
return stripItemDiagnostics(replay);
|
|
672
|
+
});
|
|
673
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
674
|
+
}
|
|
675
|
+
function stripItemDiagnostics(item) {
|
|
676
|
+
const {
|
|
677
|
+
usage: _usage,
|
|
678
|
+
logprobs: _logprobs,
|
|
679
|
+
metadata: _metadata,
|
|
680
|
+
...state
|
|
681
|
+
} = item;
|
|
682
|
+
return state;
|
|
683
|
+
}
|
|
684
|
+
function getResponseReplay(metadata) {
|
|
685
|
+
const response = metadata?.openai?.response;
|
|
686
|
+
if (response === void 0) return void 0;
|
|
687
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
688
|
+
throw new Error(
|
|
689
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
690
|
+
);
|
|
691
|
+
}
|
|
692
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
693
|
+
}
|
|
694
|
+
|
|
484
695
|
// src/core/provider-error.ts
|
|
696
|
+
function invalidProviderResponse(message) {
|
|
697
|
+
return Object.assign(new Error(message), {
|
|
698
|
+
name: "InvalidProviderResponseError",
|
|
699
|
+
status: 502,
|
|
700
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
701
|
+
});
|
|
702
|
+
}
|
|
485
703
|
function providerErrorEvent(error, code) {
|
|
486
704
|
const details = error ?? {};
|
|
487
705
|
const event = {
|
|
@@ -557,13 +775,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
557
775
|
}));
|
|
558
776
|
}
|
|
559
777
|
shouldUseResponsesApi(request) {
|
|
560
|
-
|
|
561
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
562
|
-
return true;
|
|
563
|
-
return requiresOpenAIResponses(
|
|
778
|
+
return useOpenAIResponses(
|
|
564
779
|
request.config?.model || this.model,
|
|
565
780
|
this.config.baseUrl,
|
|
566
|
-
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
|
|
567
788
|
);
|
|
568
789
|
}
|
|
569
790
|
/**
|
|
@@ -596,11 +817,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
596
817
|
});
|
|
597
818
|
}
|
|
598
819
|
buildResponsesInput(request) {
|
|
599
|
-
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);
|
|
600
821
|
const input = [];
|
|
601
822
|
for (const message of sourceMessages) {
|
|
602
823
|
if (message.role === "system") {
|
|
603
|
-
if (
|
|
824
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
604
825
|
input.push({
|
|
605
826
|
type: "message",
|
|
606
827
|
role: "developer",
|
|
@@ -610,6 +831,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
610
831
|
continue;
|
|
611
832
|
}
|
|
612
833
|
if (message.role === "assistant") {
|
|
834
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
835
|
+
if (replay) {
|
|
836
|
+
input.push(...replay);
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
613
839
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
614
840
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
615
841
|
input.push({
|
|
@@ -633,7 +859,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
633
859
|
input.push({
|
|
634
860
|
type: "function_call_output",
|
|
635
861
|
call_id: message.tool_call_id,
|
|
636
|
-
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)
|
|
637
863
|
});
|
|
638
864
|
continue;
|
|
639
865
|
}
|
|
@@ -647,10 +873,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
647
873
|
return input;
|
|
648
874
|
}
|
|
649
875
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
650
|
-
formatRawMessages(messages) {
|
|
876
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
651
877
|
return messages.map((message) => {
|
|
652
|
-
const { attachments, ...rest } = message;
|
|
653
|
-
let content = message.content;
|
|
878
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
879
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
880
|
+
if (preserveProviderMetadata && modelOutput)
|
|
881
|
+
rest.modelOutput = modelOutput;
|
|
654
882
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
655
883
|
content = null;
|
|
656
884
|
}
|
|
@@ -663,7 +891,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
663
891
|
content = [...parts, ...images];
|
|
664
892
|
}
|
|
665
893
|
}
|
|
666
|
-
return {
|
|
894
|
+
return {
|
|
895
|
+
...rest,
|
|
896
|
+
content,
|
|
897
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
898
|
+
};
|
|
667
899
|
});
|
|
668
900
|
}
|
|
669
901
|
/**
|
|
@@ -744,14 +976,40 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
744
976
|
).map((part) => part.text) : []
|
|
745
977
|
).join("") : "";
|
|
746
978
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
747
|
-
const
|
|
748
|
-
|
|
749
|
-
name
|
|
750
|
-
|
|
751
|
-
|
|
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 invalidProviderResponse(
|
|
983
|
+
"Responses contains an incomplete function call"
|
|
984
|
+
);
|
|
985
|
+
}
|
|
986
|
+
if (seenCallIds.has(item.call_id))
|
|
987
|
+
throw invalidProviderResponse(
|
|
988
|
+
"Responses contains duplicate function call IDs"
|
|
989
|
+
);
|
|
990
|
+
seenCallIds.add(item.call_id);
|
|
991
|
+
let args;
|
|
992
|
+
try {
|
|
993
|
+
args = JSON.parse(item.arguments);
|
|
994
|
+
} catch {
|
|
995
|
+
throw invalidProviderResponse(
|
|
996
|
+
"Responses function arguments must be valid JSON"
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1000
|
+
throw invalidProviderResponse(
|
|
1001
|
+
"Responses function arguments must be a JSON object"
|
|
1002
|
+
);
|
|
1003
|
+
return {
|
|
1004
|
+
id: item.call_id,
|
|
1005
|
+
name: item.name,
|
|
1006
|
+
args
|
|
1007
|
+
};
|
|
1008
|
+
}) : [];
|
|
752
1009
|
return {
|
|
753
1010
|
content,
|
|
754
1011
|
toolCalls,
|
|
1012
|
+
providerMetadata: responseMetadata(response),
|
|
755
1013
|
usage: response?.usage ? {
|
|
756
1014
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
757
1015
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -762,6 +1020,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
762
1020
|
}
|
|
763
1021
|
buildResponsesPayload(request, stream) {
|
|
764
1022
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1023
|
+
const options = resolveOpenAITransport(
|
|
1024
|
+
this.config,
|
|
1025
|
+
request.config?.openai
|
|
1026
|
+
).responses;
|
|
1027
|
+
const parameters = buildOpenAIParameters(
|
|
1028
|
+
request.config?.model || this.model,
|
|
1029
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1030
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1031
|
+
this.parameterOptions(request),
|
|
1032
|
+
"responses"
|
|
1033
|
+
);
|
|
765
1034
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
766
1035
|
request.config?.responseFormat
|
|
767
1036
|
);
|
|
@@ -777,13 +1046,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
777
1046
|
),
|
|
778
1047
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
779
1048
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
780
|
-
...
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
1049
|
+
...parameters,
|
|
1050
|
+
...options?.reasoningSummary ? {
|
|
1051
|
+
reasoning: {
|
|
1052
|
+
...parameters.reasoning,
|
|
1053
|
+
summary: options.reasoningSummary
|
|
1054
|
+
}
|
|
1055
|
+
} : {},
|
|
1056
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1057
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1058
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1059
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1060
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1061
|
+
...options?.store === false || options?.include ? {
|
|
1062
|
+
include: [
|
|
1063
|
+
.../* @__PURE__ */ new Set([
|
|
1064
|
+
...options?.include ?? [],
|
|
1065
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1066
|
+
])
|
|
1067
|
+
]
|
|
1068
|
+
} : {},
|
|
787
1069
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
788
1070
|
stream
|
|
789
1071
|
};
|
|
@@ -842,6 +1124,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
842
1124
|
let usage;
|
|
843
1125
|
const citations = [];
|
|
844
1126
|
let completed = false;
|
|
1127
|
+
let terminalResponse;
|
|
1128
|
+
let responseIdentity = {};
|
|
1129
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1130
|
+
let streamedText = "";
|
|
845
1131
|
function* flushToolCalls() {
|
|
846
1132
|
for (const call of toolCalls.values()) {
|
|
847
1133
|
if (!call.name)
|
|
@@ -858,17 +1144,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
858
1144
|
for await (const event of stream) {
|
|
859
1145
|
throwIfAborted(request.signal);
|
|
860
1146
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1147
|
+
if (completed)
|
|
1148
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
861
1149
|
const index = event?.output_index ?? 0;
|
|
862
1150
|
switch (event?.type) {
|
|
1151
|
+
case "response.created":
|
|
1152
|
+
responseIdentity = {
|
|
1153
|
+
id: event.response?.id,
|
|
1154
|
+
model: event.response?.model
|
|
1155
|
+
};
|
|
1156
|
+
break;
|
|
1157
|
+
case "response.output_item.done":
|
|
1158
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1159
|
+
if (event.item?.type === "function_call") {
|
|
1160
|
+
toolCalls.set(index, {
|
|
1161
|
+
id: event.item.call_id,
|
|
1162
|
+
name: event.item.name,
|
|
1163
|
+
arguments: event.item.arguments
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
break;
|
|
863
1167
|
case "response.output_text.delta":
|
|
864
1168
|
if (event.delta) {
|
|
1169
|
+
streamedText += event.delta;
|
|
865
1170
|
yield { type: "message:delta", content: event.delta };
|
|
866
1171
|
}
|
|
867
1172
|
break;
|
|
868
1173
|
case "response.output_item.added":
|
|
869
1174
|
if (event.item?.type === "function_call") {
|
|
870
1175
|
toolCalls.set(index, {
|
|
871
|
-
id: event.item.call_id ??
|
|
1176
|
+
id: event.item.call_id ?? "",
|
|
872
1177
|
name: event.item.name ?? "",
|
|
873
1178
|
arguments: event.item.arguments ?? ""
|
|
874
1179
|
});
|
|
@@ -887,7 +1192,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
887
1192
|
break;
|
|
888
1193
|
}
|
|
889
1194
|
case "response.completed": {
|
|
1195
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1196
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
890
1197
|
completed = true;
|
|
1198
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
891
1199
|
const found = this.collectResponsesCitations(
|
|
892
1200
|
event.response?.output,
|
|
893
1201
|
citations.length
|
|
@@ -924,12 +1232,66 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
924
1232
|
throwIfAborted(request.signal);
|
|
925
1233
|
if (!completed)
|
|
926
1234
|
throw new Error("Responses stream ended without a completed response");
|
|
1235
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1236
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1237
|
+
toolCalls.clear();
|
|
1238
|
+
for (const [index, item] of output.entries()) {
|
|
1239
|
+
if (item.type === "function_call") {
|
|
1240
|
+
toolCalls.set(index, {
|
|
1241
|
+
id: item.call_id,
|
|
1242
|
+
name: item.name,
|
|
1243
|
+
arguments: item.arguments
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1248
|
+
for (const call of toolCalls.values()) {
|
|
1249
|
+
if (!call.id || !call.name)
|
|
1250
|
+
throw invalidProviderResponse(
|
|
1251
|
+
"Responses stream contains an incomplete tool call"
|
|
1252
|
+
);
|
|
1253
|
+
uniqueCalls.set(call.id, call);
|
|
1254
|
+
}
|
|
1255
|
+
toolCalls.clear();
|
|
1256
|
+
[...uniqueCalls.values()].forEach(
|
|
1257
|
+
(call, index) => toolCalls.set(index, call)
|
|
1258
|
+
);
|
|
1259
|
+
if (!output.length && toolCalls.size) {
|
|
1260
|
+
for (const call of toolCalls.values())
|
|
1261
|
+
output.push({
|
|
1262
|
+
type: "function_call",
|
|
1263
|
+
call_id: call.id,
|
|
1264
|
+
name: call.name,
|
|
1265
|
+
arguments: call.arguments
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
if (!output.length && streamedText)
|
|
1269
|
+
output.push({
|
|
1270
|
+
type: "message",
|
|
1271
|
+
role: "assistant",
|
|
1272
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1273
|
+
});
|
|
1274
|
+
terminalResponse.output = output;
|
|
1275
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1276
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1277
|
+
yield {
|
|
1278
|
+
type: "message:delta",
|
|
1279
|
+
content: finalText.slice(streamedText.length)
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
927
1282
|
yield* flushToolCalls();
|
|
928
1283
|
if (citations.length > 0) {
|
|
929
1284
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
930
1285
|
}
|
|
931
|
-
yield {
|
|
932
|
-
|
|
1286
|
+
yield {
|
|
1287
|
+
type: "message:end",
|
|
1288
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1289
|
+
};
|
|
1290
|
+
yield {
|
|
1291
|
+
type: "done",
|
|
1292
|
+
usage,
|
|
1293
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1294
|
+
};
|
|
933
1295
|
}
|
|
934
1296
|
async *stream(request) {
|
|
935
1297
|
throwIfAborted(request.signal);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { G as GoogleProviderConfig, A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-Dg1Bcg1k.mjs';
|
|
2
|
+
import { G as GoogleProviderConfig, 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
|
* Google Provider - OpenAI-Compatible
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { L as LanguageModel } from '../../types-
|
|
2
|
-
import { G as GoogleProviderConfig, A as AIProvider } from '../../types-
|
|
1
|
+
import { L as LanguageModel } from '../../types-Dg1Bcg1k.js';
|
|
2
|
+
import { G as GoogleProviderConfig, 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
|
* Google Provider - OpenAI-Compatible
|