@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,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
|
}
|
|
@@ -480,7 +585,7 @@ function formatMessages(messages) {
|
|
|
480
585
|
return {
|
|
481
586
|
role: "tool",
|
|
482
587
|
tool_call_id: msg.toolCallId,
|
|
483
|
-
content: msg.content
|
|
588
|
+
content: textToolOutput(msg.modelOutput, msg.content)
|
|
484
589
|
};
|
|
485
590
|
default:
|
|
486
591
|
return msg;
|
|
@@ -488,6 +593,64 @@ function formatMessages(messages) {
|
|
|
488
593
|
});
|
|
489
594
|
}
|
|
490
595
|
|
|
596
|
+
// src/core/openai-responses.ts
|
|
597
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
598
|
+
return {
|
|
599
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
600
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
604
|
+
const api = transport.api ?? "auto";
|
|
605
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
606
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
607
|
+
}
|
|
608
|
+
if (api === "chat") {
|
|
609
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
610
|
+
throw new Error(
|
|
611
|
+
"Responses options and native tool search require the Responses API"
|
|
612
|
+
);
|
|
613
|
+
}
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
let officialEndpoint = !baseURL;
|
|
617
|
+
try {
|
|
618
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
619
|
+
} catch {
|
|
620
|
+
}
|
|
621
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
622
|
+
}
|
|
623
|
+
function responseMetadata(response) {
|
|
624
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
625
|
+
return {
|
|
626
|
+
openai: {
|
|
627
|
+
response: {
|
|
628
|
+
id: response?.id,
|
|
629
|
+
model: response?.model,
|
|
630
|
+
status: response?.status,
|
|
631
|
+
output,
|
|
632
|
+
usage: response?.usage,
|
|
633
|
+
store: response?.store,
|
|
634
|
+
refusals: output.flatMap(
|
|
635
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
636
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
637
|
+
).map((part) => part.refusal) : []
|
|
638
|
+
)
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
function getResponseReplay(metadata) {
|
|
644
|
+
const response = metadata?.openai?.response;
|
|
645
|
+
if (response === void 0) return void 0;
|
|
646
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
647
|
+
throw new Error(
|
|
648
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
649
|
+
);
|
|
650
|
+
}
|
|
651
|
+
return response.output;
|
|
652
|
+
}
|
|
653
|
+
|
|
491
654
|
// src/core/provider-error.ts
|
|
492
655
|
function providerErrorEvent(error, code) {
|
|
493
656
|
const details = error ?? {};
|
|
@@ -564,13 +727,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
564
727
|
}));
|
|
565
728
|
}
|
|
566
729
|
shouldUseResponsesApi(request) {
|
|
567
|
-
|
|
568
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
569
|
-
return true;
|
|
570
|
-
return requiresOpenAIResponses(
|
|
730
|
+
return useOpenAIResponses(
|
|
571
731
|
request.config?.model || this.model,
|
|
572
732
|
this.config.baseUrl,
|
|
573
|
-
this.parameterOptions(request)
|
|
733
|
+
this.parameterOptions(request),
|
|
734
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
735
|
+
this.toolDefinitions(request).length > 0,
|
|
736
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
737
|
+
(message) => message.providerMetadata?.openai?.response
|
|
738
|
+
),
|
|
739
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
574
740
|
);
|
|
575
741
|
}
|
|
576
742
|
/**
|
|
@@ -603,11 +769,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
603
769
|
});
|
|
604
770
|
}
|
|
605
771
|
buildResponsesInput(request) {
|
|
606
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
772
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
607
773
|
const input = [];
|
|
608
774
|
for (const message of sourceMessages) {
|
|
609
775
|
if (message.role === "system") {
|
|
610
|
-
if (
|
|
776
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
611
777
|
input.push({
|
|
612
778
|
type: "message",
|
|
613
779
|
role: "developer",
|
|
@@ -617,6 +783,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
617
783
|
continue;
|
|
618
784
|
}
|
|
619
785
|
if (message.role === "assistant") {
|
|
786
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
787
|
+
if (replay) {
|
|
788
|
+
input.push(...replay);
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
620
791
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
621
792
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
622
793
|
input.push({
|
|
@@ -640,7 +811,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
640
811
|
input.push({
|
|
641
812
|
type: "function_call_output",
|
|
642
813
|
call_id: message.tool_call_id,
|
|
643
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
814
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
644
815
|
});
|
|
645
816
|
continue;
|
|
646
817
|
}
|
|
@@ -654,10 +825,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
654
825
|
return input;
|
|
655
826
|
}
|
|
656
827
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
657
|
-
formatRawMessages(messages) {
|
|
828
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
658
829
|
return messages.map((message) => {
|
|
659
|
-
const { attachments, ...rest } = message;
|
|
660
|
-
let content = message.content;
|
|
830
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
831
|
+
let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
|
|
832
|
+
if (preserveProviderMetadata && modelOutput)
|
|
833
|
+
rest.modelOutput = modelOutput;
|
|
661
834
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
662
835
|
content = null;
|
|
663
836
|
}
|
|
@@ -670,7 +843,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
670
843
|
content = [...parts, ...images];
|
|
671
844
|
}
|
|
672
845
|
}
|
|
673
|
-
return {
|
|
846
|
+
return {
|
|
847
|
+
...rest,
|
|
848
|
+
content,
|
|
849
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
850
|
+
};
|
|
674
851
|
});
|
|
675
852
|
}
|
|
676
853
|
/**
|
|
@@ -751,14 +928,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
751
928
|
).map((part) => part.text) : []
|
|
752
929
|
).join("") : "";
|
|
753
930
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
754
|
-
const
|
|
755
|
-
|
|
756
|
-
name
|
|
757
|
-
|
|
758
|
-
|
|
931
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
932
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
933
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
934
|
+
throw new Error("Responses contains an incomplete function call");
|
|
935
|
+
}
|
|
936
|
+
if (seenCallIds.has(item.call_id))
|
|
937
|
+
throw new Error("Responses contains duplicate function call IDs");
|
|
938
|
+
seenCallIds.add(item.call_id);
|
|
939
|
+
const args = JSON.parse(item.arguments);
|
|
940
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
941
|
+
throw new Error(
|
|
942
|
+
"Responses function arguments must be a JSON object"
|
|
943
|
+
);
|
|
944
|
+
return { id: item.call_id, name: item.name, args };
|
|
945
|
+
}) : [];
|
|
759
946
|
return {
|
|
760
947
|
content,
|
|
761
948
|
toolCalls,
|
|
949
|
+
providerMetadata: responseMetadata(response),
|
|
762
950
|
usage: response?.usage ? {
|
|
763
951
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
764
952
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -769,6 +957,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
769
957
|
}
|
|
770
958
|
buildResponsesPayload(request, stream) {
|
|
771
959
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
960
|
+
const options = resolveOpenAITransport(
|
|
961
|
+
this.config,
|
|
962
|
+
request.config?.openai
|
|
963
|
+
).responses;
|
|
964
|
+
const parameters = buildOpenAIParameters(
|
|
965
|
+
request.config?.model || this.model,
|
|
966
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
967
|
+
request.config?.temperature ?? this.config.temperature,
|
|
968
|
+
this.parameterOptions(request),
|
|
969
|
+
"responses"
|
|
970
|
+
);
|
|
772
971
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
773
972
|
request.config?.responseFormat
|
|
774
973
|
);
|
|
@@ -784,13 +983,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
784
983
|
),
|
|
785
984
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
786
985
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
787
|
-
...
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
986
|
+
...parameters,
|
|
987
|
+
...options?.reasoningSummary ? {
|
|
988
|
+
reasoning: {
|
|
989
|
+
...parameters.reasoning,
|
|
990
|
+
summary: options.reasoningSummary
|
|
991
|
+
}
|
|
992
|
+
} : {},
|
|
993
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
994
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
995
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
996
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
997
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
998
|
+
...options?.store === false || options?.include ? {
|
|
999
|
+
include: [
|
|
1000
|
+
.../* @__PURE__ */ new Set([
|
|
1001
|
+
...options?.include ?? [],
|
|
1002
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1003
|
+
])
|
|
1004
|
+
]
|
|
1005
|
+
} : {},
|
|
794
1006
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
795
1007
|
stream
|
|
796
1008
|
};
|
|
@@ -849,6 +1061,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
849
1061
|
let usage;
|
|
850
1062
|
const citations = [];
|
|
851
1063
|
let completed = false;
|
|
1064
|
+
let terminalResponse;
|
|
1065
|
+
let responseIdentity = {};
|
|
1066
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1067
|
+
let streamedText = "";
|
|
852
1068
|
function* flushToolCalls() {
|
|
853
1069
|
for (const call of toolCalls.values()) {
|
|
854
1070
|
if (!call.name)
|
|
@@ -865,17 +1081,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
865
1081
|
for await (const event of stream) {
|
|
866
1082
|
throwIfAborted(request.signal);
|
|
867
1083
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1084
|
+
if (completed)
|
|
1085
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
868
1086
|
const index = event?.output_index ?? 0;
|
|
869
1087
|
switch (event?.type) {
|
|
1088
|
+
case "response.created":
|
|
1089
|
+
responseIdentity = {
|
|
1090
|
+
id: event.response?.id,
|
|
1091
|
+
model: event.response?.model
|
|
1092
|
+
};
|
|
1093
|
+
break;
|
|
1094
|
+
case "response.output_item.done":
|
|
1095
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1096
|
+
if (event.item?.type === "function_call") {
|
|
1097
|
+
toolCalls.set(index, {
|
|
1098
|
+
id: event.item.call_id,
|
|
1099
|
+
name: event.item.name,
|
|
1100
|
+
arguments: event.item.arguments
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
break;
|
|
870
1104
|
case "response.output_text.delta":
|
|
871
1105
|
if (event.delta) {
|
|
1106
|
+
streamedText += event.delta;
|
|
872
1107
|
yield { type: "message:delta", content: event.delta };
|
|
873
1108
|
}
|
|
874
1109
|
break;
|
|
875
1110
|
case "response.output_item.added":
|
|
876
1111
|
if (event.item?.type === "function_call") {
|
|
877
1112
|
toolCalls.set(index, {
|
|
878
|
-
id: event.item.call_id ??
|
|
1113
|
+
id: event.item.call_id ?? "",
|
|
879
1114
|
name: event.item.name ?? "",
|
|
880
1115
|
arguments: event.item.arguments ?? ""
|
|
881
1116
|
});
|
|
@@ -894,7 +1129,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
894
1129
|
break;
|
|
895
1130
|
}
|
|
896
1131
|
case "response.completed": {
|
|
1132
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1133
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
897
1134
|
completed = true;
|
|
1135
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
898
1136
|
const found = this.collectResponsesCitations(
|
|
899
1137
|
event.response?.output,
|
|
900
1138
|
citations.length
|
|
@@ -931,12 +1169,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
931
1169
|
throwIfAborted(request.signal);
|
|
932
1170
|
if (!completed)
|
|
933
1171
|
throw new Error("Responses stream ended without a completed response");
|
|
1172
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1173
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1174
|
+
toolCalls.clear();
|
|
1175
|
+
for (const [index, item] of output.entries()) {
|
|
1176
|
+
if (item.type === "function_call") {
|
|
1177
|
+
toolCalls.set(index, {
|
|
1178
|
+
id: item.call_id,
|
|
1179
|
+
name: item.name,
|
|
1180
|
+
arguments: item.arguments
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1185
|
+
for (const call of toolCalls.values()) {
|
|
1186
|
+
if (!call.id || !call.name)
|
|
1187
|
+
throw new Error("Responses stream contains an incomplete tool call");
|
|
1188
|
+
uniqueCalls.set(call.id, call);
|
|
1189
|
+
}
|
|
1190
|
+
toolCalls.clear();
|
|
1191
|
+
[...uniqueCalls.values()].forEach(
|
|
1192
|
+
(call, index) => toolCalls.set(index, call)
|
|
1193
|
+
);
|
|
1194
|
+
if (!output.length && toolCalls.size) {
|
|
1195
|
+
for (const call of toolCalls.values())
|
|
1196
|
+
output.push({
|
|
1197
|
+
type: "function_call",
|
|
1198
|
+
call_id: call.id,
|
|
1199
|
+
name: call.name,
|
|
1200
|
+
arguments: call.arguments
|
|
1201
|
+
});
|
|
1202
|
+
}
|
|
1203
|
+
if (!output.length && streamedText)
|
|
1204
|
+
output.push({
|
|
1205
|
+
type: "message",
|
|
1206
|
+
role: "assistant",
|
|
1207
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1208
|
+
});
|
|
1209
|
+
terminalResponse.output = output;
|
|
1210
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1211
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1212
|
+
yield {
|
|
1213
|
+
type: "message:delta",
|
|
1214
|
+
content: finalText.slice(streamedText.length)
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
934
1217
|
yield* flushToolCalls();
|
|
935
1218
|
if (citations.length > 0) {
|
|
936
1219
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
937
1220
|
}
|
|
938
|
-
yield {
|
|
939
|
-
|
|
1221
|
+
yield {
|
|
1222
|
+
type: "message:end",
|
|
1223
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1224
|
+
};
|
|
1225
|
+
yield {
|
|
1226
|
+
type: "done",
|
|
1227
|
+
usage,
|
|
1228
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1229
|
+
};
|
|
940
1230
|
}
|
|
941
1231
|
async *stream(request) {
|
|
942
1232
|
throwIfAborted(request.signal);
|