@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
|
}
|
|
@@ -504,7 +609,7 @@ function formatMessagesForXAI(messages) {
|
|
|
504
609
|
return {
|
|
505
610
|
role: "tool",
|
|
506
611
|
tool_call_id: msg.toolCallId,
|
|
507
|
-
content: msg.content
|
|
612
|
+
content: textToolOutput(msg.modelOutput, msg.content)
|
|
508
613
|
};
|
|
509
614
|
default:
|
|
510
615
|
return msg;
|
|
@@ -512,7 +617,120 @@ function formatMessagesForXAI(messages) {
|
|
|
512
617
|
});
|
|
513
618
|
}
|
|
514
619
|
|
|
620
|
+
// src/core/openai-responses.ts
|
|
621
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
622
|
+
return {
|
|
623
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
624
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
628
|
+
const api = transport.api ?? "auto";
|
|
629
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
630
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
631
|
+
}
|
|
632
|
+
if (api === "chat") {
|
|
633
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
634
|
+
throw new Error(
|
|
635
|
+
"Responses options and native tool search require the Responses API"
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
let officialEndpoint = !baseURL;
|
|
641
|
+
try {
|
|
642
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
643
|
+
} catch {
|
|
644
|
+
}
|
|
645
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
646
|
+
}
|
|
647
|
+
function responseMetadata(response) {
|
|
648
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
649
|
+
return {
|
|
650
|
+
openai: {
|
|
651
|
+
response: {
|
|
652
|
+
id: response?.id,
|
|
653
|
+
model: response?.model,
|
|
654
|
+
status: response?.status,
|
|
655
|
+
output,
|
|
656
|
+
usage: response?.usage,
|
|
657
|
+
store: response?.store,
|
|
658
|
+
refusals: output.flatMap(
|
|
659
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
660
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
661
|
+
).map((part) => part.refusal) : []
|
|
662
|
+
)
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
function responseReplayMetadata(metadata) {
|
|
668
|
+
const response = metadata?.openai?.response;
|
|
669
|
+
if (!response) return metadata;
|
|
670
|
+
const output = response.output.map((item) => {
|
|
671
|
+
const fields = ["type", "id", "status"];
|
|
672
|
+
switch (item.type) {
|
|
673
|
+
case "reasoning":
|
|
674
|
+
fields.push("encrypted_content");
|
|
675
|
+
break;
|
|
676
|
+
case "message":
|
|
677
|
+
fields.push("role", "phase");
|
|
678
|
+
break;
|
|
679
|
+
case "function_call":
|
|
680
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
681
|
+
break;
|
|
682
|
+
case "tool_search_call":
|
|
683
|
+
fields.push("call_id", "execution", "arguments");
|
|
684
|
+
break;
|
|
685
|
+
case "tool_search_output":
|
|
686
|
+
fields.push("call_id", "tools");
|
|
687
|
+
break;
|
|
688
|
+
case "web_search_call":
|
|
689
|
+
fields.push("action");
|
|
690
|
+
break;
|
|
691
|
+
default:
|
|
692
|
+
return stripItemDiagnostics(item);
|
|
693
|
+
}
|
|
694
|
+
const replay = Object.fromEntries(
|
|
695
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
696
|
+
);
|
|
697
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
698
|
+
if (item.type === "message")
|
|
699
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
700
|
+
(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 }] : []
|
|
701
|
+
) : [];
|
|
702
|
+
return stripItemDiagnostics(replay);
|
|
703
|
+
});
|
|
704
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
705
|
+
}
|
|
706
|
+
function stripItemDiagnostics(item) {
|
|
707
|
+
const {
|
|
708
|
+
usage: _usage,
|
|
709
|
+
logprobs: _logprobs,
|
|
710
|
+
metadata: _metadata,
|
|
711
|
+
...state
|
|
712
|
+
} = item;
|
|
713
|
+
return state;
|
|
714
|
+
}
|
|
715
|
+
function getResponseReplay(metadata) {
|
|
716
|
+
const response = metadata?.openai?.response;
|
|
717
|
+
if (response === void 0) return void 0;
|
|
718
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
719
|
+
throw new Error(
|
|
720
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
721
|
+
);
|
|
722
|
+
}
|
|
723
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
724
|
+
}
|
|
725
|
+
|
|
515
726
|
// src/core/provider-error.ts
|
|
727
|
+
function invalidProviderResponse(message) {
|
|
728
|
+
return Object.assign(new Error(message), {
|
|
729
|
+
name: "InvalidProviderResponseError",
|
|
730
|
+
status: 502,
|
|
731
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
732
|
+
});
|
|
733
|
+
}
|
|
516
734
|
function providerErrorEvent(error, code) {
|
|
517
735
|
const details = error ?? {};
|
|
518
736
|
const event = {
|
|
@@ -588,13 +806,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
588
806
|
}));
|
|
589
807
|
}
|
|
590
808
|
shouldUseResponsesApi(request) {
|
|
591
|
-
|
|
592
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
593
|
-
return true;
|
|
594
|
-
return requiresOpenAIResponses(
|
|
809
|
+
return useOpenAIResponses(
|
|
595
810
|
request.config?.model || this.model,
|
|
596
811
|
this.config.baseUrl,
|
|
597
|
-
this.parameterOptions(request)
|
|
812
|
+
this.parameterOptions(request),
|
|
813
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
814
|
+
this.toolDefinitions(request).length > 0,
|
|
815
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
816
|
+
(message) => message.providerMetadata?.openai?.response
|
|
817
|
+
),
|
|
818
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
598
819
|
);
|
|
599
820
|
}
|
|
600
821
|
/**
|
|
@@ -627,11 +848,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
627
848
|
});
|
|
628
849
|
}
|
|
629
850
|
buildResponsesInput(request) {
|
|
630
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
851
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
631
852
|
const input = [];
|
|
632
853
|
for (const message of sourceMessages) {
|
|
633
854
|
if (message.role === "system") {
|
|
634
|
-
if (
|
|
855
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
635
856
|
input.push({
|
|
636
857
|
type: "message",
|
|
637
858
|
role: "developer",
|
|
@@ -641,6 +862,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
641
862
|
continue;
|
|
642
863
|
}
|
|
643
864
|
if (message.role === "assistant") {
|
|
865
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
866
|
+
if (replay) {
|
|
867
|
+
input.push(...replay);
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
644
870
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
645
871
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
646
872
|
input.push({
|
|
@@ -664,7 +890,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
664
890
|
input.push({
|
|
665
891
|
type: "function_call_output",
|
|
666
892
|
call_id: message.tool_call_id,
|
|
667
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
893
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
668
894
|
});
|
|
669
895
|
continue;
|
|
670
896
|
}
|
|
@@ -678,10 +904,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
678
904
|
return input;
|
|
679
905
|
}
|
|
680
906
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
681
|
-
formatRawMessages(messages) {
|
|
907
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
682
908
|
return messages.map((message) => {
|
|
683
|
-
const { attachments, ...rest } = message;
|
|
684
|
-
let content = message.content;
|
|
909
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
910
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
911
|
+
if (preserveProviderMetadata && modelOutput)
|
|
912
|
+
rest.modelOutput = modelOutput;
|
|
685
913
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
686
914
|
content = null;
|
|
687
915
|
}
|
|
@@ -694,7 +922,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
694
922
|
content = [...parts, ...images];
|
|
695
923
|
}
|
|
696
924
|
}
|
|
697
|
-
return {
|
|
925
|
+
return {
|
|
926
|
+
...rest,
|
|
927
|
+
content,
|
|
928
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
929
|
+
};
|
|
698
930
|
});
|
|
699
931
|
}
|
|
700
932
|
/**
|
|
@@ -775,14 +1007,40 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
775
1007
|
).map((part) => part.text) : []
|
|
776
1008
|
).join("") : "";
|
|
777
1009
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
name
|
|
781
|
-
|
|
782
|
-
|
|
1010
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
1011
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
1012
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
1013
|
+
throw invalidProviderResponse(
|
|
1014
|
+
"Responses contains an incomplete function call"
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
if (seenCallIds.has(item.call_id))
|
|
1018
|
+
throw invalidProviderResponse(
|
|
1019
|
+
"Responses contains duplicate function call IDs"
|
|
1020
|
+
);
|
|
1021
|
+
seenCallIds.add(item.call_id);
|
|
1022
|
+
let args;
|
|
1023
|
+
try {
|
|
1024
|
+
args = JSON.parse(item.arguments);
|
|
1025
|
+
} catch {
|
|
1026
|
+
throw invalidProviderResponse(
|
|
1027
|
+
"Responses function arguments must be valid JSON"
|
|
1028
|
+
);
|
|
1029
|
+
}
|
|
1030
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1031
|
+
throw invalidProviderResponse(
|
|
1032
|
+
"Responses function arguments must be a JSON object"
|
|
1033
|
+
);
|
|
1034
|
+
return {
|
|
1035
|
+
id: item.call_id,
|
|
1036
|
+
name: item.name,
|
|
1037
|
+
args
|
|
1038
|
+
};
|
|
1039
|
+
}) : [];
|
|
783
1040
|
return {
|
|
784
1041
|
content,
|
|
785
1042
|
toolCalls,
|
|
1043
|
+
providerMetadata: responseMetadata(response),
|
|
786
1044
|
usage: response?.usage ? {
|
|
787
1045
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
788
1046
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -793,6 +1051,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
793
1051
|
}
|
|
794
1052
|
buildResponsesPayload(request, stream) {
|
|
795
1053
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1054
|
+
const options = resolveOpenAITransport(
|
|
1055
|
+
this.config,
|
|
1056
|
+
request.config?.openai
|
|
1057
|
+
).responses;
|
|
1058
|
+
const parameters = buildOpenAIParameters(
|
|
1059
|
+
request.config?.model || this.model,
|
|
1060
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1061
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1062
|
+
this.parameterOptions(request),
|
|
1063
|
+
"responses"
|
|
1064
|
+
);
|
|
796
1065
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
797
1066
|
request.config?.responseFormat
|
|
798
1067
|
);
|
|
@@ -808,13 +1077,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
808
1077
|
),
|
|
809
1078
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
810
1079
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
811
|
-
...
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
1080
|
+
...parameters,
|
|
1081
|
+
...options?.reasoningSummary ? {
|
|
1082
|
+
reasoning: {
|
|
1083
|
+
...parameters.reasoning,
|
|
1084
|
+
summary: options.reasoningSummary
|
|
1085
|
+
}
|
|
1086
|
+
} : {},
|
|
1087
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1088
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1089
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1090
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1091
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1092
|
+
...options?.store === false || options?.include ? {
|
|
1093
|
+
include: [
|
|
1094
|
+
.../* @__PURE__ */ new Set([
|
|
1095
|
+
...options?.include ?? [],
|
|
1096
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1097
|
+
])
|
|
1098
|
+
]
|
|
1099
|
+
} : {},
|
|
818
1100
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
819
1101
|
stream
|
|
820
1102
|
};
|
|
@@ -873,6 +1155,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
873
1155
|
let usage;
|
|
874
1156
|
const citations = [];
|
|
875
1157
|
let completed = false;
|
|
1158
|
+
let terminalResponse;
|
|
1159
|
+
let responseIdentity = {};
|
|
1160
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1161
|
+
let streamedText = "";
|
|
876
1162
|
function* flushToolCalls() {
|
|
877
1163
|
for (const call of toolCalls.values()) {
|
|
878
1164
|
if (!call.name)
|
|
@@ -889,17 +1175,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
889
1175
|
for await (const event of stream) {
|
|
890
1176
|
throwIfAborted(request.signal);
|
|
891
1177
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1178
|
+
if (completed)
|
|
1179
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
892
1180
|
const index = event?.output_index ?? 0;
|
|
893
1181
|
switch (event?.type) {
|
|
1182
|
+
case "response.created":
|
|
1183
|
+
responseIdentity = {
|
|
1184
|
+
id: event.response?.id,
|
|
1185
|
+
model: event.response?.model
|
|
1186
|
+
};
|
|
1187
|
+
break;
|
|
1188
|
+
case "response.output_item.done":
|
|
1189
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1190
|
+
if (event.item?.type === "function_call") {
|
|
1191
|
+
toolCalls.set(index, {
|
|
1192
|
+
id: event.item.call_id,
|
|
1193
|
+
name: event.item.name,
|
|
1194
|
+
arguments: event.item.arguments
|
|
1195
|
+
});
|
|
1196
|
+
}
|
|
1197
|
+
break;
|
|
894
1198
|
case "response.output_text.delta":
|
|
895
1199
|
if (event.delta) {
|
|
1200
|
+
streamedText += event.delta;
|
|
896
1201
|
yield { type: "message:delta", content: event.delta };
|
|
897
1202
|
}
|
|
898
1203
|
break;
|
|
899
1204
|
case "response.output_item.added":
|
|
900
1205
|
if (event.item?.type === "function_call") {
|
|
901
1206
|
toolCalls.set(index, {
|
|
902
|
-
id: event.item.call_id ??
|
|
1207
|
+
id: event.item.call_id ?? "",
|
|
903
1208
|
name: event.item.name ?? "",
|
|
904
1209
|
arguments: event.item.arguments ?? ""
|
|
905
1210
|
});
|
|
@@ -918,7 +1223,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
918
1223
|
break;
|
|
919
1224
|
}
|
|
920
1225
|
case "response.completed": {
|
|
1226
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1227
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
921
1228
|
completed = true;
|
|
1229
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
922
1230
|
const found = this.collectResponsesCitations(
|
|
923
1231
|
event.response?.output,
|
|
924
1232
|
citations.length
|
|
@@ -955,12 +1263,66 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
955
1263
|
throwIfAborted(request.signal);
|
|
956
1264
|
if (!completed)
|
|
957
1265
|
throw new Error("Responses stream ended without a completed response");
|
|
1266
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1267
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1268
|
+
toolCalls.clear();
|
|
1269
|
+
for (const [index, item] of output.entries()) {
|
|
1270
|
+
if (item.type === "function_call") {
|
|
1271
|
+
toolCalls.set(index, {
|
|
1272
|
+
id: item.call_id,
|
|
1273
|
+
name: item.name,
|
|
1274
|
+
arguments: item.arguments
|
|
1275
|
+
});
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1279
|
+
for (const call of toolCalls.values()) {
|
|
1280
|
+
if (!call.id || !call.name)
|
|
1281
|
+
throw invalidProviderResponse(
|
|
1282
|
+
"Responses stream contains an incomplete tool call"
|
|
1283
|
+
);
|
|
1284
|
+
uniqueCalls.set(call.id, call);
|
|
1285
|
+
}
|
|
1286
|
+
toolCalls.clear();
|
|
1287
|
+
[...uniqueCalls.values()].forEach(
|
|
1288
|
+
(call, index) => toolCalls.set(index, call)
|
|
1289
|
+
);
|
|
1290
|
+
if (!output.length && toolCalls.size) {
|
|
1291
|
+
for (const call of toolCalls.values())
|
|
1292
|
+
output.push({
|
|
1293
|
+
type: "function_call",
|
|
1294
|
+
call_id: call.id,
|
|
1295
|
+
name: call.name,
|
|
1296
|
+
arguments: call.arguments
|
|
1297
|
+
});
|
|
1298
|
+
}
|
|
1299
|
+
if (!output.length && streamedText)
|
|
1300
|
+
output.push({
|
|
1301
|
+
type: "message",
|
|
1302
|
+
role: "assistant",
|
|
1303
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1304
|
+
});
|
|
1305
|
+
terminalResponse.output = output;
|
|
1306
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1307
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1308
|
+
yield {
|
|
1309
|
+
type: "message:delta",
|
|
1310
|
+
content: finalText.slice(streamedText.length)
|
|
1311
|
+
};
|
|
1312
|
+
}
|
|
958
1313
|
yield* flushToolCalls();
|
|
959
1314
|
if (citations.length > 0) {
|
|
960
1315
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
961
1316
|
}
|
|
962
|
-
yield {
|
|
963
|
-
|
|
1317
|
+
yield {
|
|
1318
|
+
type: "message:end",
|
|
1319
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1320
|
+
};
|
|
1321
|
+
yield {
|
|
1322
|
+
type: "done",
|
|
1323
|
+
usage,
|
|
1324
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1325
|
+
};
|
|
964
1326
|
}
|
|
965
1327
|
async *stream(request) {
|
|
966
1328
|
throwIfAborted(request.signal);
|