Files
OmniRoute/tests/unit/compression/omniglyph-adapter.test.ts
Diego Rodrigues de Sa e Souza 04af8b1517 feat(compression): adota omniglyph 1.4.0, perfis semânticos e contabilidade com evidência (#10647)
* feat(compression): target-wire OmniGlyph stage and transport fidelity gate

Roda o OmniGlyph depois da tradução para o wire real do provedor, em vez do
corpo de origem. Um cliente OpenAI roteado para Claude deixava de comprimir com
skip:source_format_not_claude porque o corpo ainda estava em formato OpenAI
quando a engine era avaliada.

- dispatch nativo por wire: Anthropic Messages, OpenAI Chat Completions e
  OpenAI Responses (input[] preservado, sem achatar para messages[]);
- estágio target-wire pós-translateRequest, com guarda contra dupla compressão
  no caminho Claude→OpenAI;
- preserveSystemPrompt do OmniRoute mapeado para compressSystem: false;
- imageTransportPolicy: fidelidade de bytes/dimensões separada de supportsVision;
  só Anthropic/Claude tem recibo byte-preserving, o resto é fail-closed;
- contagem de tokens de data URL PNG no wire OpenAI (marcador ;base64,);
- README e i18n en/pt-BR com claims escopados ao caminho medido.

* feat(compression): adota omniglyph 1.4.0 e tira o gate de modelo da env do host

O 1.4.0 introduziu escopos de segurança e passou a resolvê-los dentro de
isOmniGlyphSupportedModel() lendo process.env.OMNIGLYPH_PROFILE. Somado ao
OMNIGLYPH_MODELS que já existia, duas variáveis do ambiente do host decidiam em
silêncio o gate de TODO request do OmniRoute: passthrough desligaria a engine
inteira e OMNIGLYPH_MODELS admitiria modelos sem recibo medido, enquanto a UI
segue prometendo "Claude Fable 5 na rota direta medida".

O adapter passa a usar isOmniGlyphSupportedModelForScope() com escopo explícito
e fixa o escopo mais restrito como teto: a env só pode ESTREITAR a allowlist,
nunca alargar. Os dois wires compartilham a mesma lista no pacote desde o
1.4.0, então uma checagem cobre Anthropic e GPT.

- omniglyph ^1.3.1 -> ^1.4.0 (lock em 1.4.0);
- testes de regressão para os dois caminhos de sequestro por env;
- teste de contrato dos exports novos (escopo, perfis, accounting).

O 1.4.0 também traz, sem mudança de código aqui: correção do glyph K que era
lido como H, remoção do backtracking polinomial no secret-guard, overrides do
pnpm em pnpm-workspace.yaml e as transitivas vulneráveis resolvidas.

* feat(compression): expõe os perfis semânticos do omniglyph nos três wires

O 1.4.0 trouxe perfis nomeados (coding-safe, balanced, aggressive,
passthrough), mas só transformAnthropicMessages() os resolve sozinho: os
transformadores OpenAI recebem TransformOptions cru e ignorariam o campo. Um
perfil escolhido pelo operador valeria no wire Claude e sumiria no OpenAI. O
adapter passa a mesclar o perfil com mergeCompressionProfileOptions() antes de
chamar Chat Completions e Responses.

O default segue aggressive — a política que os recibos publicados mediram.
Medido nesta base: com coding-safe/balanced, uma sessão sem histórico acumulado
para em below_min_chars e a engine não faz nada, porque os dois fixam
minCompressChars no máximo e desligam system/tools/tool-results. Como a engine é
opt-in, um default assim entregaria "ligado, 0% de ganho".

O perfil é TETO, não piso: mergeCompressionProfileOptions não deixa um override
do chamador reabrir uma lane lossy que o perfil fechou. Coberto por teste, por
ser contra-intuitivo.

Também fecha um caminho em que o OmniRoute violaria a própria política: o wire
OpenAI do pacote não tem compressSystem — honra apenas compressTools,
gptHistory, minCompressChars e reflow, e sempre troca a instrução por um
ponteiro para a imagem. Com preserveSystemPrompt ligado, imagear assim queimaria
o prefixo quente que a decisão cache-aware está protegendo, sem nada no corpo
devolvido denunciando. A engine agora pula com
skip:system_preservation_unsupported_on_wire.

* feat(compression): contabilidade física do omniglyph com grau de evidência

O adapter descartava o TransformInfo inteiro, então a UI mostrava um número de
economia sem dizer de onde ele vinha — contagem do provider, estimativa ou só
diferença de bytes. O 1.4.0 expõe normalizeAccounting(), que classifica essa
evidência e resolve a semântica de cache por família: Anthropic reporta input,
cache-create e cache-read em buckets DISJUNTOS, enquanto OpenAI e xAI reportam
cached como SUBCONJUNTO do input. Somar à mão dá double-count silencioso.

O novo omniglyphTelemetry.ts não filtra por denylist — MONTA um objeto novo,
campo a campo, só com número e enum. TransformInfo mistura contadores
inofensivos com material que não pode ser persistido: bytes PNG,
imageSourceText(s), recoverable[].text, os sha8 de system/CLAUDE.md/primeira
mensagem, nomes de tags observadas e o bloco env (cwd, branch, versões). Copiar
o objeto inteiro transformaria telemetria de compressão em vazamento de prompt.
O teste de negação prova que segredo, caminho do operador, texto do system e
base64 não aparecem, e varre a allowlist exigindo que toda string seja de um
enum conhecido.

- provider threaded do chatCore e do bridge Codex WS até a engine; ausente vira
  `unknown`, que faz o upstream recusar adivinhar buckets de cache;
- contabilidade propagada para o engineBreakdown do passo (o agregado do
  pipeline soma todas as engines e não serviria);
- skip não emite contabilidade: zeros ali seriam indistinguíveis de "a engine
  nem rodou".

* feat(compression): perfil do omniglyph configurável, persistido e documentado

Fecha o caminho do operador: o perfil já existia no adapter, mas só como
default de código. Agora atravessa schema Zod, normalizador do banco, API de
settings e a página dedicada do engine.

- OmniglyphConfig tipado + omniglyphConfigSchema (z.enum dos quatro perfis);
- normalizeOmniglyphConfig: nome desconhecido vindo do storage cai para o
  default em vez de virar "roda com a política padrão";
- seletor na página do engine, com PATCH próprio — o perfil vive fora do mapa
  `engines`, e mandá-lo junto reescreveria o mapa inteiro (o store persiste o
  mapa como uma linha JSON só);
- i18n en/pt-BR descrevendo o custo medido de cada perfil, não só o nome;
- README e COMPRESSION_ENGINES.md com a regra do teto e o motivo de o default
  não ser o perfil mais seguro.

Corrige de passagem um teste-irmão que ninguém via: o gate de transporte na UI
deixou de dizer "direct Anthropic" quando os wires OpenAI nativos entraram, mas
tests/unit/ui/omniglyphContextPage.test.tsx continuou afirmando a cópia antiga.
O arquivo inteiro estava excluído do vitest.config.ts como "#8618 pre-existing
failure", então a quebra passou silenciosa. Com a asserção alinhada o arquivo
fecha 3/3, e a exclusão sai — o próprio comentário mandava removê-la quando
corrigida.

A doc não nomeia OMNIGLYPH_MODELS: o gate de docs fabricadas está certo em
apontar que o OmniRoute nunca lê essa env — quem lê é o pacote.

* fix(i18n): paridade do locale vi com as chaves novas do perfil do omniglyph

`tests/unit/i18n-vi-completeness.test.ts` exige paridade ESTRITA de chaves entre
en e vi — diferente do ratchet `i18n:check-ui-coverage`, que passa com 80%. As 11
chaves do seletor de perfil entraram só em en e pt-BR, e o gate de cobertura
seguiu verde, então a quebra só apareceu na matriz completa do CI.

---------

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
2026-08-18 12:13:48 -03:00

326 lines
12 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert";
import { omniglyphEngine } from "../../../open-sse/services/compression/engines/omniglyphAdapter.ts";
// Corpo Claude denso o bastante para o gate de rentabilidade do omniglyph converter.
const DENSE =
"X".repeat(500) +
"\n" +
Array.from(
{ length: 400 },
(_, i) => `const row_${i} = compute(${i * 17}, "${"v".repeat(80)}");`
).join("\n");
function claudeBody(): Record<string, unknown> {
return {
model: "claude-fable-5",
max_tokens: 128,
system: DENSE,
messages: [{ role: "user", content: [{ type: "text", text: "oi" }] }],
};
}
const OK = {
model: "claude-fable-5",
supportsVision: true,
providerTransport: "direct" as const,
imageTransportFidelity: "byte-preserving" as const,
};
const GPT_OK = {
model: "gpt-5.6",
supportsVision: true,
providerTransport: "direct" as const,
imageTransportFidelity: "byte-preserving" as const,
sourceFormat: "openai" as const,
targetFormat: "openai" as const,
compressionStage: "post-translation" as const,
};
function openaiChatBody(): Record<string, unknown> {
return {
model: "gpt-5.6",
messages: [
{ role: "system", content: DENSE },
{ role: "user", content: "oi" },
],
tools: [
{
type: "function",
function: {
name: "inspect_repository",
description: DENSE,
parameters: { type: "object", properties: { path: { type: "string" } } },
},
},
],
};
}
function openaiResponsesBody(): Record<string, unknown> {
return {
model: "gpt-5.6",
instructions: DENSE,
input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "oi" }] }],
tools: [
{
type: "function",
name: "inspect_repository",
description: DENSE,
parameters: { type: "object", properties: { path: { type: "string" } } },
},
],
};
}
test("happy path: comprime corpo claude denso em blocos de imagem", async () => {
const r = await omniglyphEngine.applyAsync!(claudeBody(), OK);
assert.equal(r.compressed, true);
assert.ok(JSON.stringify(r.body).includes('"type":"image"'));
});
test("skip fail-closed: sem supportsVision / transporte agregador / undefined", async () => {
for (const opts of [
{ ...OK, supportsVision: false },
{ ...OK, providerTransport: "aggregator" as const },
{ model: "claude-fable-5", supportsVision: true }, // transport undefined
]) {
const r = await omniglyphEngine.applyAsync!(claudeBody(), opts);
assert.equal(r.compressed, false);
assert.ok(!JSON.stringify(r.body).includes('"type":"image"'));
}
});
test("skip fail-closed: rota direta sem recibo de fidelidade de imagem", async () => {
const r = await omniglyphEngine.applyAsync!(claudeBody(), {
...OK,
imageTransportFidelity: "unknown",
});
assert.equal(r.compressed, false);
assert.ok(r.stats?.techniquesUsed.includes("skip:transport_fidelity_unknown"));
});
test("skip: modelo fora da allowlist medida", async () => {
const body = { ...claudeBody(), model: "gpt-5.5" };
const r = await omniglyphEngine.applyAsync!(body, { ...OK, model: "gpt-5.5" });
assert.equal(r.compressed, false);
});
test("skip: corpo em formato OpenAI (role system nas messages)", async () => {
const body = {
model: "claude-fable-5",
messages: [
{ role: "system", content: DENSE },
{ role: "user", content: "oi" },
],
};
const r = await omniglyphEngine.applyAsync!(body, OK);
assert.equal(r.compressed, false);
});
test("cache_control do cliente sobrevive byte a byte", async () => {
const body = claudeBody();
(body.messages as Array<Record<string, unknown>>).push({
role: "user",
content: [{ type: "text", text: "âncora", cache_control: { type: "ephemeral" } }],
});
const r = await omniglyphEngine.applyAsync!(body, OK);
assert.ok(JSON.stringify(r.body).includes('"cache_control"'));
});
test("preserveSystemPrompt mantém o sistema nativo e ainda pode comprimir tool_result", async () => {
const body = {
...claudeBody(),
messages: [
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: "call_1",
content: DENSE,
},
],
},
],
};
const r = await omniglyphEngine.applyAsync!(body, {
...OK,
config: { preserveSystemPrompt: true } as never,
});
assert.equal(r.compressed, true);
assert.equal((r.body as { system?: unknown }).system, DENSE);
assert.ok(JSON.stringify(r.body).includes('"type":"image"'));
});
test("apply síncrono é pass-through seguro (engine async-only)", () => {
const body = claudeBody();
const r = omniglyphEngine.apply(body, OK);
assert.equal(r.compressed, false);
assert.deepEqual(r.body, body);
});
test("fail-open: erro no transform vira skip, nunca propaga", async () => {
const body = claudeBody() as Record<string, unknown>;
(body as { self?: unknown }).self = body; // referência circular → JSON.stringify lança
const r = await omniglyphEngine.applyAsync!(body, OK);
assert.equal(r.compressed, false);
assert.deepEqual(r.body, body); // corpo original devolvido intacto
});
test("versão atual: transforma Chat Completions OpenAI no wire pós-tradução", async () => {
const r = await omniglyphEngine.applyAsync!(openaiChatBody(), GPT_OK);
assert.equal(r.compressed, true);
assert.ok(JSON.stringify(r.body).includes('"type":"image_url"'));
});
test("versão atual: transforma OpenAI Responses preservando input[]", async () => {
const options = { ...GPT_OK, targetFormat: "openai-responses" as const };
const r = await omniglyphEngine.applyAsync!(openaiResponsesBody(), options);
assert.equal(r.compressed, true);
assert.ok(JSON.stringify(r.body).includes('"type":"input_image"'));
assert.ok(Array.isArray((r.body as { input?: unknown }).input));
});
test("OpenAI não roda no estágio pré-tradução", async () => {
const r = await omniglyphEngine.applyAsync!(openaiChatBody(), {
...GPT_OK,
compressionStage: "pre-translation",
});
assert.equal(r.compressed, false);
assert.ok(r.stats?.techniquesUsed.includes("skip:requires_post_translation"));
});
// OmniGlyph 1.4.0 introduziu escopos de segurança (`coding-safe`/`balanced`/
// `aggressive`/`passthrough`) e passou a resolvê-los, dentro de
// `isOmniGlyphSupportedModel()`, lendo `process.env.OMNIGLYPH_PROFILE`. Isso
// transforma uma variável de ambiente do HOST num gate silencioso de TODO
// request do OmniRoute: um `OMNIGLYPH_PROFILE=passthrough` exportado no shell
// do processo desligaria a engine sem que nenhuma configuração do OmniRoute
// tivesse mudado — e sem nenhum sinal na UI. A política é do OmniRoute; o
// adapter tem de passar o escopo explicitamente.
async function withEnv<T>(key: string, value: string, fn: () => Promise<T>): Promise<T> {
const had = Object.prototype.hasOwnProperty.call(process.env, key);
const previous = process.env[key];
process.env[key] = value;
try {
return await fn();
} finally {
if (had) process.env[key] = previous;
else delete process.env[key];
}
}
test("OMNIGLYPH_PROFILE do host não decide o gate de modelo do OmniRoute", async () => {
const r = await withEnv("OMNIGLYPH_PROFILE", "passthrough", () =>
omniglyphEngine.applyAsync!(claudeBody(), OK)
);
assert.equal(
r.compressed,
true,
"env do processo não pode desligar a engine: o escopo vem da config do OmniRoute"
);
});
test("OMNIGLYPH_PROFILE do host não amplia a allowlist de modelos do OmniRoute", async () => {
const body = { ...claudeBody(), model: "claude-sonnet-5" };
const r = await withEnv("OMNIGLYPH_PROFILE", "aggressive", () =>
withEnv("OMNIGLYPH_MODELS", "claude-fable-5,claude-sonnet-5", () =>
omniglyphEngine.applyAsync!(body, { ...OK, model: "claude-sonnet-5" })
)
);
assert.equal(r.compressed, false, "modelo sem recibo medido não pode entrar via env do host");
assert.ok(r.stats?.techniquesUsed.includes("skip:model_not_approved"));
});
// ---------------------------------------------------------------------------
// Perfis semânticos (OmniGlyph 1.4.0)
//
// `transformAnthropicMessages()` resolve e mescla o perfil sozinho, mas os
// transformadores OpenAI recebem `TransformOptions` cru e NÃO conhecem
// `profile`. Sem o merge explícito do host, um perfil escolhido pelo operador
// valeria no wire Claude e seria silenciosamente ignorado no wire OpenAI.
// ---------------------------------------------------------------------------
/** Histórico longo o bastante para o colapso valer mesmo com o system nativo. */
function claudeBodyWithHistory(): Record<string, unknown> {
const messages: Array<Record<string, unknown>> = [];
for (let i = 0; i < 40; i++) {
messages.push({ role: "user", content: [{ type: "text", text: `pergunta ${i}: ${DENSE}` }] });
messages.push({
role: "assistant",
content: [{ type: "text", text: `resposta ${i}: ${DENSE}` }],
});
}
messages.push({ role: "user", content: [{ type: "text", text: "oi" }] });
return { model: "claude-fable-5", max_tokens: 128, system: DENSE, messages };
}
test("perfil coding-safe chega ao wire OpenAI (não só ao wrapper Anthropic)", async () => {
const aggressive = await omniglyphEngine.applyAsync!(openaiChatBody(), {
...GPT_OK,
stepConfig: { profile: "aggressive" } as never,
});
assert.equal(aggressive.compressed, true, "aggressive é a política medida atual");
const codingSafe = await omniglyphEngine.applyAsync!(openaiChatBody(), {
...GPT_OK,
stepConfig: { profile: "coding-safe" } as never,
});
assert.equal(
codingSafe.compressed,
false,
"coding-safe mantém system e schemas de tools nativos no wire OpenAI"
);
assert.ok(
codingSafe.stats?.techniquesUsed.some((t) => t.startsWith("skip:below_min_chars")),
`esperado skip por minCompressChars, veio ${JSON.stringify(codingSafe.stats?.techniquesUsed)}`
);
});
test("perfil é TETO, não piso: coding-safe mantém o system nativo mesmo sem preserveSystemPrompt", async () => {
const body = claudeBodyWithHistory();
const r = await omniglyphEngine.applyAsync!(body, {
...OK,
stepConfig: { profile: "coding-safe", preserveSystemPrompt: false } as never,
});
assert.equal(r.compressed, true, "o histórico antigo ainda colapsa");
assert.equal(
(r.body as { system?: unknown }).system,
DENSE,
"coding-safe não deixa um override do chamador reabrir a compressão do system"
);
});
test("perfil passthrough desliga a engine sem tocar no corpo", async () => {
const body = claudeBodyWithHistory();
const r = await omniglyphEngine.applyAsync!(body, {
...OK,
stepConfig: { profile: "passthrough" } as never,
});
assert.equal(r.compressed, false);
assert.ok(r.stats?.techniquesUsed.includes("skip:profile_passthrough"));
assert.deepEqual(r.body, body);
});
test("perfil inválido falha fechado, não propaga exceção", async () => {
const r = await omniglyphEngine.applyAsync!(claudeBody(), {
...OK,
stepConfig: { profile: "turbo-max" } as never,
});
assert.equal(r.compressed, false);
assert.ok(r.stats?.techniquesUsed.includes("skip:invalid_profile"));
});
test("preserveSystemPrompt: wire OpenAI pula, porque o pacote não sabe preservar system lá", async () => {
// O transform OpenAI do OmniGlyph 1.4.0 honra apenas compressTools, gptHistory,
// minCompressChars e reflow — não existe compressSystem nesse wire, e a
// instrução vira sempre um ponteiro para a imagem. Imagear assim queimaria o
// prefixo quente que a decisão cache-aware do OmniRoute mandou preservar, e o
// OmniRoute não teria como saber. Sem opção de honrar a política, pula.
const r = await omniglyphEngine.applyAsync!(openaiChatBody(), {
...GPT_OK,
config: { preserveSystemPrompt: true } as never,
});
assert.equal(r.compressed, false);
assert.ok(r.stats?.techniquesUsed.includes("skip:system_preservation_unsupported_on_wire"));
assert.deepEqual(r.body, openaiChatBody());
});