mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
121 lines
4.3 KiB
TypeScript
121 lines
4.3 KiB
TypeScript
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { estimateTokens, getTokenLimit } from "../../open-sse/services/contextManager.ts";
|
|
|
|
function makeFakePngBase64(approxBytes: number): string {
|
|
return Buffer.alloc(approxBytes, 65).toString("base64");
|
|
}
|
|
|
|
test("#8368: inline base64 PNG image_url is NOT counted as raw text (bounded image-token estimate)", () => {
|
|
const base64 = makeFakePngBase64(1_900_000); // ~1.9MB, matches issue repro
|
|
const messages = [
|
|
{ role: "user", content: "Please describe this image." },
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{ type: "input_text", text: "Please describe this image." },
|
|
{ type: "input_image", image_url: `data:image/png;base64,${base64}` },
|
|
],
|
|
},
|
|
];
|
|
const estimated = estimateTokens(messages);
|
|
assert.ok(
|
|
estimated < 5000,
|
|
`BUG #8368 reproduced: image-bearing message estimated at ${estimated} tokens (limit ${getTokenLimit(
|
|
"codex"
|
|
)})`
|
|
);
|
|
});
|
|
|
|
test("#8368: plain text estimation is unaffected by the image-token fix (control)", () => {
|
|
const text = "a".repeat(4000); // 4000 chars => ~1000 tokens at CHARS_PER_TOKEN=4
|
|
const estimated = estimateTokens(text);
|
|
assert.equal(estimated, 1000);
|
|
});
|
|
|
|
test("#8368: OpenAI chat.completions image_url object shape is bounded", () => {
|
|
const base64 = makeFakePngBase64(500_000);
|
|
const messages = [
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{ type: "text", text: "What is in this image?" },
|
|
{ type: "image_url", image_url: { url: `data:image/jpeg;base64,${base64}` } },
|
|
],
|
|
},
|
|
];
|
|
const estimated = estimateTokens(messages);
|
|
assert.ok(estimated < 5000, `expected bounded estimate, got ${estimated}`);
|
|
});
|
|
|
|
test("#8368: Claude source.base64 image block shape is bounded", () => {
|
|
const base64 = makeFakePngBase64(500_000);
|
|
const messages = [
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{ type: "text", text: "Describe this." },
|
|
{
|
|
type: "image",
|
|
source: { type: "base64", media_type: "image/png", data: base64 },
|
|
},
|
|
],
|
|
},
|
|
];
|
|
const estimated = estimateTokens(messages);
|
|
assert.ok(estimated < 5000, `expected bounded estimate, got ${estimated}`);
|
|
});
|
|
|
|
test("#8368: Gemini inlineData image block shape is bounded", () => {
|
|
const base64 = makeFakePngBase64(500_000);
|
|
const messages = [
|
|
{
|
|
role: "user",
|
|
parts: [{ text: "Describe this." }, { inlineData: { mimeType: "image/png", data: base64 } }],
|
|
},
|
|
];
|
|
const estimated = estimateTokens(messages);
|
|
assert.ok(estimated < 5000, `expected bounded estimate, got ${estimated}`);
|
|
});
|
|
|
|
test("#8368: multiple images accumulate a bounded sum, not one flat cap", () => {
|
|
const base64 = makeFakePngBase64(200_000);
|
|
const oneImageMessages = [
|
|
{ role: "user", content: [{ type: "image_url", image_url: { url: `data:image/png;base64,${base64}` } }] },
|
|
];
|
|
const threeImageMessages = [
|
|
{
|
|
role: "user",
|
|
content: [
|
|
{ type: "image_url", image_url: { url: `data:image/png;base64,${base64}` } },
|
|
{ type: "image_url", image_url: { url: `data:image/png;base64,${base64}` } },
|
|
{ type: "image_url", image_url: { url: `data:image/png;base64,${base64}` } },
|
|
],
|
|
},
|
|
];
|
|
const one = estimateTokens(oneImageMessages);
|
|
const three = estimateTokens(threeImageMessages);
|
|
assert.ok(three > one, `expected 3 images to cost more than 1 (one=${one}, three=${three})`);
|
|
assert.ok(three < one * 4, `expected roughly linear scaling, got one=${one} three=${three}`);
|
|
});
|
|
|
|
test("#8368: remote http(s) image URLs are unaffected (still measured as text)", () => {
|
|
const messages = [
|
|
{
|
|
role: "user",
|
|
content: [{ type: "image_url", image_url: { url: "https://example.com/cat.png" } }],
|
|
},
|
|
];
|
|
const estimated = estimateTokens(messages);
|
|
// Should just be the JSON-length/4 heuristic for the short URL string, not near-zero
|
|
// and not a bounded image-token substitute — remote URLs stay on the text path.
|
|
assert.ok(estimated > 0 && estimated < 100, `expected small text-based estimate, got ${estimated}`);
|
|
});
|
|
|
|
test("#8368: generic long base64 text (not an image field) still uses the text path", () => {
|
|
const genericBase64 = makeFakePngBase64(100_000);
|
|
const estimated = estimateTokens(genericBase64);
|
|
const expectedTextEstimate = Math.ceil(genericBase64.length / 4);
|
|
assert.equal(estimated, expectedTextEstimate);
|
|
});
|