Files
OmniRoute/tests/unit/8594-compress-image-token-stringify.test.ts
Diego Rodrigues de Sa e Souza f9899c57ca Train 1D: merge via --admin on .113 validation
Squash merge from local merge-train (Hard Rule owner-approved). Tip 029cdf4215cf465f0e1716ac9f84a84692b1e881 validated on 192.168.0.113: 26631/26653 pass.
2026-07-27 11:30:44 -03:00

95 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import test from "node:test";
import assert from "node:assert/strict";
import { compressContext } from "../../open-sse/services/contextManager.ts";
// #8594 — six production call sites (compressContext layers + purifyHistory binary
// search + the combo.ts fallback threshold) pre-JSON.stringify the messages before
// handing them to estimateTokens(). Stringifying forces the char/4 text path and
// undoes the #8368 inline-base64-image bounded estimate, so an image-bearing request
// that fits comfortably is mis-measured as ~100× larger and compressed needlessly.
function makeFakePngBase64(approxBytes: number): string {
return Buffer.alloc(approxBytes, 65).toString("base64");
}
test("#8594: compressContext does NOT compress a within-limit inline-image request", () => {
// ~500KB image => ~666KB base64. As raw text that is ~166k tokens (over the limit);
// as a bounded image estimate it is ~1.2k tokens (well under). maxTokens=20000 sits
// between the two, so the bug (stringify) trips compression and the fix does not.
const base64 = makeFakePngBase64(500_000);
const body = {
model: "gpt-image-vision",
messages: [
{ role: "system", content: "You are a helpful vision assistant." },
{
role: "user",
content: [
{ type: "text", text: "What is in this image?" },
{ type: "image_url", image_url: { url: `data:image/png;base64,${base64}` } },
],
},
],
};
const result = compressContext(body, { maxTokens: 20000, reserveTokens: 0 });
assert.equal(
result.compressed,
false,
`BUG #8594 reproduced: within-limit image request was compressed. ` +
`stats.original=${(result.stats as { original?: number }).original} tokens ` +
`(should be a bounded ~1.2k image estimate, not the ~166k base64-as-text value)`
);
assert.ok(
(result.stats as { original: number }).original < 5000,
`expected bounded image-token estimate (<5000), got ${(result.stats as { original: number }).original}`
);
});
test("#8594: purifyHistory keeps all image-bearing turns when they fit within the limit", () => {
// Multiple image messages that, measured correctly, fit under the limit. The bug
// makes the Layer-3 binary search over-estimate and prune turns; the fix preserves them.
const base64 = makeFakePngBase64(200_000);
const imageTurn = (n: number) => ({
role: "user",
content: [
{ type: "text", text: `Image number ${n}` },
{ type: "image_url", image_url: { url: `data:image/png;base64,${base64}` } },
],
});
const body = {
model: "gpt-image-vision",
messages: [
{ role: "system", content: "vision" },
imageTurn(1),
{ role: "assistant", content: "ok 1" },
imageTurn(2),
{ role: "assistant", content: "ok 2" },
imageTurn(3),
{ role: "assistant", content: "ok 3" },
],
};
const originalCount = body.messages.length;
const result = compressContext(body, { maxTokens: 20000, reserveTokens: 0 });
assert.equal(result.compressed, false, "within-limit image history must not be compressed");
assert.equal(
(result.body as { messages: unknown[] }).messages.length,
originalCount,
"all image-bearing turns must be retained when they fit"
);
});
test("#8594: control — an oversized text request is still compressed (no regression)", () => {
const body = {
model: "gpt-text",
messages: [
{ role: "system", content: "s" },
{ role: "user", content: "a".repeat(200_000) }, // ~50k tokens, over a 20k limit
],
};
const result = compressContext(body, { maxTokens: 20000, reserveTokens: 0 });
assert.equal(result.compressed, true, "oversized text must still trigger compression");
});