headroom-ai 0.40.0 → 0.42.0
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 +8 -0
- package/dist/adapters/anthropic.cjs +4 -4
- package/dist/adapters/anthropic.d.cts +1 -1
- package/dist/adapters/anthropic.d.ts +1 -1
- package/dist/adapters/anthropic.js +1 -1
- package/dist/adapters/gemini.cjs +3 -3
- package/dist/adapters/gemini.d.cts +1 -1
- package/dist/adapters/gemini.d.ts +1 -1
- package/dist/adapters/gemini.js +1 -1
- package/dist/adapters/openai.cjs +2 -2
- package/dist/adapters/openai.d.cts +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.js +1 -1
- package/dist/adapters/vercel-ai.cjs +7 -7
- package/dist/adapters/vercel-ai.d.cts +1 -1
- package/dist/adapters/vercel-ai.d.ts +1 -1
- package/dist/adapters/vercel-ai.js +1 -1
- package/dist/{chunk-N7HYJMEN.cjs → chunk-CINZDAE4.cjs} +247 -26
- package/dist/chunk-CINZDAE4.cjs.map +1 -0
- package/dist/{chunk-FJQ65W3R.js → chunk-UVX5TGIN.js} +247 -26
- package/dist/chunk-UVX5TGIN.js.map +1 -0
- package/dist/index.cjs +35 -35
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/{types-Cjdl75F4.d.cts → types-Bxcai7Tt.d.cts} +5 -1
- package/dist/{types-Cjdl75F4.d.ts → types-Bxcai7Tt.d.ts} +5 -1
- package/package.json +2 -2
- package/dist/chunk-FJQ65W3R.js.map +0 -1
- package/dist/chunk-N7HYJMEN.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -279,8 +279,16 @@ const hints = await client.feedback.getHints('list_servers');
|
|
|
279
279
|
// TOIN (Tool Output Intelligence Network)
|
|
280
280
|
const toinStats = await client.toin.getStats();
|
|
281
281
|
const patterns = await client.toin.getPatterns(20);
|
|
282
|
+
const pattern = patterns[0] && await client.toin.getPattern(patterns[0].hash);
|
|
282
283
|
```
|
|
283
284
|
|
|
285
|
+
Each `hash` is the complete scoped aggregation key, including tenant, auth mode,
|
|
286
|
+
model family, and tool signature. Pass it back unchanged for an exact lookup;
|
|
287
|
+
the client URL-encodes it. Shorter aggregation-key prefixes are accepted only
|
|
288
|
+
when they identify one pattern; ambiguous prefixes return HTTP 409 rather than
|
|
289
|
+
an arbitrary pattern.
|
|
290
|
+
|
|
291
|
+
|
|
284
292
|
## Configuration Types
|
|
285
293
|
|
|
286
294
|
Full TypeScript interfaces for every Python config dataclass.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkCINZDAE4_cjs = require('../chunk-CINZDAE4.cjs');
|
|
4
4
|
|
|
5
5
|
// src/adapters/anthropic.ts
|
|
6
6
|
function withHeadroom(client, options = {}) {
|
|
@@ -8,13 +8,13 @@ function withHeadroom(client, options = {}) {
|
|
|
8
8
|
const compressedCreate = async (params) => {
|
|
9
9
|
const messages = params.messages;
|
|
10
10
|
const model = options.model ?? params.model ?? "claude-sonnet-4-5-20250929";
|
|
11
|
-
const openaiMessages =
|
|
12
|
-
const result = await
|
|
11
|
+
const openaiMessages = chunkCINZDAE4_cjs.anthropicToOpenAI(messages);
|
|
12
|
+
const result = await chunkCINZDAE4_cjs.compress(openaiMessages, {
|
|
13
13
|
stack: "adapter_ts_anthropic",
|
|
14
14
|
...options,
|
|
15
15
|
model
|
|
16
16
|
});
|
|
17
|
-
const anthropicMessages = result.compressed ?
|
|
17
|
+
const anthropicMessages = result.compressed ? chunkCINZDAE4_cjs.openAIToAnthropic(result.messages) : messages;
|
|
18
18
|
return originalCreate({
|
|
19
19
|
...params,
|
|
20
20
|
messages: anthropicMessages
|
package/dist/adapters/gemini.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkCINZDAE4_cjs = require('../chunk-CINZDAE4.cjs');
|
|
4
4
|
|
|
5
5
|
// src/adapters/gemini.ts
|
|
6
6
|
function withHeadroom(model, options = {}) {
|
|
@@ -9,7 +9,7 @@ function withHeadroom(model, options = {}) {
|
|
|
9
9
|
const compressedGenerate = async (params) => {
|
|
10
10
|
const contents = params.contents ?? params;
|
|
11
11
|
const modelName = options.model ?? "gemini-2.0-flash";
|
|
12
|
-
const result = await
|
|
12
|
+
const result = await chunkCINZDAE4_cjs.compress(
|
|
13
13
|
Array.isArray(contents) ? contents : [contents],
|
|
14
14
|
{ stack: "adapter_ts_gemini", ...options, model: modelName }
|
|
15
15
|
);
|
|
@@ -19,7 +19,7 @@ function withHeadroom(model, options = {}) {
|
|
|
19
19
|
const compressedStream = originalStream ? async (params) => {
|
|
20
20
|
const contents = params.contents ?? params;
|
|
21
21
|
const modelName = options.model ?? "gemini-2.0-flash";
|
|
22
|
-
const result = await
|
|
22
|
+
const result = await chunkCINZDAE4_cjs.compress(
|
|
23
23
|
Array.isArray(contents) ? contents : [contents],
|
|
24
24
|
{ stack: "adapter_ts_gemini", ...options, model: modelName }
|
|
25
25
|
);
|
package/dist/adapters/gemini.js
CHANGED
package/dist/adapters/openai.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkCINZDAE4_cjs = require('../chunk-CINZDAE4.cjs');
|
|
4
4
|
|
|
5
5
|
// src/adapters/openai.ts
|
|
6
6
|
function withHeadroom(client, options = {}) {
|
|
@@ -10,7 +10,7 @@ function withHeadroom(client, options = {}) {
|
|
|
10
10
|
const compressedCreate = async (params) => {
|
|
11
11
|
const messages = params.messages;
|
|
12
12
|
const model = options.model ?? params.model ?? "gpt-4o";
|
|
13
|
-
const result = await
|
|
13
|
+
const result = await chunkCINZDAE4_cjs.compress(messages, {
|
|
14
14
|
stack: "adapter_ts_openai",
|
|
15
15
|
...options,
|
|
16
16
|
model
|
package/dist/adapters/openai.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkCINZDAE4_cjs = require('../chunk-CINZDAE4.cjs');
|
|
4
4
|
var module$1 = require('module');
|
|
5
5
|
|
|
6
6
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
@@ -12,25 +12,25 @@ function headroomMiddleware(options = {}) {
|
|
|
12
12
|
const prompt = params.prompt;
|
|
13
13
|
if (!prompt || prompt.length === 0) return params;
|
|
14
14
|
const model = options.model ?? params.modelId ?? "gpt-4o";
|
|
15
|
-
const openaiMessages =
|
|
16
|
-
const result = await
|
|
15
|
+
const openaiMessages = chunkCINZDAE4_cjs.vercelToOpenAI(prompt);
|
|
16
|
+
const result = await chunkCINZDAE4_cjs.compress(openaiMessages, {
|
|
17
17
|
stack: "adapter_ts_vercel_ai",
|
|
18
18
|
...options,
|
|
19
19
|
model
|
|
20
20
|
});
|
|
21
21
|
if (!result.compressed) return params;
|
|
22
|
-
const compressedPrompt =
|
|
22
|
+
const compressedPrompt = chunkCINZDAE4_cjs.openAIToVercel(result.messages);
|
|
23
23
|
return { ...params, prompt: compressedPrompt };
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
async function compressVercelMessages(messages, options = {}) {
|
|
28
|
-
const openaiMessages =
|
|
29
|
-
const result = await
|
|
28
|
+
const openaiMessages = chunkCINZDAE4_cjs.vercelToOpenAI(messages);
|
|
29
|
+
const result = await chunkCINZDAE4_cjs.compress(openaiMessages, {
|
|
30
30
|
stack: "adapter_ts_vercel_ai",
|
|
31
31
|
...options
|
|
32
32
|
});
|
|
33
|
-
const vercelMessages =
|
|
33
|
+
const vercelMessages = chunkCINZDAE4_cjs.openAIToVercel(result.messages);
|
|
34
34
|
return {
|
|
35
35
|
...result,
|
|
36
36
|
messages: vercelMessages
|
|
@@ -181,6 +181,11 @@ function makeFallbackResult(messages) {
|
|
|
181
181
|
compressed: false
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
|
+
function trimTrailingSlashes(value) {
|
|
185
|
+
let end = value.length;
|
|
186
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) end--;
|
|
187
|
+
return value.slice(0, end);
|
|
188
|
+
}
|
|
184
189
|
var ChatCompletions = class {
|
|
185
190
|
constructor(client) {
|
|
186
191
|
this.client = client;
|
|
@@ -283,7 +288,9 @@ var HeadroomClient = class {
|
|
|
283
288
|
/** Anthropic-style messages API. */
|
|
284
289
|
messages;
|
|
285
290
|
constructor(options = {}) {
|
|
286
|
-
this.baseUrl = (
|
|
291
|
+
this.baseUrl = trimTrailingSlashes(
|
|
292
|
+
options.baseUrl ?? getEnv("HEADROOM_BASE_URL") ?? DEFAULT_BASE_URL
|
|
293
|
+
);
|
|
287
294
|
this.apiKey = options.apiKey ?? getEnv("HEADROOM_API_KEY");
|
|
288
295
|
this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
289
296
|
this.fallback = options.fallback ?? true;
|
|
@@ -607,7 +614,11 @@ function detectFormat(messages) {
|
|
|
607
614
|
for (const part of msg.content) {
|
|
608
615
|
if (part.type === "tool-call" || part.type === "tool-result") return "vercel";
|
|
609
616
|
if (part.type === "tool_use" || part.type === "tool_result") return "anthropic";
|
|
610
|
-
if (part.type === "image" && part.source?.type) return "anthropic";
|
|
617
|
+
if ((part.type === "image" || part.type === "document") && part.source?.type) return "anthropic";
|
|
618
|
+
if (part && typeof part === "object") {
|
|
619
|
+
if (part.type === "file" && ("data" in part || "mediaType" in part)) return "vercel";
|
|
620
|
+
if (part.type === "image" && "image" in part) return "vercel";
|
|
621
|
+
}
|
|
611
622
|
}
|
|
612
623
|
}
|
|
613
624
|
}
|
|
@@ -626,6 +637,50 @@ function openAIImageBlock(url) {
|
|
|
626
637
|
if (m) return { type: "image", source: { type: "base64", media_type: m[1], data: m[2] } };
|
|
627
638
|
return { type: "image", source: { type: "url", url } };
|
|
628
639
|
}
|
|
640
|
+
var ANTHROPIC_DOCUMENT_FIELDS = ["title", "context", "citations", "cache_control"];
|
|
641
|
+
function anthropicMediaImageUrl(block) {
|
|
642
|
+
if (block.type === "image") {
|
|
643
|
+
const url = anthropicImageUrl(block.source);
|
|
644
|
+
return url ? { url } : null;
|
|
645
|
+
}
|
|
646
|
+
if (block.type !== "document" || !block.source || typeof block.source !== "object") return null;
|
|
647
|
+
const src = block.source;
|
|
648
|
+
let out;
|
|
649
|
+
if (src.type === "base64" && src.media_type && src.data) {
|
|
650
|
+
out = { url: `data:${src.media_type};base64,${src.data}` };
|
|
651
|
+
} else if (src.type === "url" && typeof src.url === "string") {
|
|
652
|
+
out = { url: src.url, mime_type: "application/pdf" };
|
|
653
|
+
} else if (src.type === "text" && typeof src.data === "string") {
|
|
654
|
+
out = {
|
|
655
|
+
url: `data:${src.media_type || "text/plain"};base64,${bytesToBase64(new TextEncoder().encode(src.data))}`,
|
|
656
|
+
source_type: "text"
|
|
657
|
+
};
|
|
658
|
+
} else {
|
|
659
|
+
out = { url: "data:;base64,", source: src };
|
|
660
|
+
}
|
|
661
|
+
const fields = {};
|
|
662
|
+
for (const k of ANTHROPIC_DOCUMENT_FIELDS) if (block[k] !== void 0) fields[k] = block[k];
|
|
663
|
+
if (Object.keys(fields).length > 0) out.document = fields;
|
|
664
|
+
return out;
|
|
665
|
+
}
|
|
666
|
+
function anthropicMediaBlock(imageUrl) {
|
|
667
|
+
const url = imageUrl.url;
|
|
668
|
+
const m = /^data:([^;,]*);base64,(.*)$/s.exec(url);
|
|
669
|
+
const mediaType = m && m[1] || (typeof imageUrl.mime_type === "string" ? imageUrl.mime_type : void 0);
|
|
670
|
+
const fields = imageUrl.document && typeof imageUrl.document === "object" ? imageUrl.document : {};
|
|
671
|
+
if (imageUrl.source && typeof imageUrl.source === "object") {
|
|
672
|
+
return { type: "document", source: imageUrl.source, ...fields };
|
|
673
|
+
}
|
|
674
|
+
if (imageUrl.source_type === "text" && m) {
|
|
675
|
+
return { type: "document", source: { type: "text", media_type: "text/plain", data: base64ToText(m[2]) }, ...fields };
|
|
676
|
+
}
|
|
677
|
+
if (mediaType === "application/pdf") {
|
|
678
|
+
const source = m ? { type: "base64", media_type: "application/pdf", data: m[2] } : { type: "url", url };
|
|
679
|
+
return { type: "document", source, ...fields };
|
|
680
|
+
}
|
|
681
|
+
if (mediaType === void 0 || mediaType.startsWith("image/")) return openAIImageBlock(url);
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
629
684
|
function anthropicToOpenAI(messages) {
|
|
630
685
|
const result = [];
|
|
631
686
|
for (const msg of messages) {
|
|
@@ -636,12 +691,12 @@ function anthropicToOpenAI(messages) {
|
|
|
636
691
|
}
|
|
637
692
|
if (Array.isArray(msg.content)) {
|
|
638
693
|
const toolResults = msg.content.filter((b) => b.type === "tool_result");
|
|
639
|
-
const
|
|
640
|
-
if (
|
|
641
|
-
const parts = msg.content.filter((b) => b.type === "text" || b.type === "image").map((b) => {
|
|
694
|
+
const hasMedia = msg.content.some((b) => b.type === "image" || b.type === "document");
|
|
695
|
+
if (hasMedia) {
|
|
696
|
+
const parts = msg.content.filter((b) => b.type === "text" || b.type === "image" || b.type === "document").map((b) => {
|
|
642
697
|
if (b.type === "text") return { type: "text", text: b.text };
|
|
643
|
-
const
|
|
644
|
-
return
|
|
698
|
+
const imageUrl = anthropicMediaImageUrl(b);
|
|
699
|
+
return imageUrl ? { type: "image_url", image_url: imageUrl } : null;
|
|
645
700
|
}).filter((p) => p !== null);
|
|
646
701
|
if (parts.length > 0) {
|
|
647
702
|
result.push({ role: "user", content: parts });
|
|
@@ -674,7 +729,17 @@ function anthropicToOpenAI(messages) {
|
|
|
674
729
|
if (Array.isArray(msg.content)) {
|
|
675
730
|
const textBlocks = msg.content.filter((b) => b.type === "text");
|
|
676
731
|
const toolUseBlocks = msg.content.filter((b) => b.type === "tool_use");
|
|
677
|
-
const
|
|
732
|
+
const hasMedia = msg.content.some((b) => b.type === "image" || b.type === "document");
|
|
733
|
+
let content;
|
|
734
|
+
if (hasMedia) {
|
|
735
|
+
content = msg.content.filter((b) => b.type === "text" || b.type === "image" || b.type === "document").map((b) => {
|
|
736
|
+
if (b.type === "text") return { type: "text", text: b.text };
|
|
737
|
+
const imageUrl = anthropicMediaImageUrl(b);
|
|
738
|
+
return imageUrl ? { type: "image_url", image_url: imageUrl } : null;
|
|
739
|
+
}).filter((p) => p !== null);
|
|
740
|
+
} else {
|
|
741
|
+
content = textBlocks.length > 0 ? textBlocks.map((b) => b.text).join("\n") : null;
|
|
742
|
+
}
|
|
678
743
|
const openaiMsg = { role: "assistant", content };
|
|
679
744
|
if (toolUseBlocks.length > 0) {
|
|
680
745
|
openaiMsg.tool_calls = toolUseBlocks.map((b) => ({
|
|
@@ -708,7 +773,7 @@ function openAIToAnthropic(messages) {
|
|
|
708
773
|
role: "user",
|
|
709
774
|
content: msg.content.map((p) => {
|
|
710
775
|
if (p.type === "text") return { type: "text", text: p.text };
|
|
711
|
-
if (p.type === "image_url") return
|
|
776
|
+
if (p.type === "image_url") return anthropicMediaBlock(p.image_url) ?? { type: "text", text: "" };
|
|
712
777
|
return { type: "text", text: "" };
|
|
713
778
|
})
|
|
714
779
|
});
|
|
@@ -717,7 +782,17 @@ function openAIToAnthropic(messages) {
|
|
|
717
782
|
}
|
|
718
783
|
if (msg.role === "assistant") {
|
|
719
784
|
const blocks = [];
|
|
720
|
-
if (msg.content
|
|
785
|
+
if (typeof msg.content === "string") {
|
|
786
|
+
if (msg.content) blocks.push({ type: "text", text: msg.content });
|
|
787
|
+
} else if (Array.isArray(msg.content)) {
|
|
788
|
+
for (const g of groupAssistantParts(msg.content)) {
|
|
789
|
+
if ("text" in g) blocks.push({ type: "text", text: g.text });
|
|
790
|
+
else {
|
|
791
|
+
const block = anthropicMediaBlock(g.image_url);
|
|
792
|
+
if (block) blocks.push(block);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
}
|
|
721
796
|
if (msg.tool_calls) {
|
|
722
797
|
for (const tc of msg.tool_calls) {
|
|
723
798
|
blocks.push({
|
|
@@ -746,6 +821,121 @@ function openAIToAnthropic(messages) {
|
|
|
746
821
|
}
|
|
747
822
|
return result;
|
|
748
823
|
}
|
|
824
|
+
function bytesToBase64(bytes) {
|
|
825
|
+
if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
|
|
826
|
+
let binary = "";
|
|
827
|
+
for (let i = 0; i < bytes.length; i += 32768) {
|
|
828
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
829
|
+
}
|
|
830
|
+
return btoa(binary);
|
|
831
|
+
}
|
|
832
|
+
function parseUrl(value) {
|
|
833
|
+
try {
|
|
834
|
+
return new URL(value);
|
|
835
|
+
} catch {
|
|
836
|
+
return null;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
function base64ToText(b64) {
|
|
840
|
+
if (typeof Buffer !== "undefined") return Buffer.from(b64, "base64").toString("utf8");
|
|
841
|
+
const binary = atob(b64);
|
|
842
|
+
const bytes = new Uint8Array(binary.length);
|
|
843
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
844
|
+
return new TextDecoder().decode(bytes);
|
|
845
|
+
}
|
|
846
|
+
function isProviderReference(v) {
|
|
847
|
+
return !!v && typeof v === "object" && !Array.isArray(v) && !(v instanceof Uint8Array) && !(v instanceof ArrayBuffer) && !(v instanceof URL) && v.type === void 0 && Object.values(v).every((x) => typeof x === "string");
|
|
848
|
+
}
|
|
849
|
+
function vercelMediaImageUrl(p) {
|
|
850
|
+
let data = p.type === "file" ? p.data : p.image;
|
|
851
|
+
const mediaType = typeof p.mediaType === "string" ? p.mediaType : p.mimeType;
|
|
852
|
+
const out = { url: "" };
|
|
853
|
+
if (p.type === "file") out.part = "file";
|
|
854
|
+
if (typeof p.filename === "string") out.filename = p.filename;
|
|
855
|
+
if (data && typeof data === "object" && typeof data.type === "string") {
|
|
856
|
+
if (data.type === "data") {
|
|
857
|
+
out.data_tag = "data";
|
|
858
|
+
data = data.data;
|
|
859
|
+
} else if (data.type === "url") {
|
|
860
|
+
out.data_tag = "url";
|
|
861
|
+
data = data.url;
|
|
862
|
+
} else if (data.type === "text" && typeof data.text === "string") {
|
|
863
|
+
out.data_tag = "text";
|
|
864
|
+
out.url = `data:${mediaType ?? "text/plain"};base64,${bytesToBase64(new TextEncoder().encode(data.text))}`;
|
|
865
|
+
return out;
|
|
866
|
+
} else if (data.type === "reference" && data.reference && typeof data.reference === "object") {
|
|
867
|
+
out.data_tag = "reference";
|
|
868
|
+
out.reference = data.reference;
|
|
869
|
+
out.url = `data:${mediaType ?? ""};base64,`;
|
|
870
|
+
return out;
|
|
871
|
+
} else {
|
|
872
|
+
return null;
|
|
873
|
+
}
|
|
874
|
+
} else if (isProviderReference(data)) {
|
|
875
|
+
out.reference = data;
|
|
876
|
+
out.url = `data:${mediaType ?? ""};base64,`;
|
|
877
|
+
return out;
|
|
878
|
+
}
|
|
879
|
+
let carryType = false;
|
|
880
|
+
if (data instanceof Uint8Array || data instanceof ArrayBuffer) {
|
|
881
|
+
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
882
|
+
out.url = `data:${mediaType ?? ""};base64,${bytesToBase64(bytes)}`;
|
|
883
|
+
} else if (data instanceof URL) {
|
|
884
|
+
out.url = data.toString();
|
|
885
|
+
carryType = true;
|
|
886
|
+
} else if (typeof data === "string") {
|
|
887
|
+
if (data.startsWith("data:")) out.url = data;
|
|
888
|
+
else if (parseUrl(data)) {
|
|
889
|
+
out.url = data;
|
|
890
|
+
carryType = true;
|
|
891
|
+
} else out.url = `data:${mediaType ?? ""};base64,${data}`;
|
|
892
|
+
} else {
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
if (carryType && mediaType) out.mime_type = mediaType;
|
|
896
|
+
return out;
|
|
897
|
+
}
|
|
898
|
+
function vercelMediaPart(imageUrl) {
|
|
899
|
+
const url = imageUrl.url;
|
|
900
|
+
const tag = typeof imageUrl.data_tag === "string" ? imageUrl.data_tag : void 0;
|
|
901
|
+
const m = /^data:([^;,]*);base64,(.*)$/s.exec(url);
|
|
902
|
+
let mediaType = typeof imageUrl.mime_type === "string" ? imageUrl.mime_type : void 0;
|
|
903
|
+
if (m && m[1]) mediaType = m[1];
|
|
904
|
+
let data;
|
|
905
|
+
if (imageUrl.reference && typeof imageUrl.reference === "object") {
|
|
906
|
+
data = tag === "reference" ? { type: "reference", reference: imageUrl.reference } : imageUrl.reference;
|
|
907
|
+
} else if (m) {
|
|
908
|
+
data = m[2];
|
|
909
|
+
if (tag === "data") data = { type: "data", data: m[2] };
|
|
910
|
+
else if (tag === "text") data = { type: "text", text: base64ToText(m[2]) };
|
|
911
|
+
} else {
|
|
912
|
+
const parsed = parseUrl(url);
|
|
913
|
+
data = parsed ?? url;
|
|
914
|
+
if (tag === "url") data = { type: "url", url: parsed ?? url };
|
|
915
|
+
}
|
|
916
|
+
const isFile = imageUrl.part === "file" || mediaType !== void 0 && !mediaType.startsWith("image/");
|
|
917
|
+
if (isFile) {
|
|
918
|
+
const part2 = { type: "file", mediaType: mediaType ?? "application/octet-stream", data };
|
|
919
|
+
if (typeof imageUrl.filename === "string") part2.filename = imageUrl.filename;
|
|
920
|
+
return part2;
|
|
921
|
+
}
|
|
922
|
+
const part = { type: "image", image: data };
|
|
923
|
+
if (mediaType) part.mediaType = mediaType;
|
|
924
|
+
return part;
|
|
925
|
+
}
|
|
926
|
+
function groupAssistantParts(parts) {
|
|
927
|
+
const hasMedia = parts.some((p) => p.type === "image_url");
|
|
928
|
+
if (!hasMedia) {
|
|
929
|
+
const text = parts.filter((p) => p.type === "text").map((p) => p.text).join("\n");
|
|
930
|
+
return text ? [{ text }] : [];
|
|
931
|
+
}
|
|
932
|
+
const out = [];
|
|
933
|
+
for (const p of parts) {
|
|
934
|
+
if (p.type === "text") out.push({ text: p.text });
|
|
935
|
+
else if (p.type === "image_url") out.push({ image_url: p.image_url });
|
|
936
|
+
}
|
|
937
|
+
return out;
|
|
938
|
+
}
|
|
749
939
|
function vercelToOpenAI(messages) {
|
|
750
940
|
const result = [];
|
|
751
941
|
for (const msg of messages) {
|
|
@@ -760,18 +950,15 @@ function vercelToOpenAI(messages) {
|
|
|
760
950
|
}
|
|
761
951
|
const parts = Array.isArray(msg.content) ? msg.content : [];
|
|
762
952
|
const textParts = parts.filter((p) => p.type === "text");
|
|
763
|
-
const
|
|
764
|
-
if (
|
|
953
|
+
const mediaParts = parts.filter((p) => p.type === "image" || p.type === "file");
|
|
954
|
+
if (mediaParts.length === 0 && textParts.length > 0) {
|
|
765
955
|
result.push({ role: "user", content: textParts.map((p) => p.text).join("") });
|
|
766
956
|
} else {
|
|
767
|
-
const openaiParts = parts.filter((p) => p.type === "text" || p.type === "image").map((p) => {
|
|
957
|
+
const openaiParts = parts.filter((p) => p.type === "text" || p.type === "image" || p.type === "file").map((p) => {
|
|
768
958
|
if (p.type === "text") return { type: "text", text: p.text };
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
}
|
|
773
|
-
return { type: "text", text: "" };
|
|
774
|
-
});
|
|
959
|
+
const imageUrl = vercelMediaImageUrl(p);
|
|
960
|
+
return imageUrl ? { type: "image_url", image_url: imageUrl } : null;
|
|
961
|
+
}).filter((p) => p !== null);
|
|
775
962
|
result.push({ role: "user", content: openaiParts });
|
|
776
963
|
}
|
|
777
964
|
continue;
|
|
@@ -784,7 +971,17 @@ function vercelToOpenAI(messages) {
|
|
|
784
971
|
const parts = Array.isArray(msg.content) ? msg.content : [];
|
|
785
972
|
const textParts = parts.filter((p) => p.type === "text");
|
|
786
973
|
const toolCallParts = parts.filter((p) => p.type === "tool-call");
|
|
787
|
-
const
|
|
974
|
+
const hasFiles = parts.some((p) => p.type === "file");
|
|
975
|
+
let content;
|
|
976
|
+
if (hasFiles) {
|
|
977
|
+
content = parts.filter((p) => p.type === "text" || p.type === "file").map((p) => {
|
|
978
|
+
if (p.type === "text") return { type: "text", text: p.text };
|
|
979
|
+
const imageUrl = vercelMediaImageUrl(p);
|
|
980
|
+
return imageUrl ? { type: "image_url", image_url: imageUrl } : null;
|
|
981
|
+
}).filter((p) => p !== null);
|
|
982
|
+
} else {
|
|
983
|
+
content = textParts.length > 0 ? textParts.map((p) => p.text).join("") : null;
|
|
984
|
+
}
|
|
788
985
|
const openaiMsg = { role: "assistant", content };
|
|
789
986
|
if (toolCallParts.length > 0) {
|
|
790
987
|
openaiMsg.tool_calls = toolCallParts.map((p) => ({
|
|
@@ -836,7 +1033,7 @@ function openAIToVercel(messages) {
|
|
|
836
1033
|
} else if (Array.isArray(msg.content)) {
|
|
837
1034
|
const parts = msg.content.map((p) => {
|
|
838
1035
|
if (p.type === "text") return { type: "text", text: p.text };
|
|
839
|
-
if (p.type === "image_url") return
|
|
1036
|
+
if (p.type === "image_url") return vercelMediaPart(p.image_url);
|
|
840
1037
|
return { type: "text", text: "" };
|
|
841
1038
|
});
|
|
842
1039
|
result.push({ role: "user", content: parts });
|
|
@@ -845,7 +1042,14 @@ function openAIToVercel(messages) {
|
|
|
845
1042
|
}
|
|
846
1043
|
if (msg.role === "assistant") {
|
|
847
1044
|
const parts = [];
|
|
848
|
-
if (msg.content
|
|
1045
|
+
if (typeof msg.content === "string") {
|
|
1046
|
+
if (msg.content) parts.push({ type: "text", text: msg.content });
|
|
1047
|
+
} else if (Array.isArray(msg.content)) {
|
|
1048
|
+
for (const p of msg.content) {
|
|
1049
|
+
if (p.type === "text") parts.push({ type: "text", text: p.text });
|
|
1050
|
+
else if (p.type === "image_url") parts.push(vercelMediaPart(p.image_url));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
849
1053
|
if (msg.tool_calls) {
|
|
850
1054
|
for (const tc of msg.tool_calls) {
|
|
851
1055
|
toolNames.set(tc.id, tc.function.name);
|
|
@@ -950,7 +1154,17 @@ function geminiToOpenAI(messages) {
|
|
|
950
1154
|
if (role === "assistant") {
|
|
951
1155
|
const textParts = parts.filter((p) => p.text !== void 0);
|
|
952
1156
|
const funcCalls = parts.filter((p) => p.functionCall);
|
|
953
|
-
const
|
|
1157
|
+
const hasMedia = parts.some((p) => p.inlineData || p.fileData);
|
|
1158
|
+
let content;
|
|
1159
|
+
if (hasMedia) {
|
|
1160
|
+
content = parts.filter((p) => p.text !== void 0 || p.inlineData || p.fileData).map((p) => {
|
|
1161
|
+
if (p.text !== void 0) return { type: "text", text: p.text };
|
|
1162
|
+
const imageUrl = geminiMediaImageUrl(p);
|
|
1163
|
+
return imageUrl ? { type: "image_url", image_url: imageUrl } : null;
|
|
1164
|
+
}).filter((p) => p !== null);
|
|
1165
|
+
} else {
|
|
1166
|
+
content = textParts.length > 0 ? textParts.map((p) => p.text).join("\n") : null;
|
|
1167
|
+
}
|
|
954
1168
|
const openaiMsg = { role: "assistant", content };
|
|
955
1169
|
if (funcCalls.length > 0) {
|
|
956
1170
|
openaiMsg.tool_calls = funcCalls.map((p) => ({
|
|
@@ -991,7 +1205,14 @@ function openAIToGemini(messages) {
|
|
|
991
1205
|
}
|
|
992
1206
|
if (msg.role === "assistant") {
|
|
993
1207
|
const parts = [];
|
|
994
|
-
if (msg.content)
|
|
1208
|
+
if (typeof msg.content === "string") {
|
|
1209
|
+
if (msg.content) parts.push({ text: msg.content });
|
|
1210
|
+
} else if (Array.isArray(msg.content)) {
|
|
1211
|
+
for (const g of groupAssistantParts(msg.content)) {
|
|
1212
|
+
if ("text" in g) parts.push({ text: g.text });
|
|
1213
|
+
else parts.push(geminiMediaPart(g.image_url));
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
995
1216
|
if (msg.tool_calls) {
|
|
996
1217
|
for (const tc of msg.tool_calls) {
|
|
997
1218
|
parts.push({
|
|
@@ -1183,5 +1404,5 @@ exports.parseSSE = parseSSE;
|
|
|
1183
1404
|
exports.snakeToCamel = snakeToCamel;
|
|
1184
1405
|
exports.toOpenAI = toOpenAI;
|
|
1185
1406
|
exports.vercelToOpenAI = vercelToOpenAI;
|
|
1186
|
-
//# sourceMappingURL=chunk-
|
|
1187
|
-
//# sourceMappingURL=chunk-
|
|
1407
|
+
//# sourceMappingURL=chunk-CINZDAE4.cjs.map
|
|
1408
|
+
//# sourceMappingURL=chunk-CINZDAE4.cjs.map
|