@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
|
}
|
|
@@ -475,7 +580,7 @@ function formatMessages(messages) {
|
|
|
475
580
|
return {
|
|
476
581
|
role: "tool",
|
|
477
582
|
tool_call_id: msg.toolCallId,
|
|
478
|
-
content: msg.content
|
|
583
|
+
content: textToolOutput(msg.modelOutput, msg.content)
|
|
479
584
|
};
|
|
480
585
|
default:
|
|
481
586
|
return msg;
|
|
@@ -483,7 +588,120 @@ function formatMessages(messages) {
|
|
|
483
588
|
});
|
|
484
589
|
}
|
|
485
590
|
|
|
591
|
+
// src/core/openai-responses.ts
|
|
592
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
593
|
+
return {
|
|
594
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
595
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
599
|
+
const api = transport.api ?? "auto";
|
|
600
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
601
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
602
|
+
}
|
|
603
|
+
if (api === "chat") {
|
|
604
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
605
|
+
throw new Error(
|
|
606
|
+
"Responses options and native tool search require the Responses API"
|
|
607
|
+
);
|
|
608
|
+
}
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
let officialEndpoint = !baseURL;
|
|
612
|
+
try {
|
|
613
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
614
|
+
} catch {
|
|
615
|
+
}
|
|
616
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
617
|
+
}
|
|
618
|
+
function responseMetadata(response) {
|
|
619
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
620
|
+
return {
|
|
621
|
+
openai: {
|
|
622
|
+
response: {
|
|
623
|
+
id: response?.id,
|
|
624
|
+
model: response?.model,
|
|
625
|
+
status: response?.status,
|
|
626
|
+
output,
|
|
627
|
+
usage: response?.usage,
|
|
628
|
+
store: response?.store,
|
|
629
|
+
refusals: output.flatMap(
|
|
630
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
631
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
632
|
+
).map((part) => part.refusal) : []
|
|
633
|
+
)
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
function responseReplayMetadata(metadata) {
|
|
639
|
+
const response = metadata?.openai?.response;
|
|
640
|
+
if (!response) return metadata;
|
|
641
|
+
const output = response.output.map((item) => {
|
|
642
|
+
const fields = ["type", "id", "status"];
|
|
643
|
+
switch (item.type) {
|
|
644
|
+
case "reasoning":
|
|
645
|
+
fields.push("encrypted_content");
|
|
646
|
+
break;
|
|
647
|
+
case "message":
|
|
648
|
+
fields.push("role", "phase");
|
|
649
|
+
break;
|
|
650
|
+
case "function_call":
|
|
651
|
+
fields.push("call_id", "name", "namespace", "arguments");
|
|
652
|
+
break;
|
|
653
|
+
case "tool_search_call":
|
|
654
|
+
fields.push("call_id", "execution", "arguments");
|
|
655
|
+
break;
|
|
656
|
+
case "tool_search_output":
|
|
657
|
+
fields.push("call_id", "tools");
|
|
658
|
+
break;
|
|
659
|
+
case "web_search_call":
|
|
660
|
+
fields.push("action");
|
|
661
|
+
break;
|
|
662
|
+
default:
|
|
663
|
+
return stripItemDiagnostics(item);
|
|
664
|
+
}
|
|
665
|
+
const replay = Object.fromEntries(
|
|
666
|
+
fields.filter((key) => item[key] !== void 0).map((key) => [key, item[key]])
|
|
667
|
+
);
|
|
668
|
+
if (item.type === "reasoning") replay.summary = [];
|
|
669
|
+
if (item.type === "message")
|
|
670
|
+
replay.content = Array.isArray(item.content) ? item.content.flatMap(
|
|
671
|
+
(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 }] : []
|
|
672
|
+
) : [];
|
|
673
|
+
return stripItemDiagnostics(replay);
|
|
674
|
+
});
|
|
675
|
+
return { openai: { response: { output, refusals: [] } } };
|
|
676
|
+
}
|
|
677
|
+
function stripItemDiagnostics(item) {
|
|
678
|
+
const {
|
|
679
|
+
usage: _usage,
|
|
680
|
+
logprobs: _logprobs,
|
|
681
|
+
metadata: _metadata,
|
|
682
|
+
...state
|
|
683
|
+
} = item;
|
|
684
|
+
return state;
|
|
685
|
+
}
|
|
686
|
+
function getResponseReplay(metadata) {
|
|
687
|
+
const response = metadata?.openai?.response;
|
|
688
|
+
if (response === void 0) return void 0;
|
|
689
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
690
|
+
throw new Error(
|
|
691
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
return responseReplayMetadata(metadata)?.openai?.response?.output;
|
|
695
|
+
}
|
|
696
|
+
|
|
486
697
|
// src/core/provider-error.ts
|
|
698
|
+
function invalidProviderResponse(message) {
|
|
699
|
+
return Object.assign(new Error(message), {
|
|
700
|
+
name: "InvalidProviderResponseError",
|
|
701
|
+
status: 502,
|
|
702
|
+
code: "INVALID_PROVIDER_RESPONSE"
|
|
703
|
+
});
|
|
704
|
+
}
|
|
487
705
|
function providerErrorEvent(error, code) {
|
|
488
706
|
const details = error ?? {};
|
|
489
707
|
const event = {
|
|
@@ -559,13 +777,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
559
777
|
}));
|
|
560
778
|
}
|
|
561
779
|
shouldUseResponsesApi(request) {
|
|
562
|
-
|
|
563
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
564
|
-
return true;
|
|
565
|
-
return requiresOpenAIResponses(
|
|
780
|
+
return useOpenAIResponses(
|
|
566
781
|
request.config?.model || this.model,
|
|
567
782
|
this.config.baseUrl,
|
|
568
|
-
this.parameterOptions(request)
|
|
783
|
+
this.parameterOptions(request),
|
|
784
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
785
|
+
this.toolDefinitions(request).length > 0,
|
|
786
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
787
|
+
(message) => message.providerMetadata?.openai?.response
|
|
788
|
+
),
|
|
789
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
569
790
|
);
|
|
570
791
|
}
|
|
571
792
|
/**
|
|
@@ -598,11 +819,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
598
819
|
});
|
|
599
820
|
}
|
|
600
821
|
buildResponsesInput(request) {
|
|
601
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
822
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
602
823
|
const input = [];
|
|
603
824
|
for (const message of sourceMessages) {
|
|
604
825
|
if (message.role === "system") {
|
|
605
|
-
if (
|
|
826
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
606
827
|
input.push({
|
|
607
828
|
type: "message",
|
|
608
829
|
role: "developer",
|
|
@@ -612,6 +833,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
612
833
|
continue;
|
|
613
834
|
}
|
|
614
835
|
if (message.role === "assistant") {
|
|
836
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
837
|
+
if (replay) {
|
|
838
|
+
input.push(...replay);
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
615
841
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
616
842
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
617
843
|
input.push({
|
|
@@ -635,7 +861,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
635
861
|
input.push({
|
|
636
862
|
type: "function_call_output",
|
|
637
863
|
call_id: message.tool_call_id,
|
|
638
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
864
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
639
865
|
});
|
|
640
866
|
continue;
|
|
641
867
|
}
|
|
@@ -649,10 +875,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
649
875
|
return input;
|
|
650
876
|
}
|
|
651
877
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
652
|
-
formatRawMessages(messages) {
|
|
878
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
653
879
|
return messages.map((message) => {
|
|
654
|
-
const { attachments, ...rest } = message;
|
|
655
|
-
let content = message.content;
|
|
880
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
881
|
+
let content = message.role === "tool" && !preserveProviderMetadata && modelOutput !== void 0 ? textToolOutput(modelOutput, "") : message.content;
|
|
882
|
+
if (preserveProviderMetadata && modelOutput)
|
|
883
|
+
rest.modelOutput = modelOutput;
|
|
656
884
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
657
885
|
content = null;
|
|
658
886
|
}
|
|
@@ -665,7 +893,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
665
893
|
content = [...parts, ...images];
|
|
666
894
|
}
|
|
667
895
|
}
|
|
668
|
-
return {
|
|
896
|
+
return {
|
|
897
|
+
...rest,
|
|
898
|
+
content,
|
|
899
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
900
|
+
};
|
|
669
901
|
});
|
|
670
902
|
}
|
|
671
903
|
/**
|
|
@@ -746,14 +978,40 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
746
978
|
).map((part) => part.text) : []
|
|
747
979
|
).join("") : "";
|
|
748
980
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
749
|
-
const
|
|
750
|
-
|
|
751
|
-
name
|
|
752
|
-
|
|
753
|
-
|
|
981
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
982
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
983
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
984
|
+
throw invalidProviderResponse(
|
|
985
|
+
"Responses contains an incomplete function call"
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
if (seenCallIds.has(item.call_id))
|
|
989
|
+
throw invalidProviderResponse(
|
|
990
|
+
"Responses contains duplicate function call IDs"
|
|
991
|
+
);
|
|
992
|
+
seenCallIds.add(item.call_id);
|
|
993
|
+
let args;
|
|
994
|
+
try {
|
|
995
|
+
args = JSON.parse(item.arguments);
|
|
996
|
+
} catch {
|
|
997
|
+
throw invalidProviderResponse(
|
|
998
|
+
"Responses function arguments must be valid JSON"
|
|
999
|
+
);
|
|
1000
|
+
}
|
|
1001
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
1002
|
+
throw invalidProviderResponse(
|
|
1003
|
+
"Responses function arguments must be a JSON object"
|
|
1004
|
+
);
|
|
1005
|
+
return {
|
|
1006
|
+
id: item.call_id,
|
|
1007
|
+
name: item.name,
|
|
1008
|
+
args
|
|
1009
|
+
};
|
|
1010
|
+
}) : [];
|
|
754
1011
|
return {
|
|
755
1012
|
content,
|
|
756
1013
|
toolCalls,
|
|
1014
|
+
providerMetadata: responseMetadata(response),
|
|
757
1015
|
usage: response?.usage ? {
|
|
758
1016
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
759
1017
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -764,6 +1022,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
764
1022
|
}
|
|
765
1023
|
buildResponsesPayload(request, stream) {
|
|
766
1024
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1025
|
+
const options = resolveOpenAITransport(
|
|
1026
|
+
this.config,
|
|
1027
|
+
request.config?.openai
|
|
1028
|
+
).responses;
|
|
1029
|
+
const parameters = buildOpenAIParameters(
|
|
1030
|
+
request.config?.model || this.model,
|
|
1031
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1032
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1033
|
+
this.parameterOptions(request),
|
|
1034
|
+
"responses"
|
|
1035
|
+
);
|
|
767
1036
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
768
1037
|
request.config?.responseFormat
|
|
769
1038
|
);
|
|
@@ -779,13 +1048,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
779
1048
|
),
|
|
780
1049
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
781
1050
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
782
|
-
...
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
1051
|
+
...parameters,
|
|
1052
|
+
...options?.reasoningSummary ? {
|
|
1053
|
+
reasoning: {
|
|
1054
|
+
...parameters.reasoning,
|
|
1055
|
+
summary: options.reasoningSummary
|
|
1056
|
+
}
|
|
1057
|
+
} : {},
|
|
1058
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1059
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1060
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1061
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1062
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1063
|
+
...options?.store === false || options?.include ? {
|
|
1064
|
+
include: [
|
|
1065
|
+
.../* @__PURE__ */ new Set([
|
|
1066
|
+
...options?.include ?? [],
|
|
1067
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1068
|
+
])
|
|
1069
|
+
]
|
|
1070
|
+
} : {},
|
|
789
1071
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
790
1072
|
stream
|
|
791
1073
|
};
|
|
@@ -844,6 +1126,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
844
1126
|
let usage;
|
|
845
1127
|
const citations = [];
|
|
846
1128
|
let completed = false;
|
|
1129
|
+
let terminalResponse;
|
|
1130
|
+
let responseIdentity = {};
|
|
1131
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1132
|
+
let streamedText = "";
|
|
847
1133
|
function* flushToolCalls() {
|
|
848
1134
|
for (const call of toolCalls.values()) {
|
|
849
1135
|
if (!call.name)
|
|
@@ -860,17 +1146,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
860
1146
|
for await (const event of stream) {
|
|
861
1147
|
throwIfAborted(request.signal);
|
|
862
1148
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1149
|
+
if (completed)
|
|
1150
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
863
1151
|
const index = event?.output_index ?? 0;
|
|
864
1152
|
switch (event?.type) {
|
|
1153
|
+
case "response.created":
|
|
1154
|
+
responseIdentity = {
|
|
1155
|
+
id: event.response?.id,
|
|
1156
|
+
model: event.response?.model
|
|
1157
|
+
};
|
|
1158
|
+
break;
|
|
1159
|
+
case "response.output_item.done":
|
|
1160
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1161
|
+
if (event.item?.type === "function_call") {
|
|
1162
|
+
toolCalls.set(index, {
|
|
1163
|
+
id: event.item.call_id,
|
|
1164
|
+
name: event.item.name,
|
|
1165
|
+
arguments: event.item.arguments
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
break;
|
|
865
1169
|
case "response.output_text.delta":
|
|
866
1170
|
if (event.delta) {
|
|
1171
|
+
streamedText += event.delta;
|
|
867
1172
|
yield { type: "message:delta", content: event.delta };
|
|
868
1173
|
}
|
|
869
1174
|
break;
|
|
870
1175
|
case "response.output_item.added":
|
|
871
1176
|
if (event.item?.type === "function_call") {
|
|
872
1177
|
toolCalls.set(index, {
|
|
873
|
-
id: event.item.call_id ??
|
|
1178
|
+
id: event.item.call_id ?? "",
|
|
874
1179
|
name: event.item.name ?? "",
|
|
875
1180
|
arguments: event.item.arguments ?? ""
|
|
876
1181
|
});
|
|
@@ -889,7 +1194,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
889
1194
|
break;
|
|
890
1195
|
}
|
|
891
1196
|
case "response.completed": {
|
|
1197
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1198
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
892
1199
|
completed = true;
|
|
1200
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
893
1201
|
const found = this.collectResponsesCitations(
|
|
894
1202
|
event.response?.output,
|
|
895
1203
|
citations.length
|
|
@@ -926,12 +1234,66 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
926
1234
|
throwIfAborted(request.signal);
|
|
927
1235
|
if (!completed)
|
|
928
1236
|
throw new Error("Responses stream ended without a completed response");
|
|
1237
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1238
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1239
|
+
toolCalls.clear();
|
|
1240
|
+
for (const [index, item] of output.entries()) {
|
|
1241
|
+
if (item.type === "function_call") {
|
|
1242
|
+
toolCalls.set(index, {
|
|
1243
|
+
id: item.call_id,
|
|
1244
|
+
name: item.name,
|
|
1245
|
+
arguments: item.arguments
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1250
|
+
for (const call of toolCalls.values()) {
|
|
1251
|
+
if (!call.id || !call.name)
|
|
1252
|
+
throw invalidProviderResponse(
|
|
1253
|
+
"Responses stream contains an incomplete tool call"
|
|
1254
|
+
);
|
|
1255
|
+
uniqueCalls.set(call.id, call);
|
|
1256
|
+
}
|
|
1257
|
+
toolCalls.clear();
|
|
1258
|
+
[...uniqueCalls.values()].forEach(
|
|
1259
|
+
(call, index) => toolCalls.set(index, call)
|
|
1260
|
+
);
|
|
1261
|
+
if (!output.length && toolCalls.size) {
|
|
1262
|
+
for (const call of toolCalls.values())
|
|
1263
|
+
output.push({
|
|
1264
|
+
type: "function_call",
|
|
1265
|
+
call_id: call.id,
|
|
1266
|
+
name: call.name,
|
|
1267
|
+
arguments: call.arguments
|
|
1268
|
+
});
|
|
1269
|
+
}
|
|
1270
|
+
if (!output.length && streamedText)
|
|
1271
|
+
output.push({
|
|
1272
|
+
type: "message",
|
|
1273
|
+
role: "assistant",
|
|
1274
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1275
|
+
});
|
|
1276
|
+
terminalResponse.output = output;
|
|
1277
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1278
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1279
|
+
yield {
|
|
1280
|
+
type: "message:delta",
|
|
1281
|
+
content: finalText.slice(streamedText.length)
|
|
1282
|
+
};
|
|
1283
|
+
}
|
|
929
1284
|
yield* flushToolCalls();
|
|
930
1285
|
if (citations.length > 0) {
|
|
931
1286
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
932
1287
|
}
|
|
933
|
-
yield {
|
|
934
|
-
|
|
1288
|
+
yield {
|
|
1289
|
+
type: "message:end",
|
|
1290
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1291
|
+
};
|
|
1292
|
+
yield {
|
|
1293
|
+
type: "done",
|
|
1294
|
+
usage,
|
|
1295
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1296
|
+
};
|
|
935
1297
|
}
|
|
936
1298
|
async *stream(request) {
|
|
937
1299
|
throwIfAborted(request.signal);
|