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