@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
package/dist/adapters/index.js
CHANGED
|
@@ -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);
|
|
@@ -422,7 +525,27 @@ function messageToOpenAIContent(message) {
|
|
|
422
525
|
}
|
|
423
526
|
return blocks;
|
|
424
527
|
}
|
|
528
|
+
function extractAnthropicSystemPrompt(messages, systemPrompt) {
|
|
529
|
+
const parts = systemPrompt ? [systemPrompt] : [];
|
|
530
|
+
for (const message of messages) {
|
|
531
|
+
if (message.role !== "system") continue;
|
|
532
|
+
if (typeof message.content === "string") {
|
|
533
|
+
if (message.content) parts.push(message.content);
|
|
534
|
+
} else if (Array.isArray(message.content)) {
|
|
535
|
+
for (const block of message.content) {
|
|
536
|
+
if (block?.type !== "text" || typeof block.text !== "string") {
|
|
537
|
+
throw new TypeError("Anthropic system messages must contain text.");
|
|
538
|
+
}
|
|
539
|
+
if (block.text) parts.push(block.text);
|
|
540
|
+
}
|
|
541
|
+
} else {
|
|
542
|
+
throw new TypeError("Anthropic system messages must contain text.");
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return parts.join("\n");
|
|
546
|
+
}
|
|
425
547
|
function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
548
|
+
const system = extractAnthropicSystemPrompt(messages, systemPrompt);
|
|
426
549
|
const formatted = [];
|
|
427
550
|
for (let i = 0; i < messages.length; i++) {
|
|
428
551
|
const msg = messages[i];
|
|
@@ -451,7 +574,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
451
574
|
{
|
|
452
575
|
type: "tool_result",
|
|
453
576
|
tool_use_id: msg.tool_call_id,
|
|
454
|
-
content: msg.content ?? ""
|
|
577
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput, "anthropic") : msg.content ?? ""
|
|
455
578
|
}
|
|
456
579
|
];
|
|
457
580
|
while (i + 1 < messages.length && messages[i + 1].role === "tool") {
|
|
@@ -461,7 +584,7 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
461
584
|
toolResults.push({
|
|
462
585
|
type: "tool_result",
|
|
463
586
|
tool_use_id: nextTool.tool_call_id,
|
|
464
|
-
content: nextTool.content ?? ""
|
|
587
|
+
content: nextTool.modelOutput ? toolOutputForProvider(nextTool.modelOutput, "anthropic") : nextTool.content ?? ""
|
|
465
588
|
});
|
|
466
589
|
}
|
|
467
590
|
}
|
|
@@ -477,11 +600,11 @@ function formatMessagesForAnthropic(messages, systemPrompt) {
|
|
|
477
600
|
}
|
|
478
601
|
}
|
|
479
602
|
return {
|
|
480
|
-
system
|
|
603
|
+
system,
|
|
481
604
|
messages: formatted
|
|
482
605
|
};
|
|
483
606
|
}
|
|
484
|
-
function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
607
|
+
function formatMessagesForOpenAI(messages, systemPrompt, preserveProviderMetadata = false) {
|
|
485
608
|
const formatted = [];
|
|
486
609
|
if (systemPrompt) {
|
|
487
610
|
formatted.push({ role: "system", content: systemPrompt });
|
|
@@ -499,7 +622,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
499
622
|
const assistantMsg = {
|
|
500
623
|
role: "assistant",
|
|
501
624
|
// Gemini/xAI (OpenAI-compatible) reject content: "" on assistant messages with tool_calls
|
|
502
|
-
content: hasToolCalls ? msg.content || null : msg.content
|
|
625
|
+
content: hasToolCalls ? msg.content || null : msg.content,
|
|
626
|
+
...preserveProviderMetadata && msg.providerMetadata ? { providerMetadata: msg.providerMetadata } : {}
|
|
503
627
|
};
|
|
504
628
|
if (hasToolCalls) {
|
|
505
629
|
assistantMsg.tool_calls = msg.tool_calls;
|
|
@@ -508,7 +632,8 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
508
632
|
} else if (msg.role === "tool" && msg.tool_call_id) {
|
|
509
633
|
formatted.push({
|
|
510
634
|
role: "tool",
|
|
511
|
-
content: msg.content ?? "",
|
|
635
|
+
content: preserveProviderMetadata ? msg.content ?? "" : textToolOutput(msg.modelOutput, msg.content ?? ""),
|
|
636
|
+
...preserveProviderMetadata && msg.modelOutput ? { modelOutput: msg.modelOutput } : {},
|
|
512
637
|
tool_call_id: msg.tool_call_id
|
|
513
638
|
});
|
|
514
639
|
}
|
|
@@ -516,6 +641,64 @@ function formatMessagesForOpenAI(messages, systemPrompt) {
|
|
|
516
641
|
return formatted;
|
|
517
642
|
}
|
|
518
643
|
|
|
644
|
+
// src/core/openai-responses.ts
|
|
645
|
+
function resolveOpenAITransport(defaults, overrides) {
|
|
646
|
+
return {
|
|
647
|
+
api: overrides?.api ?? defaults.api ?? "auto",
|
|
648
|
+
responses: defaults.responses !== void 0 || overrides?.responses !== void 0 ? { ...defaults.responses, ...overrides?.responses } : void 0
|
|
649
|
+
};
|
|
650
|
+
}
|
|
651
|
+
function useOpenAIResponses(model, baseURL, parameters, transport, hasTools, hasReplay, nativeToolSearch = false) {
|
|
652
|
+
const api = transport.api ?? "auto";
|
|
653
|
+
if (!["auto", "chat", "responses"].includes(api)) {
|
|
654
|
+
throw new Error(`Unknown OpenAI API selection: ${api}`);
|
|
655
|
+
}
|
|
656
|
+
if (api === "chat") {
|
|
657
|
+
if (transport.responses !== void 0 || nativeToolSearch) {
|
|
658
|
+
throw new Error(
|
|
659
|
+
"Responses options and native tool search require the Responses API"
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
return false;
|
|
663
|
+
}
|
|
664
|
+
let officialEndpoint = !baseURL;
|
|
665
|
+
try {
|
|
666
|
+
officialEndpoint = !baseURL || new URL(baseURL).hostname === "api.openai.com";
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
669
|
+
return api === "responses" || transport.responses !== void 0 || hasReplay && officialEndpoint || nativeToolSearch || hasTools && requiresOpenAIResponses(model, baseURL, parameters);
|
|
670
|
+
}
|
|
671
|
+
function responseMetadata(response) {
|
|
672
|
+
const output = Array.isArray(response?.output) ? response.output : [];
|
|
673
|
+
return {
|
|
674
|
+
openai: {
|
|
675
|
+
response: {
|
|
676
|
+
id: response?.id,
|
|
677
|
+
model: response?.model,
|
|
678
|
+
status: response?.status,
|
|
679
|
+
output,
|
|
680
|
+
usage: response?.usage,
|
|
681
|
+
store: response?.store,
|
|
682
|
+
refusals: output.flatMap(
|
|
683
|
+
(item) => item?.type === "message" && Array.isArray(item.content) ? item.content.filter(
|
|
684
|
+
(part) => part?.type === "refusal" && typeof part.refusal === "string"
|
|
685
|
+
).map((part) => part.refusal) : []
|
|
686
|
+
)
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
function getResponseReplay(metadata) {
|
|
692
|
+
const response = metadata?.openai?.response;
|
|
693
|
+
if (response === void 0) return void 0;
|
|
694
|
+
if (!Array.isArray(response.output) || response.output.some((item) => !item || typeof item.type !== "string")) {
|
|
695
|
+
throw new Error(
|
|
696
|
+
"Invalid OpenAI Responses replay metadata: output must contain typed items"
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
return response.output;
|
|
700
|
+
}
|
|
701
|
+
|
|
519
702
|
// src/core/provider-error.ts
|
|
520
703
|
function providerErrorEvent(error, code) {
|
|
521
704
|
const details = error ?? {};
|
|
@@ -592,13 +775,16 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
592
775
|
}));
|
|
593
776
|
}
|
|
594
777
|
shouldUseResponsesApi(request) {
|
|
595
|
-
|
|
596
|
-
if (request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false)
|
|
597
|
-
return true;
|
|
598
|
-
return requiresOpenAIResponses(
|
|
778
|
+
return useOpenAIResponses(
|
|
599
779
|
request.config?.model || this.model,
|
|
600
780
|
this.config.baseUrl,
|
|
601
|
-
this.parameterOptions(request)
|
|
781
|
+
this.parameterOptions(request),
|
|
782
|
+
resolveOpenAITransport(this.config, request.config?.openai),
|
|
783
|
+
this.toolDefinitions(request).length > 0,
|
|
784
|
+
!!(request.rawMessages ?? request.messages)?.some(
|
|
785
|
+
(message) => message.providerMetadata?.openai?.response
|
|
786
|
+
),
|
|
787
|
+
request.providerToolOptions?.openai?.nativeToolSearch?.enabled === true && request.providerToolOptions.openai.nativeToolSearch.useResponsesApi !== false
|
|
602
788
|
);
|
|
603
789
|
}
|
|
604
790
|
/**
|
|
@@ -631,11 +817,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
631
817
|
});
|
|
632
818
|
}
|
|
633
819
|
buildResponsesInput(request) {
|
|
634
|
-
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages) : formatMessagesForOpenAI(request.messages, void 0);
|
|
820
|
+
const sourceMessages = request.rawMessages && request.rawMessages.length > 0 ? this.formatRawMessages(request.rawMessages, true) : formatMessagesForOpenAI(request.messages, void 0, true);
|
|
635
821
|
const input = [];
|
|
636
822
|
for (const message of sourceMessages) {
|
|
637
823
|
if (message.role === "system") {
|
|
638
|
-
if (
|
|
824
|
+
if (message.content && message.content !== request.systemPrompt) {
|
|
639
825
|
input.push({
|
|
640
826
|
type: "message",
|
|
641
827
|
role: "developer",
|
|
@@ -645,6 +831,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
645
831
|
continue;
|
|
646
832
|
}
|
|
647
833
|
if (message.role === "assistant") {
|
|
834
|
+
const replay = getResponseReplay(message.providerMetadata);
|
|
835
|
+
if (replay) {
|
|
836
|
+
input.push(...replay);
|
|
837
|
+
continue;
|
|
838
|
+
}
|
|
648
839
|
const content = this.toResponsesContent(message.content, "assistant");
|
|
649
840
|
if (typeof content === "string" ? content : Array.isArray(content) && content.length > 0) {
|
|
650
841
|
input.push({
|
|
@@ -668,7 +859,7 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
668
859
|
input.push({
|
|
669
860
|
type: "function_call_output",
|
|
670
861
|
call_id: message.tool_call_id,
|
|
671
|
-
output: typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
862
|
+
output: message.modelOutput ? toolOutputForProvider(message.modelOutput, "responses") : typeof message.content === "string" ? message.content : JSON.stringify(message.content ?? null)
|
|
672
863
|
});
|
|
673
864
|
continue;
|
|
674
865
|
}
|
|
@@ -682,10 +873,12 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
682
873
|
return input;
|
|
683
874
|
}
|
|
684
875
|
/** Preserve Copilot screenshot attachments on every OpenAI transport. */
|
|
685
|
-
formatRawMessages(messages) {
|
|
876
|
+
formatRawMessages(messages, preserveProviderMetadata = false) {
|
|
686
877
|
return messages.map((message) => {
|
|
687
|
-
const { attachments, ...rest } = message;
|
|
688
|
-
let content = message.content;
|
|
878
|
+
const { attachments, providerMetadata, modelOutput, ...rest } = message;
|
|
879
|
+
let content = message.role === "tool" && !preserveProviderMetadata ? textToolOutput(modelOutput, String(message.content ?? "")) : message.content;
|
|
880
|
+
if (preserveProviderMetadata && modelOutput)
|
|
881
|
+
rest.modelOutput = modelOutput;
|
|
689
882
|
if (message.role === "assistant" && Array.isArray(message.tool_calls) && message.tool_calls.length > 0 && content === "") {
|
|
690
883
|
content = null;
|
|
691
884
|
}
|
|
@@ -698,7 +891,11 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
698
891
|
content = [...parts, ...images];
|
|
699
892
|
}
|
|
700
893
|
}
|
|
701
|
-
return {
|
|
894
|
+
return {
|
|
895
|
+
...rest,
|
|
896
|
+
content,
|
|
897
|
+
...preserveProviderMetadata && providerMetadata ? { providerMetadata } : {}
|
|
898
|
+
};
|
|
702
899
|
});
|
|
703
900
|
}
|
|
704
901
|
/**
|
|
@@ -779,14 +976,25 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
779
976
|
).map((part) => part.text) : []
|
|
780
977
|
).join("") : "";
|
|
781
978
|
const content = textFromOutput || (typeof response?.output_text === "string" ? response.output_text : "");
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
name
|
|
785
|
-
|
|
786
|
-
|
|
979
|
+
const seenCallIds = /* @__PURE__ */ new Set();
|
|
980
|
+
const toolCalls = Array.isArray(response?.output) ? response.output.filter((item) => item?.type === "function_call").map((item) => {
|
|
981
|
+
if (typeof item.call_id !== "string" || !item.call_id || typeof item.name !== "string" || !item.name || typeof item.arguments !== "string" || item.status && item.status !== "completed") {
|
|
982
|
+
throw new Error("Responses contains an incomplete function call");
|
|
983
|
+
}
|
|
984
|
+
if (seenCallIds.has(item.call_id))
|
|
985
|
+
throw new Error("Responses contains duplicate function call IDs");
|
|
986
|
+
seenCallIds.add(item.call_id);
|
|
987
|
+
const args = JSON.parse(item.arguments);
|
|
988
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
989
|
+
throw new Error(
|
|
990
|
+
"Responses function arguments must be a JSON object"
|
|
991
|
+
);
|
|
992
|
+
return { id: item.call_id, name: item.name, args };
|
|
993
|
+
}) : [];
|
|
787
994
|
return {
|
|
788
995
|
content,
|
|
789
996
|
toolCalls,
|
|
997
|
+
providerMetadata: responseMetadata(response),
|
|
790
998
|
usage: response?.usage ? {
|
|
791
999
|
promptTokens: response.usage.input_tokens ?? 0,
|
|
792
1000
|
completionTokens: response.usage.output_tokens ?? 0,
|
|
@@ -797,6 +1005,17 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
797
1005
|
}
|
|
798
1006
|
buildResponsesPayload(request, stream) {
|
|
799
1007
|
const openaiToolOptions = request.providerToolOptions?.openai;
|
|
1008
|
+
const options = resolveOpenAITransport(
|
|
1009
|
+
this.config,
|
|
1010
|
+
request.config?.openai
|
|
1011
|
+
).responses;
|
|
1012
|
+
const parameters = buildOpenAIParameters(
|
|
1013
|
+
request.config?.model || this.model,
|
|
1014
|
+
request.config?.maxTokens ?? this.config.maxTokens,
|
|
1015
|
+
request.config?.temperature ?? this.config.temperature,
|
|
1016
|
+
this.parameterOptions(request),
|
|
1017
|
+
"responses"
|
|
1018
|
+
);
|
|
800
1019
|
const responsesTextFormat = toOpenAIResponsesTextFormat(
|
|
801
1020
|
request.config?.responseFormat
|
|
802
1021
|
);
|
|
@@ -812,13 +1031,26 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
812
1031
|
),
|
|
813
1032
|
tool_choice: openaiToolOptions?.toolChoice,
|
|
814
1033
|
parallel_tool_calls: openaiToolOptions?.parallelToolCalls,
|
|
815
|
-
...
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
1034
|
+
...parameters,
|
|
1035
|
+
...options?.reasoningSummary ? {
|
|
1036
|
+
reasoning: {
|
|
1037
|
+
...parameters.reasoning,
|
|
1038
|
+
summary: options.reasoningSummary
|
|
1039
|
+
}
|
|
1040
|
+
} : {},
|
|
1041
|
+
...options?.store !== void 0 ? { store: options.store } : {},
|
|
1042
|
+
...options?.previousResponseId !== void 0 ? { previous_response_id: options.previousResponseId } : {},
|
|
1043
|
+
...options?.promptCacheKey !== void 0 ? { prompt_cache_key: options.promptCacheKey } : {},
|
|
1044
|
+
...options?.promptCacheOptions !== void 0 ? { prompt_cache_options: options.promptCacheOptions } : {},
|
|
1045
|
+
...options?.promptCacheRetention !== void 0 ? { prompt_cache_retention: options.promptCacheRetention } : {},
|
|
1046
|
+
...options?.store === false || options?.include ? {
|
|
1047
|
+
include: [
|
|
1048
|
+
.../* @__PURE__ */ new Set([
|
|
1049
|
+
...options?.include ?? [],
|
|
1050
|
+
...options?.store === false ? ["reasoning.encrypted_content"] : []
|
|
1051
|
+
])
|
|
1052
|
+
]
|
|
1053
|
+
} : {},
|
|
822
1054
|
...responsesTextFormat ? { text: { format: responsesTextFormat } } : {},
|
|
823
1055
|
stream
|
|
824
1056
|
};
|
|
@@ -877,6 +1109,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
877
1109
|
let usage;
|
|
878
1110
|
const citations = [];
|
|
879
1111
|
let completed = false;
|
|
1112
|
+
let terminalResponse;
|
|
1113
|
+
let responseIdentity = {};
|
|
1114
|
+
const outputItems = /* @__PURE__ */ new Map();
|
|
1115
|
+
let streamedText = "";
|
|
880
1116
|
function* flushToolCalls() {
|
|
881
1117
|
for (const call of toolCalls.values()) {
|
|
882
1118
|
if (!call.name)
|
|
@@ -893,17 +1129,36 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
893
1129
|
for await (const event of stream) {
|
|
894
1130
|
throwIfAborted(request.signal);
|
|
895
1131
|
logProviderPayload("openai", "stream chunk", event, request.debug);
|
|
1132
|
+
if (completed)
|
|
1133
|
+
throw new Error("Responses stream emitted an event after completion");
|
|
896
1134
|
const index = event?.output_index ?? 0;
|
|
897
1135
|
switch (event?.type) {
|
|
1136
|
+
case "response.created":
|
|
1137
|
+
responseIdentity = {
|
|
1138
|
+
id: event.response?.id,
|
|
1139
|
+
model: event.response?.model
|
|
1140
|
+
};
|
|
1141
|
+
break;
|
|
1142
|
+
case "response.output_item.done":
|
|
1143
|
+
if (event.item) outputItems.set(index, event.item);
|
|
1144
|
+
if (event.item?.type === "function_call") {
|
|
1145
|
+
toolCalls.set(index, {
|
|
1146
|
+
id: event.item.call_id,
|
|
1147
|
+
name: event.item.name,
|
|
1148
|
+
arguments: event.item.arguments
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
break;
|
|
898
1152
|
case "response.output_text.delta":
|
|
899
1153
|
if (event.delta) {
|
|
1154
|
+
streamedText += event.delta;
|
|
900
1155
|
yield { type: "message:delta", content: event.delta };
|
|
901
1156
|
}
|
|
902
1157
|
break;
|
|
903
1158
|
case "response.output_item.added":
|
|
904
1159
|
if (event.item?.type === "function_call") {
|
|
905
1160
|
toolCalls.set(index, {
|
|
906
|
-
id: event.item.call_id ??
|
|
1161
|
+
id: event.item.call_id ?? "",
|
|
907
1162
|
name: event.item.name ?? "",
|
|
908
1163
|
arguments: event.item.arguments ?? ""
|
|
909
1164
|
});
|
|
@@ -922,7 +1177,10 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
922
1177
|
break;
|
|
923
1178
|
}
|
|
924
1179
|
case "response.completed": {
|
|
1180
|
+
if (event.response?.status && event.response.status !== "completed")
|
|
1181
|
+
throw new Error(`Responses stream ${event.response.status}`);
|
|
925
1182
|
completed = true;
|
|
1183
|
+
terminalResponse = { ...responseIdentity, ...event.response };
|
|
926
1184
|
const found = this.collectResponsesCitations(
|
|
927
1185
|
event.response?.output,
|
|
928
1186
|
citations.length
|
|
@@ -959,12 +1217,64 @@ var OpenAIAdapter = class _OpenAIAdapter {
|
|
|
959
1217
|
throwIfAborted(request.signal);
|
|
960
1218
|
if (!completed)
|
|
961
1219
|
throw new Error("Responses stream ended without a completed response");
|
|
1220
|
+
const output = terminalResponse.output?.length ? terminalResponse.output : [...outputItems.entries()].sort(([a], [b]) => a - b).map(([, item]) => item);
|
|
1221
|
+
if (output.some((item) => item.type === "function_call"))
|
|
1222
|
+
toolCalls.clear();
|
|
1223
|
+
for (const [index, item] of output.entries()) {
|
|
1224
|
+
if (item.type === "function_call") {
|
|
1225
|
+
toolCalls.set(index, {
|
|
1226
|
+
id: item.call_id,
|
|
1227
|
+
name: item.name,
|
|
1228
|
+
arguments: item.arguments
|
|
1229
|
+
});
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
const uniqueCalls = /* @__PURE__ */ new Map();
|
|
1233
|
+
for (const call of toolCalls.values()) {
|
|
1234
|
+
if (!call.id || !call.name)
|
|
1235
|
+
throw new Error("Responses stream contains an incomplete tool call");
|
|
1236
|
+
uniqueCalls.set(call.id, call);
|
|
1237
|
+
}
|
|
1238
|
+
toolCalls.clear();
|
|
1239
|
+
[...uniqueCalls.values()].forEach(
|
|
1240
|
+
(call, index) => toolCalls.set(index, call)
|
|
1241
|
+
);
|
|
1242
|
+
if (!output.length && toolCalls.size) {
|
|
1243
|
+
for (const call of toolCalls.values())
|
|
1244
|
+
output.push({
|
|
1245
|
+
type: "function_call",
|
|
1246
|
+
call_id: call.id,
|
|
1247
|
+
name: call.name,
|
|
1248
|
+
arguments: call.arguments
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
if (!output.length && streamedText)
|
|
1252
|
+
output.push({
|
|
1253
|
+
type: "message",
|
|
1254
|
+
role: "assistant",
|
|
1255
|
+
content: [{ type: "output_text", text: streamedText, annotations: [] }]
|
|
1256
|
+
});
|
|
1257
|
+
terminalResponse.output = output;
|
|
1258
|
+
const finalText = this.parseResponsesResult(terminalResponse).content;
|
|
1259
|
+
if (finalText.startsWith(streamedText) && finalText.length > streamedText.length) {
|
|
1260
|
+
yield {
|
|
1261
|
+
type: "message:delta",
|
|
1262
|
+
content: finalText.slice(streamedText.length)
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
962
1265
|
yield* flushToolCalls();
|
|
963
1266
|
if (citations.length > 0) {
|
|
964
1267
|
yield { type: "citation", citations: deduplicateCitations(citations) };
|
|
965
1268
|
}
|
|
966
|
-
yield {
|
|
967
|
-
|
|
1269
|
+
yield {
|
|
1270
|
+
type: "message:end",
|
|
1271
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1272
|
+
};
|
|
1273
|
+
yield {
|
|
1274
|
+
type: "done",
|
|
1275
|
+
usage,
|
|
1276
|
+
providerMetadata: responseMetadata(terminalResponse)
|
|
1277
|
+
};
|
|
968
1278
|
}
|
|
969
1279
|
async *stream(request) {
|
|
970
1280
|
throwIfAborted(request.signal);
|
|
@@ -1350,7 +1660,7 @@ var AnthropicAdapter = class {
|
|
|
1350
1660
|
}
|
|
1351
1661
|
pendingToolResults.push({
|
|
1352
1662
|
tool_use_id: toolCallId,
|
|
1353
|
-
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
1663
|
+
content: msg.modelOutput ? toolOutputForProvider(msg.modelOutput, "anthropic") : typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
1354
1664
|
});
|
|
1355
1665
|
} else if (msg.role === "user") {
|
|
1356
1666
|
if (pendingToolResults.length > 0) {
|
|
@@ -1471,14 +1781,23 @@ var AnthropicAdapter = class {
|
|
|
1471
1781
|
buildRequestOptions(request) {
|
|
1472
1782
|
const responseFormat = request.config?.responseFormat;
|
|
1473
1783
|
const jsonObjectSuffix = responseFormat?.type === "json_object" ? "\n\nRespond with a single JSON object and no other text." : "";
|
|
1474
|
-
|
|
1784
|
+
let systemMessage;
|
|
1475
1785
|
let messages;
|
|
1476
1786
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
1787
|
+
systemMessage = extractAnthropicSystemPrompt(
|
|
1788
|
+
request.rawMessages,
|
|
1789
|
+
request.systemPrompt
|
|
1790
|
+
);
|
|
1477
1791
|
messages = this.convertToAnthropicMessages(request.rawMessages);
|
|
1478
1792
|
} else {
|
|
1479
|
-
const formatted = formatMessagesForAnthropic(
|
|
1793
|
+
const formatted = formatMessagesForAnthropic(
|
|
1794
|
+
request.messages,
|
|
1795
|
+
request.systemPrompt
|
|
1796
|
+
);
|
|
1797
|
+
systemMessage = formatted.system;
|
|
1480
1798
|
messages = formatted.messages;
|
|
1481
1799
|
}
|
|
1800
|
+
systemMessage += jsonObjectSuffix;
|
|
1482
1801
|
const anthropicNativeSearch = request.providerToolOptions?.anthropic?.nativeToolSearch;
|
|
1483
1802
|
const tools = anthropicNativeSearch?.enabled ? this.buildNativeSearchTools(
|
|
1484
1803
|
request.toolDefinitions ?? [],
|
|
@@ -1821,7 +2140,7 @@ async function formatMessagesForOllama(messages, systemPrompt) {
|
|
|
1821
2140
|
for (const msg of messages) {
|
|
1822
2141
|
const baseMessage = {
|
|
1823
2142
|
role: msg.role,
|
|
1824
|
-
content: msg.content ?? ""
|
|
2143
|
+
content: msg.role === "tool" ? textToolOutput(msg.modelOutput, msg.content ?? "") : msg.content ?? ""
|
|
1825
2144
|
};
|
|
1826
2145
|
if (msg.role === "user" && msg.metadata?.attachments) {
|
|
1827
2146
|
const images = await extractImagesFromAttachments(
|
|
@@ -1858,7 +2177,7 @@ async function processRawMessagesForOllama(rawMessages, systemPrompt) {
|
|
|
1858
2177
|
for (const msg of rawMessages) {
|
|
1859
2178
|
const baseMessage = {
|
|
1860
2179
|
role: msg.role,
|
|
1861
|
-
content: msg.content ?? ""
|
|
2180
|
+
content: msg.role === "tool" ? textToolOutput(msg.modelOutput, String(msg.content ?? "")) : msg.content ?? ""
|
|
1862
2181
|
};
|
|
1863
2182
|
if (msg.role === "user" && msg.attachments && Array.isArray(msg.attachments)) {
|
|
1864
2183
|
const attachments = msg.attachments;
|
|
@@ -2068,6 +2387,10 @@ function messageToGeminiContent(msg) {
|
|
|
2068
2387
|
if (msg.role === "system") return null;
|
|
2069
2388
|
const parts = [];
|
|
2070
2389
|
if (msg.role === "tool" && msg.tool_call_id) {
|
|
2390
|
+
msg = {
|
|
2391
|
+
...msg,
|
|
2392
|
+
content: textToolOutput(msg.modelOutput, msg.content ?? "")
|
|
2393
|
+
};
|
|
2071
2394
|
let responseData;
|
|
2072
2395
|
try {
|
|
2073
2396
|
responseData = JSON.parse(msg.content || "{}");
|
|
@@ -2528,6 +2851,13 @@ var AzureAdapter = class {
|
|
|
2528
2851
|
let messages;
|
|
2529
2852
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
2530
2853
|
const processedMessages = request.rawMessages.map((msg) => {
|
|
2854
|
+
const { modelOutput, ...rest } = msg;
|
|
2855
|
+
msg = {
|
|
2856
|
+
...rest,
|
|
2857
|
+
...msg.role === "tool" ? {
|
|
2858
|
+
content: textToolOutput(modelOutput, String(msg.content ?? ""))
|
|
2859
|
+
} : {}
|
|
2860
|
+
};
|
|
2531
2861
|
const hasAttachments = msg.attachments && Array.isArray(msg.attachments) && msg.attachments.length > 0;
|
|
2532
2862
|
if (hasAttachments) {
|
|
2533
2863
|
const content = [];
|
|
@@ -2658,7 +2988,10 @@ var AzureAdapter = class {
|
|
|
2658
2988
|
const client = await this.getClient();
|
|
2659
2989
|
let messages;
|
|
2660
2990
|
if (request.rawMessages && request.rawMessages.length > 0) {
|
|
2661
|
-
messages = request.rawMessages
|
|
2991
|
+
messages = request.rawMessages.map(({ modelOutput, ...msg }) => ({
|
|
2992
|
+
...msg,
|
|
2993
|
+
...msg.role === "tool" ? { content: textToolOutput(modelOutput, String(msg.content ?? "")) } : {}
|
|
2994
|
+
}));
|
|
2662
2995
|
if (request.systemPrompt) {
|
|
2663
2996
|
const hasSystem = messages.some((m) => m.role === "system");
|
|
2664
2997
|
if (!hasSystem) {
|