Compare commits

..

6 Commits

Author SHA1 Message Date
Xiangzhe
19e7bd6d63 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.
2026-08-18 05:56:36 -03:00
Xiangzhe
098c72d1e3 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.
2026-08-18 00:42:26 -03:00
Xiangzhe
638fe783a0 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".
2026-08-18 00:23:47 -03:00
Xiangzhe
b5e5838a59 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.
2026-08-18 00:13:09 -03:00
Xiangzhe
ce89143232 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.
2026-08-18 00:04:26 -03:00
Xiangzhe
6b05eedc8d 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.
2026-08-17 23:56:01 -03:00
37 changed files with 1320 additions and 1110 deletions

View File

@@ -853,7 +853,7 @@ Engines run in pipeline order; each is independently toggleable and configurable
<tr><td align="center" nowrap>9</td><td align="left" nowrap><b>Aggressive</b></td><td align="left">Summarization + progressive aging of old turns</td></tr>
<tr><td align="center" nowrap>10</td><td align="left" nowrap><b>LLMLingua-2</b></td><td align="left">ML semantic pruning via MobileBERT ONNX — code-safe, async</td></tr>
<tr><td align="center" nowrap>11</td><td align="left" nowrap><b>Ultra</b></td><td align="left">Heuristic token pruning with an optional small-model (SLM) tier</td></tr>
<tr><td align="center" nowrap>12</td><td align="left" nowrap><b>OmniGlyph</b></td><td align="left">Experimental context-as-image encoding routed to Claude Fable 5 (most aggressive; opt-in)</td></tr>
<tr><td align="center" nowrap>12</td><td align="left" nowrap><b>OmniGlyph</b></td><td align="left">Experimental context-as-image encoding for measured Claude Fable 5 on the direct Anthropic wire; GPT 5.6 transformers remain fail-closed pending provider receipts. Four compression profiles (aggressive default, balanced, coding-safe, passthrough) (most aggressive; opt-in)</td></tr>
</table>
Code blocks, URLs and structured data are **always preserved** byte-perfect. **One-click presets** combine the engines:

View File

@@ -19,8 +19,36 @@ OmniRoute compression is built around engine contracts. A mode can run one engin
| `aggressive` | Caveman + history/tool summarizers | Long chat sessions |
| `ultra` | Caveman + pruning helpers | Context-limit recovery |
| `rtk` | RTK | Terminal, shell, build, test, and git output |
| `omniglyph` | OmniGlyph | Context-as-image on the native provider wire |
| `stacked` | Pipeline, default `rtk -> caveman` | Mixed tool logs and prose, max savings |
### OmniGlyph compression profiles
The `omniglyph` engine (package `omniglyph`, 1.4.0+) accepts a named semantic profile, set
globally through `omniglyph.profile` in the compression settings or per step through the
stacked pipeline's step config:
| Profile | Boundary |
| -------------- | --------------------------------------------------------------------------- |
| `aggressive` | Default. The policy the published receipts measured — images system, tool docs and dense history |
| `balanced` | Keeps live state native, protects the last 8 turns, collapses older closed history |
| `coding-safe` | Keeps authority, tool schemas and live tool output native, protects the last 12 turns |
| `passthrough` | Routes without transforming; the engine is skipped |
The profile is a **ceiling, not a floor**: `mergeCompressionProfileOptions` in the package
refuses to let a caller override reopen a lossy lane the profile closed, so a per-step
`preserveSystemPrompt: false` cannot re-enable system compression under `coding-safe`.
Measured on this codebase: `coding-safe` and `balanced` raise `minCompressChars` to its
maximum and keep system, tool schemas and tool results native, so a session that has not
accumulated history yet stops at `below_min_chars` and the engine transforms nothing. That
is why the default is `aggressive` rather than the safest profile.
The package resolves its own model scope and profile from its environment configuration.
OmniRoute never delegates the decision: the adapter pins the model gate to the package's
most restrictive scope, so host environment settings can only narrow the allowlist, never
widen it past OmniRoute's measured receipts.
## Engine Registry
The registry lives in `open-sse/services/compression/engines/registry.ts`. Engines expose a shared

View File

@@ -368,7 +368,7 @@ const result = await executor.execute({
});
````
Resolution goes through the `ExecutorRegistry` (`executors/registry.ts`): every specialized executor is declared in the built-in table of `executors/index.ts` and registered via `registerExecutor(alias, instance)` at module load; `getExecutor()` consults the registry and falls back to a memoized `DefaultExecutor` for any provider without a specialized entry. The full alias → executor mapping is characterized by the golden test `tests/unit/executor-map-golden.test.ts`.
The factory is generated from `config/providerRegistry.ts` which lists all 338 providers and their executor class.
---

View File

@@ -1,9 +1,4 @@
import { SEARCH_PROVIDERS } from "../config/searchRegistry.ts";
import {
registerExecutor,
getRegisteredExecutor,
hasRegisteredExecutor,
} from "./registry.ts";
import { AntigravityExecutor } from "./antigravity.ts";
import { GithubExecutor } from "./github.ts";
import { GheCopilotExecutor } from "./ghe-copilot.ts";
@@ -83,12 +78,6 @@ import { XaiExecutor } from "./xai.ts";
import { PromptQlExecutor } from "./promptql.ts";
import { ConolWebExecutor } from "./conol-web.ts";
// R0.3 — declarative built-in table. The object literal stays as the single
// place built-ins are declared (compile-time duplicate-key safety; the
// check:known-symbols gate parses this literal from source), but lookup goes
// through the ExecutorRegistry (./registry.ts): every entry is registered at
// module load below, and getExecutor()/hasSpecializedExecutor() consult the
// registry — the literal is never read at request time.
const executors = {
antigravity: new AntigravityExecutor(),
agy: new AntigravityExecutor(),
@@ -232,13 +221,6 @@ const executors = {
cnl: new ConolWebExecutor(), // Alias
};
// Bootstrap: register every built-in in the ExecutorRegistry. registerExecutor
// throws on duplicates, so an alias collision fails at module load, exactly as
// loudly as a duplicate object key would have failed at lint time.
for (const [alias, executor] of Object.entries(executors)) {
registerExecutor(alias, executor);
}
const defaultCache = new Map();
// #6699 — providers that exist ONLY as Cloud Agent task-API entries
@@ -264,8 +246,7 @@ const CHAT_UNSUPPORTED_CLOUD_AGENT_PROVIDERS = new Set(["jules"]);
const CHAT_UNSUPPORTED_SEARCH_PROVIDERS = new Set(Object.keys(SEARCH_PROVIDERS));
export function getExecutor(provider) {
const registered = getRegisteredExecutor(provider);
if (registered) return registered;
if (executors[provider]) return executors[provider];
if (CHAT_UNSUPPORTED_CLOUD_AGENT_PROVIDERS.has(provider)) {
const err = new Error(
`Provider "${provider}" is a cloud-agent provider and does not support direct chat completions; use the Cloud Agents task API instead.`
@@ -285,11 +266,9 @@ export function getExecutor(provider) {
}
export function hasSpecializedExecutor(provider) {
return hasRegisteredExecutor(provider);
return !!executors[provider];
}
export { registerExecutor, listExecutorAliases } from "./registry.ts";
export { BaseExecutor } from "./base.ts";
export { AntigravityExecutor } from "./antigravity.ts";
export { GithubExecutor } from "./github.ts";

View File

@@ -1,38 +0,0 @@
import type { BaseExecutor } from "./base.ts";
// R0.3 — ExecutorRegistry: runtime registry for provider executors, mirroring
// open-sse/translator/registry.ts. Built-ins register at module load from
// executors/index.ts; getExecutor() resolves through this map instead of a
// hard-coded object literal. This is the seam the v4 plan (M1.6
// host.registerProvider) extends — today the surface is internal-only.
//
// The alias → executor mapping is characterized by
// tests/unit/executor-map-golden.test.ts (tests/snapshots/executors/): any
// change to keys, classes or instance sharing shows up as a golden diff.
const registry = new Map<string, BaseExecutor>();
/**
* Register an executor under an alias. Aliases are unique: registering the
* same alias twice throws, preserving the guarantee the old object literal
* gave at compile time (duplicate keys were impossible).
*/
export function registerExecutor(alias: string, executor: BaseExecutor): void {
if (registry.has(alias)) {
throw new Error(`executor alias already registered: "${alias}"`);
}
registry.set(alias, executor);
}
export function getRegisteredExecutor(alias: string): BaseExecutor | undefined {
return registry.get(alias);
}
export function hasRegisteredExecutor(alias: string): boolean {
return registry.has(alias);
}
/** All registered aliases, in registration order. */
export function listExecutorAliases(): string[] {
return [...registry.keys()];
}

View File

@@ -88,6 +88,7 @@ import { checkResourcePressureGuard } from "../utils/resourcePressure.ts";
import { normalizeHeaders } from "../utils/headers.ts";
import { resolveChatCoreRequestFormat } from "./chatCore/requestFormat.ts";
import { resolveChatCoreTargetFormat } from "./chatCore/targetFormat.ts";
import { resolveOmniGlyphTransport } from "../services/compression/imageTransportPolicy.ts";
import { stripStore, usesClaudeBridge } from "./chatCore/agentRouterProtocol.ts";
import { defaultClaudeToolType } from "./chatCore/claudeToolDefaults.ts";
import { injectSystemPrompt, injectCustomSystemPrompt } from "../services/systemPrompt.ts";
@@ -1548,16 +1549,13 @@ export async function handleChatCore({
// models, which is intentionally NOT `false` so the gate still preserves images.
supportsVision: getResolvedModelCapabilities({ provider, model: effectiveModel })
.supportsVision,
// Rotas diretas oficiais ('anthropic' API key e 'claude' OAuth) vs agregadores:
// o engine omniglyph exige 'direct' — agregadores redimensionam imagens
// (medido 2026-07-06). OAuth 'claude' é rota direta oficial (#7863).
providerTransport:
provider === "anthropic" ||
provider === "claude" ||
provider === "openai" ||
provider === "xai"
? ("direct" as const)
: ("aggregator" as const),
// OmniGlyph uses a measured provider/image-fidelity allowlist. Direct HTTP
// alone is not proof that a route preserves PNG bytes and dimensions.
...resolveOmniGlyphTransport(provider),
// Sem o provider, a contabilidade do OmniGlyph cai para `unknown` e
// recusa deduzir a semântica de cache (Anthropic usa buckets disjuntos,
// OpenAI reporta cached como subconjunto do input).
provider,
sourceFormat,
targetFormat,
compressionStage: "pre-translation" as const,

View File

@@ -9,6 +9,7 @@
* - modelo fora da allowlist medida → skip:model_not_approved
* - providerTransport !== 'direct' → skip:transport_not_direct
* (agregadores redimensionam imagens e destroem a legibilidade — medido)
* - imageTransportFidelity !== 'byte-preserving' → skip:transport_fidelity_unknown/resizes
* - wire não é Claude/OpenAI suportado → skip:target_format_not_supported
* - gate de rentabilidade interno do omniglyph decide o resto (patches 28px
* exatos; texto esparso/pequeno passa direto) → skip:not_profitable
@@ -20,14 +21,65 @@ import type { CompressionEngine, CompressionEngineApplyOptions } from "./types.t
import type { CompressionResult } from "../types.ts";
import { createCompressionStats } from "../stats.ts";
import {
isOmniGlyphSupportedGptModel,
isOmniGlyphSupportedModel,
buildOmniGlyphAccounting,
type OmniGlyphAccounting,
} from "../omniglyphTelemetry.ts";
import {
isOmniGlyphSupportedModelForScope,
mergeCompressionProfileOptions,
resolveCompressionProfile,
transformAnthropicMessages,
transformOpenAIChatCompletions,
transformOpenAIResponses,
type CompressionProfile,
type OmniGlyphSafetyScope,
} from "omniglyph";
import { isModelImageable } from "omniglyph/applicability";
/**
* Teto de modelos do OmniRoute — sempre o escopo mais restrito do pacote.
*
* `isOmniGlyphSupportedModel()` resolve o escopo lendo `OMNIGLYPH_PROFILE` do
* processo, e a lista base sai de `OMNIGLYPH_MODELS`. Duas variáveis do HOST
* decidiriam, 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 continua prometendo "Claude Fable 5 na rota
* direta medida". Fixar o escopo mais restrito faz o gate só poder ESTREITAR
* pela env, nunca alargar, e mantém a decisão na configuração do OmniRoute.
*/
const MEASURED_MODEL_SCOPE: OmniGlyphSafetyScope = "coding-safe";
/**
* Perfil padrão do OmniRoute.
*
* `aggressive` é a política que os recibos publicados mediram. `coding-safe` e
* `balanced` fixam `minCompressChars` no máximo e só colapsam histórico antigo:
* medido nesta base, uma sessão sem histórico acumulado fica em
* `below_min_chars` e a engine não faz nada — o operador veria "ligado, 0% de
* ganho". Ficam disponíveis como escolha explícita, não como default.
*/
const DEFAULT_PROFILE: OmniGlyphSafetyScope = "aggressive";
/** Perfil do passo (mais específico) > perfil global > default do OmniRoute. */
function resolveProfileName(options?: CompressionEngineApplyOptions): string {
const step = options?.stepConfig?.profile;
if (typeof step === "string" && step.trim()) return step;
const global = (options?.config as { omniglyph?: { profile?: unknown } } | undefined)?.omniglyph
?.profile;
if (typeof global === "string" && global.trim()) return global;
return DEFAULT_PROFILE;
}
/**
* O modelo precisa passar no teto medido E no escopo em vigor. Os dois wires
* (Anthropic e GPT) compartilham a mesma allowlist no pacote desde 1.4.0, então
* uma única checagem cobre os dois.
*/
function isModelWithinScope(model: string, scope: OmniGlyphSafetyScope): boolean {
if (!isOmniGlyphSupportedModelForScope(model, MEASURED_MODEL_SCOPE)) return false;
return isOmniGlyphSupportedModelForScope(model, scope);
}
function skip(body: Record<string, unknown>, reason: string): CompressionResult {
try {
return {
@@ -80,9 +132,36 @@ async function applyOmniglyph(
const model = options?.model ?? (body as { model?: string }).model ?? "";
if (options?.supportsVision !== true) return skip(body, "no_vision");
if (options?.providerTransport !== "direct") return skip(body, "transport_not_direct");
// Keep the old direct-call contract usable for standalone callers, but let
// production callers override it explicitly. The chat pipeline supplies
// `unknown` for every provider without a byte-preservation receipt.
if (
options?.imageTransportFidelity !== undefined &&
options.imageTransportFidelity !== "byte-preserving"
) {
return skip(
body,
options.imageTransportFidelity === "resizes"
? "transport_resizes_images"
: "transport_fidelity_unknown"
);
}
const stage = options?.compressionStage ?? "pre-translation";
const wireFormat = resolveWireFormat(body, options);
// A source/target format mismatch means the body is still on the wrong wire,
// even when the source itself is native Claude. Defer the engine until the
// translated provider body so Claude→OpenAI cannot be imaged once before
// translation and then considered again on the target wire.
const sourceWireFormat = options?.sourceFormat ?? wireFormat;
if (
stage === "pre-translation" &&
options?.targetFormat &&
sourceWireFormat &&
options.targetFormat !== sourceWireFormat
) {
return skip(body, "requires_post_translation");
}
// The pre-translation lane is retained for the existing native Claude
// passthrough. OpenAI requests must wait until translation has produced the
// exact provider wire, otherwise Responses input[] would be flattened by the
@@ -104,53 +183,98 @@ async function applyOmniglyph(
) {
return skip(body, "source_format_not_openai_responses");
}
const supportedModel =
wireFormat === "claude"
? isOmniGlyphSupportedModel(model)
: isOmniGlyphSupportedGptModel(model);
if (!supportedModel) return skip(body, "model_not_approved");
let profile: CompressionProfile;
try {
profile = resolveCompressionProfile(resolveProfileName(options));
} catch {
// `resolveCompressionProfile` lança em nome desconhecido. Um perfil que o
// pacote não entende não pode virar "roda com a política padrão".
return skip(body, "invalid_profile");
}
if (profile.name === "passthrough") return skip(body, "profile_passthrough");
if (!isModelWithinScope(model, profile.name)) {
return skip(body, "model_not_approved");
}
const preserveSystemPrompt =
(typeof options?.stepConfig?.preserveSystemPrompt === "boolean"
? options.stepConfig.preserveSystemPrompt
: options?.config?.preserveSystemPrompt) === true;
// `compressSystem` só existe no transform Anthropic. Os wires OpenAI honram
// apenas compressTools/gptHistory/minCompressChars/reflow e sempre trocam a
// instrução por um ponteiro para a imagem. Imagear o system quando o OmniRoute
// decidiu preservá-lo queimaria o prefixo quente que a política cache-aware
// está protegendo — e nada no corpo devolvido denunciaria isso. Sem como
// honrar a política nesse wire, a engine pula.
if (preserveSystemPrompt && wireFormat !== "claude") {
return skip(body, "system_preservation_unsupported_on_wire");
}
// OmniGlyph 1.3.x deliberately keeps unverified families (currently Grok)
// text-only until the operator acknowledges them via its own env gate.
if (!isModelImageable(model)) return skip(body, "model_not_imageable");
const started = Date.now();
let outBody: Record<string, unknown>;
let accounting: OmniGlyphAccounting | undefined;
try {
const encoded = new TextEncoder().encode(JSON.stringify(body));
// The upstream OpenAI transformer resolves its billing/render profile from
// body.model. Keep the provider body byte-compatible on output, but use the
// already-resolved engine model for that internal gate when a translator
// omitted the model or left an alias in place.
const transformBody =
wireFormat !== "claude" && model && body.model !== model ? { ...body, model } : body;
const encoded = new TextEncoder().encode(JSON.stringify(transformBody));
const overrides = preserveSystemPrompt ? { compressSystem: false } : {};
// Só `transformAnthropicMessages` resolve o perfil por conta própria; os
// transformadores OpenAI recebem TransformOptions cru e ignorariam o campo.
const openAIOptions = mergeCompressionProfileOptions(profile, overrides);
const result =
wireFormat === "claude"
? await transformAnthropicMessages({ body: encoded, model })
? await transformAnthropicMessages({
body: encoded,
model,
options: { ...overrides, profile: profile.name },
})
: wireFormat === "openai"
? await transformOpenAIChatCompletions(encoded)
: await transformOpenAIResponses(encoded);
const applied = wireFormat === "claude" ? result.applied : result.info.compressed;
? await transformOpenAIChatCompletions(encoded, openAIOptions)
: await transformOpenAIResponses(encoded, openAIOptions);
const applied = "applied" in result ? result.applied : result.info.compressed;
if (!applied) return skip(body, result.info?.reason ?? "not_profitable");
outBody = JSON.parse(new TextDecoder().decode(result.body)) as Record<string, unknown>;
if (transformBody !== body && body.model !== undefined) outBody.model = body.model;
accounting = buildOmniGlyphAccounting({
provider: options?.provider,
model,
originalBytes: encoded.byteLength,
transformedBytes: result.body.byteLength,
info: result.info,
durationMs: Date.now() - started,
});
} catch {
// Fail-open: qualquer erro no encode/transform/decode (ex.: corpo não serializável,
// render PNG estourando, JSON decodificado malformado) vira skip, nunca propaga.
return skip(body, "transform_error");
}
return {
body: outBody,
compressed: true,
stats: createCompressionStats(
body,
outBody,
"stacked",
["omniglyph:context-as-image"],
undefined,
Date.now() - started
),
};
const stats = createCompressionStats(
body,
outBody,
"stacked",
["omniglyph:context-as-image"],
undefined,
Date.now() - started
);
// A contabilidade só acompanha uma conversão que realmente aconteceu: um skip
// não tem economia para reportar, e inventar zeros ali viraria "0% de ganho"
// indistinguível de "a engine nem rodou".
if (accounting) stats.omniglyph = accounting;
return { body: outBody, compressed: true, stats };
}
export const omniglyphEngine: CompressionEngine = {
id: "omniglyph",
name: "OmniGlyph",
description:
"Contexto-como-imagem (Anthropic Fable 5, rota direta): system prompt, tool docs e histórico viram páginas PNG densas — ~10× menos tokens no bloco convertido.",
"Contexto-como-imagem para Claude Fable 5 na rota direta medida; wires GPT nativos ficam disponíveis apenas após recibo de fidelidade do provedor.",
icon: "image",
targets: ["messages", "tool_results"],
stackable: true,
@@ -160,7 +284,7 @@ export const omniglyphEngine: CompressionEngine = {
id: "omniglyph",
name: "OmniGlyph",
description:
"Contexto-como-imagem para Claude Fable 5 e GPT 5.6 via wires nativos Anthropic/OpenAI em rota direta.",
"Contexto-como-imagem para Claude Fable 5 na rota direta medida; transformadores GPT nativos permanecem fail-closed até validação do provedor.",
inputScope: "mixed",
targetLatencyMs: 250, // render+encode PNG de páginas grandes
supportsPreview: true,

View File

@@ -7,6 +7,9 @@ export type CompressionWireFormat = "claude" | "openai" | "openai-responses" | s
export type CompressionStage = "pre-translation" | "post-translation";
/** Whether an upstream route preserves OmniGlyph PNG bytes and dimensions. */
export type ImageTransportFidelity = "byte-preserving" | "resizes" | "unknown";
export interface EngineConfigField {
key: string;
type: "boolean" | "number" | "string" | "select" | "multiselect";
@@ -42,8 +45,11 @@ export interface CompressionEngineApplyOptions {
/** Como o request chega ao provider: rota direta oficial ('direct') vs
* agregador que pode reprocessar imagens ('aggregator'). O engine omniglyph
* exige 'direct' — medição 2026-07-06: agregadores redimensionam as páginas
* e destroem a legibilidade. undefined = desconhecido = skip (fail-closed). */
* e destroem a legibilidade. A política de produção também informa
* imageTransportFidelity; chamadas legadas sem esse campo mantêm o gate direct. */
providerTransport?: "direct" | "aggregator";
/** Independent image-fidelity gate; direct HTTP does not imply byte preservation. */
imageTransportFidelity?: ImageTransportFidelity;
/** Protocol shape before the current compression stage. */
sourceFormat?: CompressionWireFormat;
/** Protocol shape expected by the upstream provider. */
@@ -55,6 +61,10 @@ export interface CompressionEngineApplyOptions {
stepConfig?: Record<string, unknown>;
/** Authenticated principal (API key id) making the request. Used by CCR to scope its store. */
principalId?: string;
/** Provider resolvido do alvo. A contabilidade do omniglyph depende dele:
* Anthropic reporta input/cache em buckets disjuntos, OpenAI/xAI reportam
* cached como subconjunto do input. Ausente => `unknown` (falha fechado). */
provider?: string;
}
export interface CompressionEngine {

View File

@@ -0,0 +1,33 @@
/**
* Provider-level image transport policy for loss-sensitive compression engines.
*
* `supportsVision` only says that a model can read images. OmniGlyph also needs
* the PNG bytes and dimensions to survive the provider route unchanged. The
* allowlist below contains only paths with an existing OmniRoute receipt;
* everything else is deliberately classified as unknown and skipped.
*/
import type { ImageTransportFidelity } from "./engines/types.ts";
export type OmniGlyphTransportPolicy = {
providerTransport: "direct" | "aggregator";
imageTransportFidelity: ImageTransportFidelity;
};
const BYTE_PRESERVING_PROVIDERS = new Set(["anthropic", "claude"]);
export function resolveOmniGlyphTransport(
provider: string | null | undefined
): OmniGlyphTransportPolicy {
const normalized = typeof provider === "string" ? provider.trim().toLowerCase() : "";
if (BYTE_PRESERVING_PROVIDERS.has(normalized)) {
return {
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
};
}
return {
providerTransport: "aggregator",
imageTransportFidelity: "unknown",
};
}

View File

@@ -0,0 +1,156 @@
/**
* Ponte de telemetria do OmniGlyph — allowlist positiva.
*
* `TransformInfo` mistura contadores inofensivos com material que NUNCA pode
* ser persistido: bytes PNG, `imageSourceText(s)`, `recoverable[].text`, os
* sha8 de system/CLAUDE.md/primeira mensagem, os nomes de tags observadas e o
* bloco `env` (cwd, branch, versões). Copiar o objeto inteiro seria transformar
* a telemetria de compressão num vazamento do prompt.
*
* Este módulo não filtra por denylist — ele MONTA um objeto novo, campo a
* campo, só com número e enum. Um campo novo no upstream não entra sozinho.
*
* `normalizeAccounting()` (OmniGlyph 1.4.0) faz a parte difícil: classifica o
* grau de evidência da economia e resolve a semântica de cache por provider —
* Anthropic reporta input/cache-create/cache-read em buckets DISJUNTOS,
* enquanto OpenAI e xAI reportam `cached` como SUBCONJUNTO do input. Somar à
* mão dá double-count silencioso.
*/
import {
normalizeAccounting,
type AccountingProvider,
type OmniGlyphTransformInfo,
type SavingsEvidence,
} from "omniglyph";
/** Contabilidade segura de uma execução do OmniGlyph. Só número e enum. */
export interface OmniGlyphAccounting {
provider: AccountingProvider;
model?: string;
bytes: {
original?: number;
transformed?: number;
reduced?: number;
compressionRatio?: number;
};
tokens: {
estimatedOriginalInput?: number;
estimatedActualInput?: number;
estimatedReduced?: number;
image?: number;
};
savings: {
/** De onde saiu o número: contagem do provider, estimativa ou só bytes. */
evidence: SavingsEvidence;
inputTokensReduced?: number;
inputReductionRatio?: number;
};
images: {
count: number;
bytes: number;
pixels?: number;
};
/** Chars de origem imageados vs. mantidos como texto por turno. */
chars: {
original?: number;
imaged?: number;
static?: number;
dynamic?: number;
outgoingText?: number;
};
dynamicBlockCount?: number;
latencyMs?: number;
}
/**
* A semântica de cache de `normalizeAccounting` depende da família do provider,
* não do nome comercial da rota. Rota desconhecida vira `unknown`, que faz o
* upstream falhar fechado em vez de adivinhar buckets de cache.
*/
export function toAccountingProvider(provider: string | null | undefined): AccountingProvider {
const normalized = typeof provider === "string" ? provider.trim().toLowerCase() : "";
if (normalized === "anthropic" || normalized === "claude") return "anthropic";
if (normalized === "openai" || normalized === "codex" || normalized === "chatgpt") {
return "openai";
}
if (normalized === "xai" || normalized === "grok") return "xai";
return "unknown";
}
function count(value: unknown): number | undefined {
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
}
export function buildOmniGlyphAccounting(params: {
provider: string | null | undefined;
model?: string;
originalBytes: number;
transformedBytes: number;
info?: OmniGlyphTransformInfo | null;
durationMs?: number;
}): OmniGlyphAccounting {
const { info } = params;
const provider = toAccountingProvider(params.provider);
// `baselineImagedTokens` é o custo em tokens de texto do que foi imageado (o
// "teria pago assim"); `imageTokens` é o que as imagens custam de fato. Os
// dois só existem no wire GPT — no Anthropic a evidência honesta cai para
// bytes, e é isso que o campo `evidence` passa a dizer em vez de exibir um
// número sem procedência.
const normalized = normalizeAccounting({
provider,
...(params.model ? { model: params.model } : {}),
originalBytes: params.originalBytes,
transformedBytes: params.transformedBytes,
...(count(info?.baselineImagedTokens) !== undefined
? { estimatedOriginalInputTokens: info!.baselineImagedTokens }
: {}),
...(count(info?.imageTokens) !== undefined
? { estimatedTransformedInputTokens: info!.imageTokens }
: {}),
...(count(info?.imageTokens) !== undefined ? { imageTokens: info!.imageTokens } : {}),
...(params.durationMs !== undefined ? { proxyAddedLatencyMs: params.durationMs } : {}),
});
const chars = {
...(count(info?.origChars) !== undefined ? { original: info!.origChars } : {}),
...(count(info?.compressedChars) !== undefined ? { imaged: info!.compressedChars } : {}),
...(count(info?.staticChars) !== undefined ? { static: info!.staticChars } : {}),
...(count(info?.dynamicChars) !== undefined ? { dynamic: info!.dynamicChars } : {}),
...(count(info?.outgoingTextChars) !== undefined
? { outgoingText: info!.outgoingTextChars }
: {}),
};
return {
provider: normalized.provider,
...(normalized.model ? { model: normalized.model } : {}),
bytes: normalized.bytes,
tokens: {
...(normalized.tokens.estimatedOriginalInput !== undefined
? { estimatedOriginalInput: normalized.tokens.estimatedOriginalInput }
: {}),
...(normalized.tokens.estimatedActualInput !== undefined
? { estimatedActualInput: normalized.tokens.estimatedActualInput }
: {}),
...(normalized.tokens.estimatedReduced !== undefined
? { estimatedReduced: normalized.tokens.estimatedReduced }
: {}),
...(normalized.tokens.image !== undefined ? { image: normalized.tokens.image } : {}),
},
savings: normalized.savings,
images: {
count: count(info?.imageCount) ?? 0,
bytes: count(info?.imageBytes) ?? 0,
...(count(info?.imagePixels) !== undefined ? { pixels: info!.imagePixels } : {}),
},
chars,
...(count(info?.dynamicBlockCount) !== undefined
? { dynamicBlockCount: info!.dynamicBlockCount }
: {}),
...(normalized.latency.proxyAddedMs !== undefined
? { latencyMs: normalized.latency.proxyAddedMs }
: {}),
};
}

View File

@@ -110,5 +110,8 @@ export function mergeStackStep(
techniquesUsed: result.stats.techniquesUsed,
...(result.stats.rulesApplied ? { rulesApplied: result.stats.rulesApplied } : {}),
...(result.stats.durationMs !== undefined ? { durationMs: result.stats.durationMs } : {}),
// O agregado do pipeline soma tokens de todas as engines; a contabilidade
// física do omniglyph só faz sentido no passo que a produziu.
...(result.stats.omniglyph ? { omniglyph: result.stats.omniglyph } : {}),
});
}

View File

@@ -77,7 +77,7 @@ function isOpenAIResponsesPngImagePart(value: unknown): value is OpenAIResponses
}
function pngDimensionsFromDataUrl(value: string): { width: number; height: number } | null {
const marker = ",base64,";
const marker = ";base64,";
const markerIndex = value.indexOf(marker);
if (markerIndex < 0) return null;
return decodePngDimensions(value.slice(markerIndex + marker.length));

View File

@@ -11,6 +11,7 @@ import type {
CompressionEngineApplyOptions,
CompressionStage,
CompressionWireFormat,
ImageTransportFidelity,
} from "./engines/types.ts";
import { applyLiteCompression } from "./lite.ts";
import { cavemanCompress } from "./caveman.ts";
@@ -266,6 +267,7 @@ export function applyCompression(
options?: {
model?: string;
supportsVision?: boolean | null;
imageTransportFidelity?: ImageTransportFidelity;
sourceFormat?: CompressionWireFormat;
targetFormat?: CompressionWireFormat;
compressionStage?: CompressionStage;
@@ -292,6 +294,7 @@ function runCompression(
options?: {
model?: string;
supportsVision?: boolean | null;
imageTransportFidelity?: ImageTransportFidelity;
sourceFormat?: CompressionWireFormat;
targetFormat?: CompressionWireFormat;
compressionStage?: CompressionStage;
@@ -479,6 +482,9 @@ export async function applyCompressionAsync(
supportsVision?: boolean | null;
/** Direct-to-provider vs. aggregator transport (gates transport-sensitive engines like omniglyph). */
providerTransport?: "direct" | "aggregator";
/** Provider resolvido — a contabilidade do omniglyph depende dele. */
provider?: string;
imageTransportFidelity?: ImageTransportFidelity;
sourceFormat?: CompressionWireFormat;
targetFormat?: CompressionWireFormat;
compressionStage?: CompressionStage;
@@ -501,6 +507,9 @@ async function runCompressionAsync(
supportsVision?: boolean | null;
/** Direct-to-provider vs. aggregator transport (gates transport-sensitive engines like omniglyph). */
providerTransport?: "direct" | "aggregator";
/** Provider resolvido — a contabilidade do omniglyph depende dele. */
provider?: string;
imageTransportFidelity?: ImageTransportFidelity;
sourceFormat?: CompressionWireFormat;
targetFormat?: CompressionWireFormat;
compressionStage?: CompressionStage;
@@ -693,6 +702,9 @@ interface StackOptions {
supportsVision?: boolean | null;
/** Direct-to-provider vs. aggregator transport (gates transport-sensitive engines like omniglyph). */
providerTransport?: "direct" | "aggregator";
/** Provider resolvido — a contabilidade do omniglyph depende dele. */
provider?: string;
imageTransportFidelity?: ImageTransportFidelity;
sourceFormat?: CompressionWireFormat;
targetFormat?: CompressionWireFormat;
compressionStage?: CompressionStage;

View File

@@ -16,6 +16,7 @@ import type { RiskGateConfig } from "./riskGate/riskGate.ts";
import type { PipelineCircuitBreakerConfig } from "./pipelineEngineBreaker.ts";
import type { RiskGateStats } from "./riskGate/riskGateStep.ts";
import type { QuantumLockConfig, QuantumLockStats } from "./quantumLock/quantumPatterns.ts";
import type { OmniGlyphAccounting } from "./omniglyphTelemetry.ts";
// Re-export so consumers that already import from this module (e.g. src/lib/db/compression.ts)
// can get ENGINE_IDS without a second bare `@omniroute/open-sse/...engineCatalog.ts` specifier.
@@ -157,6 +158,22 @@ export interface LiveZoneConfig {
enabled: boolean;
}
/** Perfil semântico do OmniGlyph (pacote 1.4.0+). */
export type OmniglyphProfile = "coding-safe" | "balanced" | "aggressive" | "passthrough";
/**
* Política do OmniGlyph escolhida pelo operador.
*
* O perfil é um TETO: `mergeCompressionProfileOptions` do pacote não deixa um
* override reabrir uma lane que o perfil fechou. Trocar de `aggressive` para
* `coding-safe` mantém system, schemas de tools e tool results nativos, ao custo
* medido de a engine não fazer nada até a sessão acumular histórico
* (`minCompressChars` vai ao máximo). Por isso o default é `aggressive`.
*/
export interface OmniglyphConfig {
profile: OmniglyphProfile;
}
/** Lite detail settings for proactive request-time transformations. */
export interface LiteConfig {
/** Truncate tool-result strings over 2,000 characters before provider dispatch. */
@@ -206,6 +223,8 @@ export interface CompressionConfig {
comboOverrides: Record<string, CompressionMode>;
compressionComboId?: string | null;
stackedPipeline?: CompressionPipelineStep[];
/** Política do engine OmniGlyph (perfil semântico). */
omniglyph?: OmniglyphConfig;
/** Opt-in QuantumLock cache-prefix stabilization (default off). */
quantumLock?: QuantumLockConfig;
/** Opt-in per-step fidelity gate (default disabled). */
@@ -303,6 +322,12 @@ export interface CompressionStats {
validationWarnings?: string[];
validationErrors?: string[];
fallbackApplied?: boolean;
/**
* Contabilidade física do OmniGlyph, normalizada pelo próprio pacote
* (`normalizeAccounting`). Só número e enum — ver `omniglyphTelemetry.ts`
* para a allowlist e o que nunca pode entrar aqui.
*/
omniglyph?: OmniGlyphAccounting;
riskGate?: RiskGateStats;
/**
* Phase 4 (B): which `ultra` tier actually ran for this request.
@@ -341,6 +366,8 @@ export interface CompressionStats {
durationMs?: number;
rejected?: boolean;
rejectReason?: string;
/** Contabilidade física — presente só no passo omniglyph que comprimiu. */
omniglyph?: OmniGlyphAccounting;
}>;
/** Present only when QuantumLock stabilized ≥1 fragment this run. */
quantumLock?: QuantumLockStats;
@@ -460,6 +487,16 @@ export const DEFAULT_COMPRESSION_LANGUAGE_CONFIG: CompressionLanguageConfig = {
enabledPacks: ["en"],
};
/**
* `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 — como o OmniGlyph é opt-in, esse
* default entregaria "ligado, 0% de ganho".
*/
export const DEFAULT_OMNIGLYPH_CONFIG: OmniglyphConfig = {
profile: "aggressive",
};
export const DEFAULT_CONTEXT_EDITING_CONFIG: ContextEditingConfig = {
enabled: false,
};

8
package-lock.json generated
View File

@@ -60,7 +60,7 @@
"next-intl": "^4.13.6",
"next-themes": "^0.4.6",
"node-machine-id": "^1.1.12",
"omniglyph": "^1.0.2",
"omniglyph": "^1.4.0",
"onnxruntime-node": "~1.24.3",
"open": "^11.0.0",
"ora": "^9.4.1",
@@ -28871,9 +28871,9 @@
"license": "MIT"
},
"node_modules/omniglyph": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/omniglyph/-/omniglyph-1.3.1.tgz",
"integrity": "sha512-6QnZCoXYczjsPN2x+XpbimimjO6kCoSZUzsdSvoKjtw28U1U724VgLICBNaLX4FFs5jd7SrYNNs9Aee2iIkcoA==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/omniglyph/-/omniglyph-1.4.0.tgz",
"integrity": "sha512-4zAqDW9pBb2i+fiGOVLIKbdecZeo55UmKQoLku1apxo3TSA4gfqcMo2MqQpal1VicckUwTbexFLasW7qngXUHA==",
"license": "MIT",
"dependencies": {
"gpt-tokenizer": "^3.4.0"

View File

@@ -304,7 +304,7 @@
"next-intl": "^4.13.6",
"next-themes": "^0.4.6",
"node-machine-id": "^1.1.12",
"omniglyph": "^1.0.2",
"omniglyph": "^1.4.0",
"open": "^11.0.0",
"ora": "^9.4.1",
"parse5": "^8.0.1",

View File

@@ -17,10 +17,22 @@ import { SAMPLE_BEFORE_TEXT, SAMPLE_PAGE_PNG_DATA_URI, SAMPLE_METRICS } from "./
interface CompressionConfigLite {
engines?: Record<string, { enabled: boolean; level?: string }>;
omniglyph?: { profile?: string };
}
type EngineMap = Record<string, { enabled: boolean; level?: string }>;
/** Perfis do pacote, na ordem do mais permissivo ao mais restrito. O primeiro é
* o default: a política que os recibos publicados mediram. */
const PROFILES = [
{ id: "aggressive", key: "aggressive" },
{ id: "balanced", key: "balanced" },
{ id: "coding-safe", key: "codingSafe" },
{ id: "passthrough", key: "passthrough" },
] as const;
type ProfileId = (typeof PROFILES)[number]["id"];
/** The measured fail-closed gate chain, in evaluation order. Every no-op is telemetered
* as `skip:<reason>`; the engine only fires when all pass. */
const GATES = [
@@ -157,6 +169,40 @@ function GatesCard() {
);
}
function ProfileCard(props: {
profile: ProfileId;
disabled: boolean;
onChange: (next: ProfileId) => void;
}) {
const t = useTranslations("omniglyph");
const selected = PROFILES.find((p) => p.id === props.profile) ?? PROFILES[0];
return (
<Card className="p-6">
<div className="flex flex-col gap-3">
<h2 className="text-lg font-semibold">{t("profileTitle")}</h2>
<p className="max-w-xl text-sm text-text-muted">{t("profileDescription")}</p>
<select
className="w-full max-w-sm rounded-md border border-border bg-surface px-3 py-2 text-sm"
value={props.profile}
disabled={props.disabled}
aria-label={t("profileAria")}
data-testid="omniglyph-profile-select"
onChange={(e) => props.onChange(e.target.value as ProfileId)}
>
{PROFILES.map((p) => (
<option key={p.id} value={p.id}>
{t(`profiles.${p.key}.label`)}
</option>
))}
</select>
<span className="max-w-xl text-xs text-text-muted">
{t(`profiles.${selected.key}.description`)}
</span>
</div>
</Card>
);
}
function EnableCard(props: {
enabled: boolean;
disabled: boolean;
@@ -199,6 +245,7 @@ function EnableCard(props: {
export default function OmniglyphContextPageClient() {
const [engines, setEngines] = useState<EngineMap>({});
const [enabled, setEnabled] = useState(false);
const [profile, setProfile] = useState<ProfileId>("aggressive");
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [status, setStatus] = useState<"" | "saved" | "error">("");
@@ -210,6 +257,8 @@ export default function OmniglyphContextPageClient() {
const e = data?.engines ?? {};
setEngines(e);
setEnabled(e.omniglyph?.enabled === true);
const stored = data?.omniglyph?.profile;
if (PROFILES.some((p) => p.id === stored)) setProfile(stored as ProfileId);
})
.catch(() => {})
.finally(() => setLoading(false));
@@ -245,12 +294,41 @@ export default function OmniglyphContextPageClient() {
}
};
// O perfil vive na config do engine (não no mapa `engines`), então é um PATCH
// próprio — misturá-lo no payload do toggle reescreveria o mapa inteiro.
const changeProfile = async (next: ProfileId) => {
const previous = profile;
setProfile(next);
setSaving(true);
setStatus("");
try {
const res = await fetch("/api/settings/compression", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ omniglyph: { profile: next } }),
});
if (res.ok) {
setStatus("saved");
setTimeout(() => setStatus(""), 2000);
} else {
setProfile(previous);
setStatus("error");
}
} catch {
setProfile(previous);
setStatus("error");
} finally {
setSaving(false);
}
};
return (
<div className="mx-auto flex max-w-4xl flex-col gap-6 p-6" data-testid="omniglyph-page">
<PageHeader />
<EconomicsCard />
<BeforeAfterCard />
<GatesCard />
<ProfileCard profile={profile} disabled={loading || saving} onChange={changeProfile} />
<EnableCard
enabled={enabled}
disabled={loading || saving}

View File

@@ -20,6 +20,7 @@
import { logger } from "@omniroute/open-sse/utils/logger.ts";
import { estimateTokens } from "@omniroute/open-sse/services/contextManager.ts";
import { adaptBodyForCompression } from "@omniroute/open-sse/services/compression/bodyAdapter.ts";
import { resolveOmniGlyphTransport } from "@omniroute/open-sse/services/compression/imageTransportPolicy.ts";
import type {
CompressionConfig,
CompressionResult,
@@ -55,13 +56,16 @@ export async function applyResponsesWsCompression(
if (!enabled || !settings) return responseBody;
const adapter = adaptBodyForCompression(responseBody);
if (!adapter.adapted || !Array.isArray(adapter.body.messages) || adapter.body.messages.length === 0) {
if (
!adapter.adapted ||
!Array.isArray(adapter.body.messages) ||
adapter.body.messages.length === 0
) {
return responseBody;
}
const { selectCompressionStrategy, applyCompressionAsync } = await import(
"@omniroute/open-sse/services/compression/strategySelector.ts"
);
const { selectCompressionStrategy, applyCompressionAsync } =
await import("@omniroute/open-sse/services/compression/strategySelector.ts");
const estimatedTokens = estimateTokens(adapter.body.messages);
const cachingContext = {
@@ -83,8 +87,8 @@ export async function applyResponsesWsCompression(
const result = await applyCompressionAsync(adapter.body, mode, {
model: ctx.model,
providerTransport:
ctx.provider === "anthropic" || ctx.provider === "claude" ? "direct" : "aggregator",
...resolveOmniGlyphTransport(ctx.provider),
provider: ctx.provider,
config: settings as CompressionConfig,
cachingContext,
});

View File

@@ -8534,13 +8534,13 @@
},
"omniglyph": {
"preview": "Preview",
"description": "Context-as-image compression. Renders the system prompt, tool documentation, and dense history as compact PNG pages that Claude Fable 5 reads instead of text. Image tokens are billed by dimensions rather than characters, so the converted block costs about 10× less. Direct Anthropic route only.",
"description": "Context-as-image compression. Renders the system prompt, tool documentation, and dense history as compact PNG pages for the measured Claude Fable 5 path. The published OmniGlyph package also exposes native GPT 5.6 transformers, but OmniRoute keeps those routes fail-closed until provider fidelity and reading receipts exist.",
"economicsTitle": "The economics",
"economics": {
"fewerTokens": "fewer tokens on the converted block",
"savings": "end-to-end savings (measured)",
"imageTokens": "image tokens for a 1568×728 page (about 28k characters)",
"accuracy": "reading accuracy on Fable 5 (n=30)"
"accuracy": "scoped Fable 5 reading receipt"
},
"beforeAfterTitle": "Before → after",
"blockSavings": "{percent}% tokens on this block",
@@ -8553,18 +8553,18 @@
"gates": {
"model": {
"label": "Model",
"pass": "claude-fable-5",
"why": "Only Fable 5 reads dense pages at 100% accuracy (measured, n=30). GPT-5.5 and Gemini 2.5 Flash are blocked."
"pass": "claude-fable-5 (measured); gpt-5.6 (HOLD)",
"why": "Only the measured Fable 5 path is enabled in OmniRoute. GPT 5.6 is structurally supported by the package but remains blocked until its provider receipt; unverified families such as Grok stay text-only."
},
"transport": {
"label": "Transport",
"pass": "direct Anthropic",
"why": "Aggregators resample images and destroy legibility — only the direct route is authoritative."
"pass": "direct provider",
"why": "Aggregators may resample images and destroy legibility — only a direct provider route is authoritative."
},
"format": {
"label": "Format",
"pass": "native Claude",
"why": "The body must use Claude format and must never put a system role inside messages."
"pass": "native Claude/OpenAI",
"why": "The body must match the provider wire: Claude Messages, OpenAI Chat Completions, or native OpenAI Responses input[]."
},
"profitable": {
"label": "Profitable",
@@ -8573,7 +8573,28 @@
}
},
"enableTitle": "Enable the engine",
"enableDescription": "Runs last in the stack (after RTK/Caveman cleans the text, OmniGlyph converts the remainder to images) and also runs standalone through <code>omniglyph</code> mode. This is a preview and remains off by default until end-to-end validation is complete.",
"enableDescription": "Runs last in the stack after text engines clean the request, using the native provider wire; OpenAI Chat/Responses requests are compressed after translation so their shape is preserved. It also runs standalone through <code>omniglyph</code> mode. This is a preview and remains off by default until end-to-end validation is complete.",
"profileTitle": "Compression profile",
"profileDescription": "The profile is a ceiling, not a floor: a stricter profile cannot be reopened by a per-step override. Measured on this codebase: with coding-safe or balanced, a session that has not accumulated history yet compresses nothing, because both raise the minimum-characters threshold and keep the system prompt, tool schemas and tool results native.",
"profiles": {
"aggressive": {
"label": "Aggressive (default)",
"description": "The policy the published receipts measured. Images the system prompt, tool documentation and dense history."
},
"balanced": {
"label": "Balanced",
"description": "Keeps live state native and protects the last 8 turns; only collapses older closed history."
},
"codingSafe": {
"label": "Coding-safe",
"description": "Keeps authority, tool schemas and live tool output native, protecting the last 12 turns. Compresses nothing until the session accumulates history."
},
"passthrough": {
"label": "Passthrough",
"description": "Routes without transforming. The engine is skipped and the request is forwarded untouched."
}
},
"profileAria": "Select the OmniGlyph compression profile",
"saved": "Saved.",
"saveFailed": "Could not save.",
"enableAria": "Enable the OmniGlyph engine",

View File

@@ -8534,13 +8534,13 @@
},
"omniglyph": {
"preview": "Visualização",
"description": "Compressão de contexto como imagem. Renderiza o prompt de sistema, a documentação de ferramentas e o histórico denso como páginas PNG compactas que o Claude Fable 5 lê em vez de texto. Os tokens de imagem são cobrados por dimensões em vez de caracteres, então o bloco convertido custa cerca de 10× menos. Somente na rota direta da Anthropic.",
"description": "Compressão de contexto como imagem. Renderiza o prompt de sistema, a documentação de ferramentas e o histórico denso como páginas PNG compactas para a rota medida do Claude Fable 5. O pacote OmniGlyph também expõe transformadores nativos para GPT 5.6, mas o OmniRoute mantém essas rotas fail-closed até existirem recibos de fidelidade do provedor e de leitura.",
"economicsTitle": "A economia",
"economics": {
"fewerTokens": "menos tokens no bloco convertido",
"savings": "economia de ponta a ponta (medida)",
"imageTokens": "tokens de imagem para uma página de 1568×728 (cerca de 28 mil caracteres)",
"accuracy": "precio de leitura no Fable 5 (n=30)"
"accuracy": "recibo de leitura do Fable 5 (escopo medido)"
},
"beforeAfterTitle": "Antes → depois",
"blockSavings": "{percent}% de tokens neste bloco",
@@ -8553,18 +8553,18 @@
"gates": {
"model": {
"label": "Modelo",
"pass": "claude-fable-5",
"why": "Somente o Fable 5 lê páginas densas com 100% de precisão (medido, n=30). GPT-5.5 e Gemini 2.5 Flash são bloqueados."
"pass": "claude-fable-5 (medido); gpt-5.6 (HOLD)",
"why": "Somente a rota medida do Fable 5 está habilitada no OmniRoute. O GPT 5.6 tem suporte estrutural no pacote, mas continua bloqueado até seu recibo do provedor; famílias não verificadas, como Grok, permanecem em texto."
},
"transport": {
"label": "Transporte",
"pass": "direto Anthropic",
"why": "Agregadores reamostram imagens e destroem a legibilidade — apenas a rota direta é confiável."
"pass": "provedor direto",
"why": "Agregadores podem reamostrar imagens e destruir a legibilidade — apenas uma rota direta do provedor é confiável."
},
"format": {
"label": "Formato",
"pass": "Claude nativo",
"why": "O corpo deve usar o formato Claude e nunca colocar um papel system dentro de messages."
"pass": "Claude/OpenAI nativo",
"why": "O corpo precisa corresponder ao wire do provedor: Claude Messages, OpenAI Chat Completions ou input[] nativo do OpenAI Responses."
},
"profitable": {
"label": "Rentável",
@@ -8573,7 +8573,28 @@
}
},
"enableTitle": "Ativar a engine",
"enableDescription": "Executa por último na pilha (depois que RTK/Caveman limpa o texto, o OmniGlyph converte o restante em imagens) e também roda de forma independente pelo modo <code>omniglyph</code>. Este é um preview e permanece desativado por padrão até que a validação de ponta a ponta seja concluída.",
"enableDescription": "Executa por último na pilha, depois que os engines de texto limpam a solicitação, usando o wire nativo do provedor; solicitações OpenAI Chat/Responses são comprimidas depois da tradução para preservar seu formato. Também roda de forma independente pelo modo <code>omniglyph</code>. Este é um preview e permanece desativado por padrão até que a validação de ponta a ponta seja concluída.",
"profileTitle": "Perfil de compressão",
"profileDescription": "O perfil é um teto, não um piso: um perfil mais restrito não pode ser reaberto por um override de passo. Medido nesta base: com coding-safe ou balanced, uma sessão que ainda não acumulou histórico não comprime nada, porque os dois elevam o mínimo de caracteres e mantêm o system prompt, os schemas de tools e os tool results nativos.",
"profiles": {
"aggressive": {
"label": "Agressivo (padrão)",
"description": "A política que os recibos publicados mediram. Imageia o system prompt, a documentação de tools e o histórico denso."
},
"balanced": {
"label": "Equilibrado",
"description": "Mantém o estado vivo nativo e protege os últimos 8 turnos; só colapsa histórico antigo já fechado."
},
"codingSafe": {
"label": "Seguro para código",
"description": "Mantém autoridade, schemas de tools e saída de ferramenta nativos, protegendo os últimos 12 turnos. Não comprime nada até a sessão acumular histórico."
},
"passthrough": {
"label": "Sem transformação",
"description": "Só roteia. A engine é pulada e o request segue intacto."
}
},
"profileAria": "Selecionar o perfil de compressão do OmniGlyph",
"saved": "Salvo.",
"saveFailed": "Não foi possível salvar.",
"enableAria": "Ativar a engine OmniGlyph",

View File

@@ -8574,6 +8574,27 @@
},
"enableTitle": "Bật bộ máy",
"enableDescription": "Chạy cuối cùng trong ngăn xếp (sau khi RTK/Caveman làm sạch văn bản, OmniGlyph chuyển phần còn lại thành hình ảnh) và cũng có thể chạy độc lập qua chế độ <code>omniglyph</code>. Đây là bản xem trước và mặc định vẫn tắt cho đến khi hoàn tất kiểm thử đầu cuối.",
"profileTitle": "Hồ sơ nén",
"profileDescription": "Hồ sơ là giới hạn trên, không phải giới hạn dưới: một hồ sơ chặt chẽ hơn không thể bị mở lại bằng ghi đè ở từng bước. Đo trên chính mã nguồn này: với coding-safe hoặc balanced, một phiên chưa tích lũy lịch sử sẽ không nén gì cả, vì cả hai đều nâng ngưỡng số ký tự tối thiểu và giữ nguyên system prompt, lược đồ công cụ và kết quả công cụ.",
"profiles": {
"aggressive": {
"label": "Tích cực (mặc định)",
"description": "Chính sách mà các biên nhận đã công bố đo được. Kết xuất system prompt, tài liệu công cụ và lịch sử dày đặc thành ảnh."
},
"balanced": {
"label": "Cân bằng",
"description": "Giữ nguyên trạng thái đang hoạt động và bảo vệ 8 lượt gần nhất; chỉ gộp lịch sử cũ đã khép lại."
},
"codingSafe": {
"label": "An toàn cho lập trình",
"description": "Giữ nguyên thẩm quyền, lược đồ công cụ và đầu ra công cụ đang hoạt động, bảo vệ 12 lượt gần nhất. Không nén gì cho đến khi phiên tích lũy lịch sử."
},
"passthrough": {
"label": "Không biến đổi",
"description": "Chỉ định tuyến. Engine bị bỏ qua và yêu cầu được chuyển tiếp nguyên vẹn."
}
},
"profileAria": "Chọn hồ sơ nén của OmniGlyph",
"saved": "Đã lưu.",
"saveFailed": "Không thể lưu.",
"enableAria": "Bật bộ máy OmniGlyph",

View File

@@ -26,6 +26,8 @@ import {
DEFAULT_CODEX_RESPONSES_CONFIG,
type CodexResponsesConfig,
type ContextEditingConfig,
DEFAULT_OMNIGLYPH_CONFIG,
type OmniglyphConfig,
type EngineToggle,
type HeadroomConfig,
type McpAccessibilityConfig,
@@ -304,6 +306,19 @@ function normalizeLanguageConfig(value: unknown): CompressionLanguageConfig {
};
}
function normalizeOmniglyphConfig(value: unknown): OmniglyphConfig {
const record = toRecord(value);
const profile = record.profile;
// Um perfil desconhecido não pode virar "roda com a política padrão": cai para
// o default explícito, e o adapter ainda falha fechado se algo passar por aqui.
return {
profile:
profile === "coding-safe" || profile === "balanced" || profile === "passthrough"
? profile
: DEFAULT_OMNIGLYPH_CONFIG.profile,
};
}
function normalizeContextEditingConfig(value: unknown): ContextEditingConfig {
const record = toRecord(value);
return {
@@ -621,6 +636,7 @@ export async function getCompressionSettings(): Promise<CompressionConfig> {
...buildDetailConfigDefaults(),
contextBudget: normalizeContextBudgetConfig(undefined),
contextEditing: { ...DEFAULT_CONTEXT_EDITING_CONFIG },
omniglyph: { ...DEFAULT_OMNIGLYPH_CONFIG },
liveZone: { enabled: false },
engines: {},
activeComboId: null,
@@ -744,6 +760,9 @@ export async function getCompressionSettings(): Promise<CompressionConfig> {
case "contextEditing":
config.contextEditing = normalizeContextEditingConfig(parsed);
break;
case "omniglyph":
config.omniglyph = normalizeOmniglyphConfig(parsed);
break;
case "liveZone":
config.liveZone = { enabled: toRecord(parsed).enabled === true };
break;

View File

@@ -346,6 +346,19 @@ export const contextBudgetConfigSchema = z
})
.strict();
/**
* Perfil semântico do OmniGlyph. O perfil é um TETO: o pacote não deixa um
* override reabrir uma lane que o perfil fechou. `aggressive` é o default e a
* política que os recibos publicados mediram; `coding-safe`/`balanced` mantêm
* system, schemas de tools e tool results nativos, e não comprimem nada até a
* sessão acumular histórico.
*/
export const omniglyphConfigSchema = z
.object({
profile: z.enum(["coding-safe", "balanced", "aggressive", "passthrough"]),
})
.strict();
export const compressionSettingsUpdateSchema = z
.object({
enabled: z.boolean().optional(),
@@ -373,6 +386,7 @@ export const compressionSettingsUpdateSchema = z
ccr: ccrConfigSchema.optional(),
contextBudget: contextBudgetConfigSchema.optional(),
contextEditing: contextEditingConfigSchema.optional(),
omniglyph: omniglyphConfigSchema.optional(),
liveZone: z.object({ enabled: z.boolean() }).strict().optional(),
engines: z.record(z.string(), engineToggleSchema).optional(),
enginesExplicit: z.boolean().optional(),

View File

@@ -1,86 +0,0 @@
{
"cloudAgentGuard": {
"jules": {
"message": "Provider \"jules\" is a cloud-agent provider and does not support direct chat completions; use the Cloud Agents task API instead.",
"status": 400,
"throws": true
}
},
"fallback": {
"className": "DefaultExecutor",
"configSource": "openai",
"provider": "golden-test-unknown-provider"
},
"searchGuard": {
"brave-search": {
"message": "Provider \"brave-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"duckduckgo-free": {
"message": "Provider \"duckduckgo-free\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"exa-search": {
"message": "Provider \"exa-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"firecrawl": {
"message": "Provider \"firecrawl\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"google-pse-search": {
"message": "Provider \"google-pse-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"linkup-search": {
"message": "Provider \"linkup-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"ollama-search": {
"message": "Provider \"ollama-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"perplexity-search": {
"message": "Provider \"perplexity-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"searchapi-search": {
"message": "Provider \"searchapi-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"searxng-search": {
"message": "Provider \"searxng-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"serper-search": {
"message": "Provider \"serper-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"tavily-search": {
"message": "Provider \"tavily-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"youcom-search": {
"message": "Provider \"youcom-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
},
"zai-search": {
"message": "Provider \"zai-search\" is a search provider and does not support chat completions; use the /v1/search endpoint instead.",
"status": 400,
"throws": true
}
}
}

View File

@@ -1,691 +0,0 @@
{
"entries": {
"9router": {
"className": "NineRouterExecutor",
"configSource": "<custom-config>",
"provider": "9router"
},
"adapta-web": {
"className": "AdaptaWebExecutor",
"configSource": "<custom-config>",
"provider": "adapta-web"
},
"adobe-firefly": {
"className": "AdobeFireflyExecutor",
"configSource": "<custom-config>",
"provider": "adobe-firefly"
},
"adp-web": {
"className": "AdaptaWebExecutor",
"configSource": "<custom-config>",
"provider": "adapta-web"
},
"agy": {
"className": "AntigravityExecutor",
"configSource": "antigravity",
"provider": "antigravity"
},
"amazon-q": {
"className": "KiroExecutor",
"configSource": "kiro",
"provider": "amazon-q"
},
"antigravity": {
"className": "AntigravityExecutor",
"configSource": "antigravity",
"provider": "antigravity"
},
"auggie": {
"className": "AuggieExecutor",
"configSource": "<custom-config>",
"provider": "auggie"
},
"azure-ai": {
"className": "AzureAiExecutor",
"configSource": "openai",
"provider": "azure-ai"
},
"azure-openai": {
"className": "AzureOpenAIExecutor",
"configSource": "openai",
"provider": "azure-openai"
},
"bb-web": {
"className": "BlackboxWebExecutor",
"configSource": "<custom-config>",
"provider": "blackbox-web"
},
"bedrock": {
"className": "BedrockExecutor",
"configSource": "bedrock",
"provider": "bedrock"
},
"blackbox-web": {
"className": "BlackboxWebExecutor",
"configSource": "<custom-config>",
"provider": "blackbox-web"
},
"cbcn": {
"className": "CodeBuddyCnExecutor",
"configSource": "codebuddy-cn",
"provider": "codebuddy-cn"
},
"cf": {
"className": "CloudflareAIExecutor",
"configSource": "cloudflare-ai",
"provider": "cloudflare-ai"
},
"cgpt-codex": {
"className": "ChatGptWebCodexExecutor",
"configSource": "<custom-config>",
"provider": "chatgpt-web-codex"
},
"cgpt-web": {
"className": "ChatGptWebExecutor",
"configSource": "<custom-config>",
"provider": "chatgpt-web"
},
"chatgpt-web": {
"className": "ChatGptWebExecutor",
"configSource": "<custom-config>",
"provider": "chatgpt-web"
},
"chatgpt-web-codex": {
"className": "ChatGptWebCodexExecutor",
"configSource": "<custom-config>",
"provider": "chatgpt-web-codex"
},
"cheaperinference": {
"className": "CheaperInferenceExecutor",
"configSource": "cheaperinference",
"provider": "cheaperinference"
},
"chipotle": {
"className": "ChipotleExecutor",
"configSource": "<custom-config>",
"provider": "chipotle"
},
"cinf": {
"className": "CheaperInferenceExecutor",
"configSource": "cheaperinference",
"provider": "cheaperinference"
},
"claude-web": {
"className": "ClaudeWebExecutor",
"configSource": "<custom-config>",
"provider": "claude-web"
},
"cliproxyapi": {
"className": "CliproxyapiExecutor",
"configSource": "<custom-config>",
"provider": "cliproxyapi"
},
"cloudflare-ai": {
"className": "CloudflareAIExecutor",
"configSource": "cloudflare-ai",
"provider": "cloudflare-ai"
},
"cmd": {
"className": "CommandCodeExecutor",
"configSource": "<custom-config>",
"provider": "command-code"
},
"cnl": {
"className": "ConolWebExecutor",
"configSource": "<custom-config>",
"provider": "conol-web"
},
"codebuddy-cn": {
"className": "CodeBuddyCnExecutor",
"configSource": "codebuddy-cn",
"provider": "codebuddy-cn"
},
"codex": {
"className": "CodexExecutor",
"configSource": "codex",
"provider": "codex"
},
"command-code": {
"className": "CommandCodeExecutor",
"configSource": "<custom-config>",
"provider": "command-code"
},
"conol-web": {
"className": "ConolWebExecutor",
"configSource": "<custom-config>",
"provider": "conol-web"
},
"copilot": {
"className": "CopilotWebExecutor",
"configSource": "<custom-config>",
"provider": "copilot-web"
},
"copilot-m365-web": {
"className": "CopilotM365WebExecutor",
"configSource": "<custom-config>",
"provider": "copilot-m365-web"
},
"copilot-web": {
"className": "CopilotWebExecutor",
"configSource": "<custom-config>",
"provider": "copilot-web"
},
"cpa": {
"className": "CliproxyapiExecutor",
"configSource": "<custom-config>",
"provider": "cliproxyapi"
},
"cu": {
"className": "CursorExecutor",
"configSource": "cursor",
"provider": "cursor"
},
"cursor": {
"className": "CursorExecutor",
"configSource": "cursor",
"provider": "cursor"
},
"cw-web": {
"className": "ClaudeWebExecutor",
"configSource": "<custom-config>",
"provider": "claude-web"
},
"dario": {
"className": "DarioExecutor",
"configSource": "<custom-config>",
"provider": "dario"
},
"db": {
"className": "DoubaoWebExecutor",
"configSource": "<custom-config>",
"provider": "doubao-web"
},
"ddgw": {
"className": "DuckDuckGoWebExecutor",
"configSource": "<custom-config>",
"provider": "duckduckgo-web"
},
"deepseek-web": {
"className": "DeepSeekWebWithAutoRefreshExecutor",
"configSource": "<custom-config>",
"provider": "deepseek-web"
},
"devin": {
"className": "DevinCliExecutor",
"configSource": "<custom-config>",
"provider": "devin-cli"
},
"devin-cli": {
"className": "DevinCliExecutor",
"configSource": "<custom-config>",
"provider": "devin-cli"
},
"devin-cli-agentic": {
"className": "DevinCliAgenticExecutor",
"configSource": "<custom-config>",
"provider": "devin-cli-agentic"
},
"devin-desktop": {
"className": "DevinDesktopExecutor",
"configSource": "devin-desktop",
"provider": "devin-desktop"
},
"doubao-web": {
"className": "DoubaoWebExecutor",
"configSource": "<custom-config>",
"provider": "doubao-web"
},
"dr": {
"className": "DarioExecutor",
"configSource": "<custom-config>",
"provider": "dario"
},
"ds-web": {
"className": "DeepSeekWebWithAutoRefreshExecutor",
"configSource": "<custom-config>",
"provider": "deepseek-web"
},
"duckduckgo-web": {
"className": "DuckDuckGoWebExecutor",
"configSource": "<custom-config>",
"provider": "duckduckgo-web"
},
"felo": {
"className": "FeloWebExecutor",
"configSource": "<custom-config>",
"provider": "felo-web"
},
"felo-web": {
"className": "FeloWebExecutor",
"configSource": "<custom-config>",
"provider": "felo-web"
},
"firefly": {
"className": "AdobeFireflyExecutor",
"configSource": "<custom-config>",
"provider": "adobe-firefly"
},
"gc": {
"className": "GrokCliExecutor",
"configSource": "grok-cli",
"provider": "grok-cli"
},
"gembiz": {
"className": "GeminiBusinessExecutor",
"configSource": "<custom-config>",
"provider": "gemini-business"
},
"gemini-business": {
"className": "GeminiBusinessExecutor",
"configSource": "<custom-config>",
"provider": "gemini-business"
},
"gemini-web": {
"className": "GeminiWebExecutor",
"configSource": "<custom-config>",
"provider": "gemini-web"
},
"ghe-copilot": {
"className": "GheCopilotExecutor",
"configSource": "<custom-config>",
"provider": "ghe-copilot"
},
"github": {
"className": "GithubExecutor",
"configSource": "github",
"provider": "github"
},
"gitlab": {
"className": "GitlabExecutor",
"configSource": "<custom-config>",
"provider": "gitlab"
},
"gitlab-duo": {
"className": "GitlabExecutor",
"configSource": "<custom-config>",
"provider": "gitlab-duo"
},
"glm": {
"className": "GlmExecutor",
"configSource": "glm",
"provider": "glm"
},
"glm-cn": {
"className": "GlmExecutor",
"configSource": "glm-cn",
"provider": "glm-cn"
},
"glmt": {
"className": "GlmExecutor",
"configSource": "glmt",
"provider": "glmt"
},
"grok-cli": {
"className": "GrokCliExecutor",
"configSource": "grok-cli",
"provider": "grok-cli"
},
"grok-web": {
"className": "GrokWebExecutor",
"configSource": "<custom-config>",
"provider": "grok-web"
},
"gweb": {
"className": "GeminiWebExecutor",
"configSource": "<custom-config>",
"provider": "gemini-web"
},
"ha": {
"className": "HyperAgentExecutor",
"configSource": "<custom-config>",
"provider": "hyperagent"
},
"hailuo-web": {
"className": "HailuoWebExecutor",
"configSource": "<custom-config>",
"provider": "hailuo-web"
},
"hc": {
"className": "HuggingChatExecutor",
"configSource": "<custom-config>",
"provider": "huggingchat"
},
"huggingchat": {
"className": "HuggingChatExecutor",
"configSource": "<custom-config>",
"provider": "huggingchat"
},
"hyperagent": {
"className": "HyperAgentExecutor",
"configSource": "<custom-config>",
"provider": "hyperagent"
},
"in-ai": {
"className": "InnerAiExecutor",
"configSource": "<custom-config>",
"provider": "inner-ai"
},
"inner-ai": {
"className": "InnerAiExecutor",
"configSource": "<custom-config>",
"provider": "inner-ai"
},
"kimi": {
"className": "MoonshotExecutor",
"configSource": "kimi",
"provider": "kimi"
},
"kimi-coding": {
"className": "KimiExecutor",
"configSource": "kimi-coding",
"provider": "kimi-coding"
},
"kimi-coding-apikey": {
"className": "KimiExecutor",
"configSource": "kimi-coding-apikey",
"provider": "kimi-coding-apikey"
},
"kimi-web": {
"className": "KimiWebExecutor",
"configSource": "<custom-config>",
"provider": "kimi-web"
},
"kiro": {
"className": "KiroExecutor",
"configSource": "kiro",
"provider": "kiro"
},
"lma": {
"className": "LMArenaExecutor",
"configSource": "<custom-config>",
"provider": "lmarena"
},
"lmarena": {
"className": "LMArenaExecutor",
"configSource": "<custom-config>",
"provider": "lmarena"
},
"mcode": {
"className": "MimocodeExecutor",
"configSource": "<custom-config>",
"provider": "mimocode"
},
"microsoft-designer-web": {
"className": "MicrosoftDesignerWebExecutor",
"configSource": "<custom-config>",
"provider": "microsoft-designer-web"
},
"mimocode": {
"className": "MimocodeExecutor",
"configSource": "<custom-config>",
"provider": "mimocode"
},
"moonshot": {
"className": "MoonshotExecutor",
"configSource": "moonshot",
"provider": "moonshot"
},
"ms-web": {
"className": "MuseSparkWebExecutor",
"configSource": "<custom-config>",
"provider": "muse-spark-web"
},
"msdesigner": {
"className": "MicrosoftDesignerWebExecutor",
"configSource": "<custom-config>",
"provider": "microsoft-designer-web"
},
"muse-spark-web": {
"className": "MuseSparkWebExecutor",
"configSource": "<custom-config>",
"provider": "muse-spark-web"
},
"nlpcloud": {
"className": "NlpCloudExecutor",
"configSource": "nlpcloud",
"provider": "nlpcloud"
},
"notion-web": {
"className": "NotionWebExecutor",
"configSource": "<custom-config>",
"provider": "notion-web"
},
"nr": {
"className": "NineRouterExecutor",
"configSource": "<custom-config>",
"provider": "9router"
},
"nw": {
"className": "NotionWebExecutor",
"configSource": "<custom-config>",
"provider": "notion-web"
},
"opencode": {
"className": "OpencodeExecutor",
"configSource": "opencode-zen",
"provider": "opencode-zen"
},
"opencode-go": {
"className": "OpencodeExecutor",
"configSource": "opencode-go",
"provider": "opencode-go"
},
"opencode-zen": {
"className": "OpencodeExecutor",
"configSource": "opencode-zen",
"provider": "opencode-zen"
},
"pepper": {
"className": "ChipotleExecutor",
"configSource": "<custom-config>",
"provider": "chipotle"
},
"perplexity-web": {
"className": "PerplexityWebExecutor",
"configSource": "<custom-config>",
"provider": "perplexity-web"
},
"poe-web": {
"className": "PoeWebExecutor",
"configSource": "<custom-config>",
"provider": "poe-web"
},
"pol": {
"className": "PollinationsExecutor",
"configSource": "pollinations",
"provider": "pollinations"
},
"pollinations": {
"className": "PollinationsExecutor",
"configSource": "pollinations",
"provider": "pollinations"
},
"pplx-web": {
"className": "PerplexityWebExecutor",
"configSource": "<custom-config>",
"provider": "perplexity-web"
},
"pql": {
"className": "PromptQlExecutor",
"configSource": "<custom-config>",
"provider": "promptql"
},
"promptql": {
"className": "PromptQlExecutor",
"configSource": "<custom-config>",
"provider": "promptql"
},
"qoder": {
"className": "QoderExecutor",
"configSource": "qoder",
"provider": "qoder"
},
"qw": {
"className": "QwenWebExecutor",
"configSource": "<custom-config>",
"provider": "qwen-web"
},
"qwen-web": {
"className": "QwenWebExecutor",
"configSource": "<custom-config>",
"provider": "qwen-web"
},
"raycast": {
"className": "RaycastExecutor",
"configSource": "raycast",
"provider": "raycast"
},
"rc": {
"className": "RaycastExecutor",
"configSource": "raycast",
"provider": "raycast"
},
"t3-web": {
"className": "T3ChatWebExecutor",
"configSource": "<custom-config>",
"provider": "t3-web"
},
"t3chat": {
"className": "T3ChatWebExecutor",
"configSource": "<custom-config>",
"provider": "t3-web"
},
"tasw": {
"className": "TencentAIStudioWebExecutor",
"configSource": "<custom-config>",
"provider": "tencent-aistudio-web"
},
"tcw": {
"className": "TinyCmsExecutor",
"configSource": "<custom-config>",
"provider": "tinycms-web"
},
"tencent-aistudio-web": {
"className": "TencentAIStudioWebExecutor",
"configSource": "<custom-config>",
"provider": "tencent-aistudio-web"
},
"theoldllm": {
"className": "TheOldLlmExecutor",
"configSource": "<custom-config>",
"provider": "theoldllm"
},
"tinycms-web": {
"className": "TinyCmsExecutor",
"configSource": "<custom-config>",
"provider": "tinycms-web"
},
"tllm": {
"className": "TheOldLlmExecutor",
"configSource": "<custom-config>",
"provider": "theoldllm"
},
"trae": {
"className": "TraeExecutor",
"configSource": "trae",
"provider": "trae"
},
"v0": {
"className": "V0VercelWebExecutor",
"configSource": "<custom-config>",
"provider": "v0-vercel-web"
},
"v0-vercel-web": {
"className": "V0VercelWebExecutor",
"configSource": "<custom-config>",
"provider": "v0-vercel-web"
},
"ven": {
"className": "VeniceWebExecutor",
"configSource": "<custom-config>",
"provider": "venice-web"
},
"venice-web": {
"className": "VeniceWebExecutor",
"configSource": "<custom-config>",
"provider": "venice-web"
},
"veo-free": {
"className": "VeoAIFreeWebExecutor",
"configSource": "<custom-config>",
"provider": "veoaifree-web"
},
"veoaifree-web": {
"className": "VeoAIFreeWebExecutor",
"configSource": "<custom-config>",
"provider": "veoaifree-web"
},
"vertex": {
"className": "VertexExecutor",
"configSource": "vertex",
"provider": "vertex"
},
"vertex-partner": {
"className": "VertexExecutor",
"configSource": "vertex",
"provider": "vertex"
},
"xai": {
"className": "XaiExecutor",
"configSource": "xai",
"provider": "xai"
},
"xai-oauth": {
"className": "XaiExecutor",
"configSource": "xai-oauth",
"provider": "xai-oauth"
},
"xao": {
"className": "XaiExecutor",
"configSource": "xai-oauth",
"provider": "xai-oauth"
},
"ybw": {
"className": "YuanbaoWebExecutor",
"configSource": "<custom-config>",
"provider": "yuanbao-web"
},
"yuanbao-web": {
"className": "YuanbaoWebExecutor",
"configSource": "<custom-config>",
"provider": "yuanbao-web"
},
"zai-web": {
"className": "ZaiWebExecutor",
"configSource": "<custom-config>",
"provider": "zai-web"
},
"zc": {
"className": "ZcodeExecutor",
"configSource": "<custom-config>",
"provider": "zcode"
},
"zcode": {
"className": "ZcodeExecutor",
"configSource": "<custom-config>",
"provider": "zcode"
},
"zed-hosted": {
"className": "ZedHostedExecutor",
"configSource": "zed-hosted",
"provider": "zed-hosted"
},
"zenmux-free": {
"className": "ZenmuxFreeExecutor",
"configSource": "<custom-config>",
"provider": "zenmux-free"
},
"zmf": {
"className": "ZenmuxFreeExecutor",
"configSource": "<custom-config>",
"provider": "zenmux-free"
},
"zw": {
"className": "ZaiWebExecutor",
"configSource": "<custom-config>",
"provider": "zai-web"
}
},
"keyCount": 137,
"sharedInstances": []
}

View File

@@ -1,7 +1,7 @@
import { test } from "node:test";
import assert from "node:assert";
import { estimateCompressionTokens } from "../../../open-sse/services/compression/stats.ts";
import { transformAnthropicMessages } from "omniglyph";
import { transformAnthropicMessages, transformOpenAIChatCompletions } from "omniglyph";
const CHARS_PER_TOKEN = 4;
@@ -67,3 +67,33 @@ test("regressão: corpo sem imagem estima o MESMO valor de antes (char-count pur
const expected = Math.ceil(JSON.stringify(plainBody).length / CHARS_PER_TOKEN);
assert.equal(estimateCompressionTokens(plainBody), expected);
});
test("estimateCompressionTokens contabiliza image_url PNG no wire OpenAI", async () => {
const originalBody = {
model: "gpt-5.6",
messages: [
{ role: "system", content: DENSE },
{ role: "user", content: "oi" },
],
};
const encoded = new TextEncoder().encode(JSON.stringify(originalBody));
const result = await transformOpenAIChatCompletions(encoded);
assert.equal(result.info.compressed, true);
const compressedBody = JSON.parse(new TextDecoder().decode(result.body)) as Record<
string,
unknown
>;
assert.ok(JSON.stringify(compressedBody).includes('"type":"image_url"'));
const originalEstimate = estimateCompressionTokens(originalBody);
const compressedEstimate = estimateCompressionTokens(compressedBody);
const naiveEstimate = Math.ceil(JSON.stringify(compressedBody).length / CHARS_PER_TOKEN);
assert.ok(
compressedEstimate < naiveEstimate,
`expected image-aware (${compressedEstimate}) < base64 char estimate (${naiveEstimate})`
);
assert.ok(
compressedEstimate < originalEstimate,
`expected OpenAI image compression (${compressedEstimate}) < original (${originalEstimate})`
);
});

View File

@@ -18,11 +18,17 @@ function claudeBody(): Record<string, unknown> {
messages: [{ role: "user", content: [{ type: "text", text: "oi" }] }],
};
}
const OK = { model: "claude-fable-5", supportsVision: true, providerTransport: "direct" as const };
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,
@@ -82,6 +88,15 @@ test("skip fail-closed: sem supportsVision / transporte agregador / undefined",
}
});
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" });
@@ -110,6 +125,31 @@ test("cache_control do cliente sobrevive byte a byte", async () => {
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);
@@ -147,3 +187,139 @@ test("OpenAI não roda no estágio pré-tradução", async () => {
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());
});

View File

@@ -1,12 +1,27 @@
import { readFileSync } from "node:fs";
import assert from "node:assert/strict";
import { test } from "node:test";
import { resolveOmniGlyphTransport } from "../../../open-sse/services/compression/imageTransportPolicy.ts";
test("chatCore treats both Anthropic providers as direct OmniGlyph transports", () => {
test("chatCore uses the measured Anthropic byte-preserving transport policy", () => {
const chatCore = readFileSync("open-sse/handlers/chatCore.ts", "utf8");
assert.match(
chatCore,
/providerTransport:\s*provider === "anthropic" \|\| provider === "claude"[\s\S]{0,80}?"direct"/
);
assert.match(chatCore, /resolveOmniGlyphTransport\(provider\)/);
const translationIndex = chatCore.indexOf("translatedBody = translateRequest(");
const postCompressionIndex = chatCore.indexOf("if (runPostTranslationCompression");
assert.ok(translationIndex >= 0, "chatCore deve manter a tradução explícita");
assert.ok(postCompressionIndex > translationIndex, "OmniGlyph target-wire roda após tradução");
assert.match(chatCore, /compressionStage: "post-translation"/);
assert.deepEqual(resolveOmniGlyphTransport("anthropic"), {
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
});
assert.deepEqual(resolveOmniGlyphTransport("claude"), {
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
});
assert.deepEqual(resolveOmniGlyphTransport("openai"), {
providerTransport: "aggregator",
imageTransportFidelity: "unknown",
});
});

View File

@@ -6,6 +6,7 @@ test("pacote omniglyph exporta a API que o adapter consome", async () => {
assert.equal(typeof mod.transformAnthropicMessages, "function");
assert.equal(typeof mod.transformOpenAIChatCompletions, "function");
assert.equal(typeof mod.transformOpenAIResponses, "function");
assert.equal(typeof mod.transformRequest, "function");
assert.equal(typeof mod.isOmniGlyphSupportedModel, "function");
assert.equal(typeof mod.isOmniGlyphSupportedGptModel, "function");
assert.equal(mod.isOmniGlyphSupportedModel("claude-fable-5"), true);
@@ -14,3 +15,30 @@ test("pacote omniglyph exporta a API que o adapter consome", async () => {
const applicability = await import("omniglyph/applicability");
assert.equal(typeof applicability.isModelImageable, "function");
});
// Superfícies introduzidas no 1.4.0. Sem esta asserção, uma remoção upstream só
// apareceria em runtime — o adapter importa esses símbolos diretamente.
test("omniglyph 1.4.0 exporta escopo de segurança, perfis e accounting", async () => {
const mod = await import("omniglyph");
// Gate de modelo por escopo explícito (não pela env do processo).
assert.equal(typeof mod.isOmniGlyphSupportedModelForScope, "function");
assert.equal(mod.isOmniGlyphSupportedModelForScope("claude-fable-5", "coding-safe"), true);
assert.equal(mod.isOmniGlyphSupportedModelForScope("claude-sonnet-5", "coding-safe"), false);
assert.equal(
mod.isOmniGlyphSupportedModelForScope("claude-fable-5", "passthrough"),
false,
"passthrough não habilita modelo nenhum"
);
// Perfis semânticos.
assert.equal(typeof mod.resolveCompressionProfile, "function");
assert.equal(typeof mod.mergeCompressionProfileOptions, "function");
assert.equal(typeof mod.shouldKeepToolResultSharp, "function");
assert.equal(mod.resolveCompressionProfile("coding-safe").name, "coding-safe");
assert.throws(() => mod.resolveCompressionProfile("nao-existe"));
// Contabilidade física normalizada.
assert.equal(typeof mod.normalizeAccounting, "function");
assert.equal(typeof mod.providerActualInputTokens, "function");
});

View File

@@ -18,6 +18,20 @@ const body = () => ({
messages: [{ role: "user", content: [{ type: "text", text: "oi" }] }],
});
const openaiBody = () => ({
model: "gpt-5.6",
messages: [
{ role: "system", content: DENSE },
{ role: "user", content: "oi" },
],
});
const responsesBody = () => ({
model: "gpt-5.6",
instructions: DENSE,
input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "oi" }] }],
});
// Agora que `estimateCompressionTokens` (stats.ts) é image-aware (Task 6), o guard
// honesto de inflação agregada do stacked (`guardPipelineInflation` em
// pipelineGuards.ts) não reverte mais a saída imageada do omniglyph: o estimador
@@ -30,6 +44,7 @@ test("stacked com step omniglyph recebe providerTransport (engine roda, não é
model: "claude-fable-5",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
config: { stackedPipeline: [{ engine: "rtk" }, { engine: "omniglyph" }] } as never,
});
const omniglyphStep = r.stats?.engineBreakdown?.find((e) => e.engine === "omniglyph");
@@ -59,3 +74,122 @@ test("stacked sem providerTransport 'direct' pula omniglyph (transport_not_direc
assert.ok(omniglyphStep, "omniglyph step deveria aparecer no engineBreakdown mesmo pulado");
assert.ok(omniglyphStep!.techniquesUsed.includes("skip:transport_not_direct"));
});
test("stacked pós-tradução preserva o wire OpenAI Chat e executa OmniGlyph nativo", async () => {
registerBuiltinCompressionEngines();
const r = await applyCompressionAsync(openaiBody(), "stacked", {
model: "gpt-5.6",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
sourceFormat: "openai",
targetFormat: "openai",
compressionStage: "post-translation",
config: { stackedPipeline: [{ engine: "rtk" }, { engine: "omniglyph" }] } as never,
});
const omniglyphStep = r.stats?.engineBreakdown?.find((e) => e.engine === "omniglyph");
assert.ok(omniglyphStep);
assert.ok(omniglyphStep!.techniquesUsed.includes("omniglyph:context-as-image"));
assert.equal(r.compressed, true);
assert.ok(JSON.stringify(r.body).includes('"type":"image_url"'));
assert.ok(
r.stats?.validationWarnings?.some((warning) => warning.includes("rtk: skipped (stage")),
"engines sem suporte ao estágio devem ser explicitamente pulados"
);
});
test("stacked pós-tradução não adapta input[] Responses para messages[] antes do OmniGlyph", async () => {
registerBuiltinCompressionEngines();
const r = await applyCompressionAsync(responsesBody(), "stacked", {
model: "gpt-5.6",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
sourceFormat: "openai-responses",
targetFormat: "openai-responses",
compressionStage: "post-translation",
config: { stackedPipeline: [{ engine: "omniglyph" }] } as never,
});
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→Claude usa o wire traduzido sem uma segunda tradução", async () => {
registerBuiltinCompressionEngines();
const translatedClaudeBody = body();
const r = await applyCompressionAsync(translatedClaudeBody, "omniglyph", {
model: "claude-fable-5",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
sourceFormat: "openai",
targetFormat: "claude",
compressionStage: "post-translation",
});
assert.equal(r.compressed, true);
assert.ok(JSON.stringify(r.body).includes('"type":"image"'));
assert.ok(!JSON.stringify(r.body).includes('"type":"image_url"'));
});
test("Claude→OpenAI aguarda o wire alvo e não imageia o corpo fonte", async () => {
registerBuiltinCompressionEngines();
const pre = await applyCompressionAsync(body(), "omniglyph", {
model: "claude-fable-5",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
sourceFormat: "claude",
targetFormat: "openai",
compressionStage: "pre-translation",
});
assert.equal(pre.compressed, false);
assert.ok(pre.stats?.techniquesUsed.includes("skip:requires_post_translation"));
const post = await applyCompressionAsync(
{
model: "gpt-5.6",
messages: [
{ role: "system", content: DENSE },
{ role: "user", content: "oi" },
],
},
"omniglyph",
{
model: "gpt-5.6",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
sourceFormat: "claude",
targetFormat: "openai",
compressionStage: "post-translation",
}
);
assert.equal(post.compressed, true);
assert.ok(JSON.stringify(post.body).includes('"type":"image_url"'));
});
// O `provider` é threaded explicitamente por cada camada do selector (não é um
// spread cego), então uma camada nova pode derrubá-lo em silêncio: a
// contabilidade cairia para `unknown` e passaria a recusar a semântica de cache
// sem nenhum erro aparecer.
test("provider chega do selector até a contabilidade da engine", async () => {
registerBuiltinCompressionEngines();
const r = await applyCompressionAsync(body(), "stacked", {
model: "claude-fable-5",
provider: "anthropic",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
config: { stackedPipeline: [{ engine: "omniglyph" }] } as never,
});
assert.equal(r.compressed, true);
const omniglyphStep = r.stats?.engineBreakdown?.find((e) => e.engine === "omniglyph");
assert.ok(omniglyphStep, "omniglyph step deveria aparecer no engineBreakdown");
assert.equal(
omniglyphStep!.omniglyph?.provider,
"anthropic",
"sem o provider a contabilidade cai para unknown e recusa a semântica de cache"
);
assert.equal(omniglyphStep!.omniglyph?.savings.evidence, "bytes-only");
});

View File

@@ -0,0 +1,83 @@
/**
* Perfil semântico do OmniGlyph (pacote 1.4.0) — persistência ponta a ponta.
*
* Cobre:
* 1. compressionSettingsUpdateSchema aceita omniglyph:{profile} e RECUSA nome inválido
* 2. updateCompressionSettings / getCompressionSettings fazem round-trip do perfil
* 3. o default persistido é `aggressive` (a política que os recibos mediram)
* 4. um perfil desconhecido vindo do storage cai para o default, não vaza adiante
*/
import { describe, it, beforeEach, afterEach, after } from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { compressionSettingsUpdateSchema } from "../../../src/shared/validation/compressionConfigSchemas.ts";
import { DEFAULT_OMNIGLYPH_CONFIG } from "../../../open-sse/services/compression/types.ts";
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-omniglyph-profile-"));
const ORIGINAL_DATA_DIR = process.env.DATA_DIR;
process.env.DATA_DIR = TEST_DATA_DIR;
const core = await import("../../../src/lib/db/core.ts");
const { getCompressionSettings, updateCompressionSettings } = await import(
"../../../src/lib/db/compression.ts"
);
beforeEach(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
fs.mkdirSync(TEST_DATA_DIR, { recursive: true });
});
afterEach(() => {
core.resetDbInstance();
});
after(() => {
core.resetDbInstance();
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
if (ORIGINAL_DATA_DIR === undefined) delete process.env.DATA_DIR;
else process.env.DATA_DIR = ORIGINAL_DATA_DIR;
});
describe("omniglyph profile config", () => {
it("o schema aceita os quatro perfis e recusa qualquer outro nome", () => {
for (const profile of ["coding-safe", "balanced", "aggressive", "passthrough"]) {
const parsed = compressionSettingsUpdateSchema.safeParse({ omniglyph: { profile } });
assert.equal(parsed.success, true, `perfil válido recusado: ${profile}`);
}
// Um nome inválido tem de morrer no schema. Se passar, o adapter ainda falha
// fechado (skip:invalid_profile), mas o operador veria a engine desligada
// sem nenhum erro na tela de configuração.
assert.equal(
compressionSettingsUpdateSchema.safeParse({ omniglyph: { profile: "turbo-max" } }).success,
false
);
assert.equal(
compressionSettingsUpdateSchema.safeParse({ omniglyph: { profile: "" } }).success,
false
);
});
it("o default é aggressive — a política que os recibos publicados mediram", async () => {
assert.equal(DEFAULT_OMNIGLYPH_CONFIG.profile, "aggressive");
assert.equal((await getCompressionSettings()).omniglyph?.profile, "aggressive");
});
it("round-trip do perfil escolhido pelo operador", async () => {
await updateCompressionSettings({ omniglyph: { profile: "coding-safe" } });
assert.equal((await getCompressionSettings()).omniglyph?.profile, "coding-safe");
await updateCompressionSettings({ omniglyph: { profile: "passthrough" } });
assert.equal((await getCompressionSettings()).omniglyph?.profile, "passthrough");
});
it("perfil desconhecido no storage cai para o default em vez de vazar adiante", async () => {
await updateCompressionSettings({ omniglyph: { profile: "coding-safe" } });
// Simula uma linha gravada por uma versão futura/adulterada, contornando o schema.
await updateCompressionSettings({ omniglyph: { profile: "turbo-max" } } as never);
assert.equal((await getCompressionSettings()).omniglyph?.profile, "aggressive");
});
});

View File

@@ -3,8 +3,13 @@ import assert from "node:assert";
import { applyCompressionAsync } from "../../../open-sse/services/compression/strategySelector.ts";
import { registerBuiltinCompressionEngines } from "../../../open-sse/services/compression/engines/index.ts";
const DENSE = "X".repeat(500) + "\n" +
Array.from({ length: 400 }, (_, i) => `const row_${i} = compute(${i * 17}, "${"v".repeat(80)}");`).join("\n");
const DENSE =
"X".repeat(500) +
"\n" +
Array.from(
{ length: 400 },
(_, i) => `const row_${i} = compute(${i * 17}, "${"v".repeat(80)}");`
).join("\n");
const body = () => ({
model: "claude-fable-5",
max_tokens: 128,
@@ -18,6 +23,7 @@ test("modo omniglyph sozinho comprime (selecionar o modo é o enable)", async ()
model: "claude-fable-5",
supportsVision: true,
providerTransport: "direct",
imageTransportFidelity: "byte-preserving",
});
assert.equal(r.compressed, true);
assert.ok(JSON.stringify(r.body).includes('"type":"image"'));

View File

@@ -0,0 +1,121 @@
import { test } from "node:test";
import assert from "node:assert";
import { omniglyphEngine } from "../../../open-sse/services/compression/engines/omniglyphAdapter.ts";
// O OmniGlyph 1.4.0 expõe `normalizeAccounting()`, que classifica o GRAU DE
// EVIDÊNCIA da economia (provider-reported / estimated / bytes-only /
// unavailable) e resolve a semântica de cache por provider — Anthropic usa
// buckets disjuntos, OpenAI/xAI reportam cached como subconjunto do input.
// Somar à mão dá double-count. Antes disso o adapter descartava tudo e a UI
// exibia um número sem dizer de onde ele veio.
const SEGREDO = "sk-ant-api03-SEGREDO-QUE-NAO-PODE-VAZAR-NA-TELEMETRIA";
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}\nAPI_KEY=${SEGREDO}\ncwd=/home/operador/projeto-secreto`,
messages: [{ role: "user", content: [{ type: "text", text: "oi" }] }],
};
}
const OK = {
model: "claude-fable-5",
provider: "anthropic",
supportsVision: true,
providerTransport: "direct" as const,
imageTransportFidelity: "byte-preserving" as const,
};
test("stats do omniglyph carregam a contabilidade normalizada com grau de evidência", async () => {
const r = await omniglyphEngine.applyAsync!(claudeBody(), OK as never);
assert.equal(r.compressed, true);
const accounting = r.stats?.omniglyph;
assert.ok(accounting, "compressão aplicada deve registrar a contabilidade");
assert.equal(accounting.provider, "anthropic");
assert.ok(
["provider-reported", "estimated", "bytes-only", "unavailable"].includes(
accounting.savings.evidence
),
`evidência inesperada: ${accounting.savings.evidence}`
);
// Sem contadores do provider nesta etapa, a base honesta é o tamanho do corpo.
assert.equal(accounting.savings.evidence, "bytes-only");
assert.ok(typeof accounting.bytes.original === "number" && accounting.bytes.original > 0);
assert.ok(typeof accounting.bytes.transformed === "number");
assert.ok(typeof accounting.images.count === "number" && accounting.images.count > 0);
assert.ok(typeof accounting.images.bytes === "number" && accounting.images.bytes > 0);
});
test("telemetria não carrega conteúdo: nem base64, nem prompt, nem segredo, nem ambiente", async () => {
const r = await omniglyphEngine.applyAsync!(claudeBody(), OK as never);
assert.equal(r.compressed, true);
const serialized = JSON.stringify(r.stats);
// Valores do request.
assert.ok(!serialized.includes(SEGREDO), "segredo do system vazou na telemetria");
assert.ok(!serialized.includes("projeto-secreto"), "caminho do operador vazou");
assert.ok(!serialized.includes("const row_0 = compute"), "texto do system vazou");
assert.ok(!serialized.includes("data:image/png;base64"), "data URL de imagem vazou");
assert.ok(!serialized.includes("iVBORw0KGgo"), "cabeçalho PNG em base64 vazou");
// Chaves do TransformInfo que carregam conteúdo, hash de conteúdo ou ambiente.
for (const proibida of [
"imageSourceText",
"imageSourceTexts",
"recoverable",
"systemSha8",
"claudeMdSha8",
"firstUserSha8",
"unknownStaticTags",
"churningStaticTags",
'"env"',
]) {
assert.ok(!serialized.includes(proibida), `campo proibido na telemetria: ${proibida}`);
}
// A allowlist é positiva: todo valor da contabilidade é número, string de enum
// conhecida, ou objeto desses. Nada de texto livre vindo do request.
const accounting = r.stats?.omniglyph;
assert.ok(accounting);
const enums = new Set([
"anthropic",
"openai",
"xai",
"unknown",
"provider-reported",
"estimated",
"bytes-only",
"unavailable",
"claude-fable-5",
]);
const walk = (value: unknown, path: string): void => {
if (value === undefined || value === null || typeof value === "number") return;
if (typeof value === "string") {
assert.ok(enums.has(value), `string fora da allowlist em ${path}: ${value}`);
return;
}
assert.equal(typeof value, "object", `tipo inesperado em ${path}`);
for (const [k, v] of Object.entries(value as Record<string, unknown>)) walk(v, `${path}.${k}`);
};
walk(accounting, "omniglyph");
});
test("skip não inventa contabilidade", async () => {
const r = await omniglyphEngine.applyAsync!(claudeBody(), {
...OK,
imageTransportFidelity: "unknown",
} as never);
assert.equal(r.compressed, false);
assert.equal(r.stats?.omniglyph, undefined);
});

View File

@@ -1,134 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// R0.3 GOLDEN LOCK (characterization BEFORE the ExecutorRegistry refactor):
// freeze the full provider-id → executor mapping of open-sse/executors/index.ts —
// every specialized key with its executor class, effective provider identity and
// which PROVIDERS config entry backs it — plus the getExecutor() dispatch rules
// (specialized hit, DefaultExecutor fallback + cache, cloud-agent guard #6699,
// search-provider guard #10274). The registry refactor must keep this snapshot
// byte-identical: any drift in keys, classes, provider identity or guard behavior
// is a golden diff, not a silent routing change.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-executor-golden-"));
process.env.DATA_DIR = TEST_DATA_DIR;
// Dynamic imports AFTER DATA_DIR is set so db/core.ts picks up the temp path.
const { getExecutor, hasSpecializedExecutor, DefaultExecutor } = await import(
"../../open-sse/executors/index.ts"
);
const { PROVIDERS } = await import("../../open-sse/config/constants.ts");
const { SEARCH_PROVIDERS } = await import("../../open-sse/config/searchRegistry.ts");
const { goldenSnapshot } = await import("../helpers/goldenSnapshot.ts");
test.after(() => {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
// The specialized keys are not exported; enumerate them through the public
// surface by probing every plausible id source AND the literal keys read from
// the module source. Reading the source keeps the golden honest: a key added
// to (or removed from) the hard-coded map cannot hide from the snapshot.
function readSpecializedKeys(): string[] {
const src = fs.readFileSync(
path.resolve(path.dirname(new URL(import.meta.url).pathname), "../../open-sse/executors/index.ts"),
"utf8"
);
const mapMatch = src.match(/const executors = \{([\s\S]*?)\n\};/);
assert.ok(mapMatch, "executors map literal not found in open-sse/executors/index.ts");
const keys: string[] = [];
for (const line of mapMatch[1].split("\n")) {
const m = line.match(/^\s*(?:"([^"]+)"|([A-Za-z0-9_$-]+)):\s*new /);
if (m) keys.push(m[1] ?? m[2]);
}
return keys;
}
// Map a ProviderConfig object back to its PROVIDERS key by identity, so the
// snapshot records WHICH config backs each executor without freezing the whole
// (huge, frequently-edited) config content.
const providerConfigKeyByRef = new Map<object, string>();
for (const [key, cfg] of Object.entries(PROVIDERS)) {
if (cfg && typeof cfg === "object" && !providerConfigKeyByRef.has(cfg)) {
providerConfigKeyByRef.set(cfg, key);
}
}
function describeExecutor(instance: unknown): {
className: string;
provider: string | null;
configSource: string | null;
} {
const inst = instance as { constructor: { name: string }; provider?: string; config?: object };
const cfg = inst.config;
return {
className: inst.constructor.name,
provider: typeof inst.provider === "string" ? inst.provider : null,
configSource:
cfg == null ? null : (providerConfigKeyByRef.get(cfg) ?? "<custom-config>"),
};
}
const specializedKeys = readSpecializedKeys();
test("golden: specialized executor map — key → class + provider identity + config source", () => {
assert.ok(specializedKeys.length >= 100, `suspiciously few keys: ${specializedKeys.length}`);
const entries: Record<
string,
{ className: string; provider: string | null; configSource: string | null }
> = {};
const byInstance = new Map<unknown, string[]>();
for (const key of [...specializedKeys].sort()) {
assert.equal(hasSpecializedExecutor(key), true, `hasSpecializedExecutor(${key})`);
const instance = getExecutor(key);
entries[key] = describeExecutor(instance);
const group = byInstance.get(instance) ?? [];
group.push(key);
byInstance.set(instance, group);
}
// Keys sharing the SAME instance share per-instance state (session pools,
// rotation cooldowns); today every map entry is its own `new X()`. Freeze that.
const sharedInstances = [...byInstance.values()]
.filter((keys) => keys.length > 1)
.map((keys) => keys.sort())
.sort((a, b) => a[0].localeCompare(b[0]));
goldenSnapshot("executors/executor-map", {
keyCount: specializedKeys.length,
entries,
sharedInstances,
});
});
test("golden: getExecutor dispatch rules — fallback, cache and 400-guards", () => {
// 1. Unknown provider → DefaultExecutor for that provider, memoized.
const unknown = "golden-test-unknown-provider";
assert.equal(hasSpecializedExecutor(unknown), false);
const fallback = getExecutor(unknown);
assert.ok(fallback instanceof DefaultExecutor, "fallback must be DefaultExecutor");
assert.equal(getExecutor(unknown), fallback, "DefaultExecutor fallback must be cached");
// 2. Cloud-agent guard (#6699) and search guard (#10274) → status-400 throw.
const guardOutcome = (provider: string) => {
try {
getExecutor(provider);
return { throws: false as const };
} catch (err) {
const e = err as Error & { status?: number };
return { throws: true as const, status: e.status ?? null, message: e.message };
}
};
const searchProviders = Object.keys(SEARCH_PROVIDERS).sort();
goldenSnapshot("executors/dispatch-rules", {
fallback: describeExecutor(fallback),
cloudAgentGuard: { jules: guardOutcome("jules") },
searchGuard: Object.fromEntries(searchProviders.map((p) => [p, guardOutcome(p)])),
});
});

View File

@@ -1,57 +0,0 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
// R0.3 — unit tests for the ExecutorRegistry seam itself (registration
// semantics + wiring of the built-ins). Behavior parity of the full map is
// covered separately by tests/unit/executor-map-golden.test.ts.
const TEST_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), "omniroute-executor-registry-"));
process.env.DATA_DIR = TEST_DATA_DIR;
const { registerExecutor, getRegisteredExecutor, hasRegisteredExecutor, listExecutorAliases } =
await import("../../open-sse/executors/registry.ts");
const { getExecutor, hasSpecializedExecutor, BaseExecutor, DefaultExecutor } = await import(
"../../open-sse/executors/index.ts"
);
test.after(() => {
fs.rmSync(TEST_DATA_DIR, { recursive: true, force: true });
});
test("built-ins are registered at module load and resolve through the registry", () => {
const aliases = listExecutorAliases();
assert.ok(aliases.length >= 100, `expected the built-in table, got ${aliases.length} aliases`);
for (const alias of ["antigravity", "kiro", "glm", "9router", "conol-web"]) {
assert.ok(hasRegisteredExecutor(alias), `missing built-in: ${alias}`);
assert.equal(getExecutor(alias), getRegisteredExecutor(alias));
assert.ok(getExecutor(alias) instanceof BaseExecutor);
}
});
test("registerExecutor throws on duplicate alias", () => {
assert.throws(() => registerExecutor("kiro", getRegisteredExecutor("kiro")!), {
message: /already registered: "kiro"/,
});
});
test("registering a new alias makes it resolvable via getExecutor and hasSpecializedExecutor", () => {
const alias = "registry-test-provider";
assert.equal(hasSpecializedExecutor(alias), false);
const instance = new DefaultExecutor(alias);
registerExecutor(alias, instance);
assert.equal(hasSpecializedExecutor(alias), true);
assert.equal(getExecutor(alias), instance);
});
test("registry lookup is exact — Object.prototype names are not executors", () => {
// The old object-literal lookup (`executors[provider]`) leaked prototype
// members: getExecutor("constructor") returned Object's constructor. The Map
// registry must treat these as unknown providers (DefaultExecutor fallback).
for (const name of ["constructor", "toString", "hasOwnProperty", "__proto__"]) {
assert.equal(hasSpecializedExecutor(name), false, name);
assert.ok(getExecutor(name) instanceof DefaultExecutor, name);
}
});

View File

@@ -108,7 +108,11 @@ describe("OmniglyphContextPage", () => {
expect(img!.getAttribute("src")).toMatch(/^data:image\/png;base64,/);
// Gates
expect(text).toContain("claude-fable-5");
expect(text).toContain("direct Anthropic");
// A cópia do gate deixou de dizer "direct Anthropic" quando os wires OpenAI
// nativos entraram: transporte direto é condição de TODO provider, e o que
// restringe a rota ao Anthropic é o recibo de fidelidade de bytes, não o
// rótulo do transporte.
expect(text).toContain("direct provider");
// Config control
expect(container.querySelector('[data-testid="omniglyph-enable-toggle"]')).toBeTruthy();
});
@@ -138,4 +142,66 @@ describe("OmniglyphContextPage", () => {
expect(engines.rtk?.enabled).toBe(true);
expect(engines.caveman?.enabled).toBe(false);
});
it("carrega o perfil salvo e faz PATCH só do perfil, sem reescrever o mapa de engines", async () => {
const puts: CapturedPut[] = [];
const json = (body: unknown, status = 200) =>
new Response(JSON.stringify(body), {
status,
headers: { "Content-Type": "application/json" },
});
const stored = {
enabled: true,
engines: { rtk: { enabled: true, level: "standard" } },
omniglyph: { profile: "coding-safe" },
};
vi.spyOn(globalThis, "fetch").mockImplementation(
async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input.toString();
const method = (init?.method ?? "GET").toUpperCase();
if (url.includes("/api/settings/compression")) {
if (method === "PUT") {
puts.push({ url, body: JSON.parse(String(init?.body ?? "{}")) });
return json(stored);
}
return json(stored);
}
return json({}, 404);
}
);
const { default: Page } = await import(
"../../../src/app/(dashboard)/dashboard/context/omniglyph/OmniglyphContextPageClient"
);
let container!: HTMLElement;
await act(async () => {
container = mount(<Page />);
});
await flush();
const select = container.querySelector(
'[data-testid="omniglyph-profile-select"]'
) as HTMLSelectElement | null;
expect(select, "o seletor de perfil deve existir").toBeTruthy();
expect(select!.value, "o perfil salvo tem de vir selecionado").toBe("coding-safe");
// Os quatro perfis do pacote, com aggressive como primeiro (default).
expect(Array.from(select!.options).map((o) => o.value)).toEqual([
"aggressive",
"balanced",
"coding-safe",
"passthrough",
]);
await act(async () => {
select!.value = "passthrough";
select!.dispatchEvent(new Event("change", { bubbles: true }));
});
await flush();
expect(puts.length).toBe(1);
expect(puts[0]!.body).toEqual({ omniglyph: { profile: "passthrough" } });
// O perfil vive fora do mapa `engines`: mandá-lo junto reescreveria o mapa inteiro.
expect(puts[0]!.body.engines).toBeUndefined();
});
});

View File

@@ -88,7 +88,6 @@ export default defineConfig({
"src/app/(dashboard)/dashboard/endpoint/__tests__/ApiEndpointsTab.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed
"tests/unit/ui/compression-combos-routing-mode-6760.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed
"tests/unit/ui/use-local-storage-pool-migration.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed
"tests/unit/ui/omniglyphContextPage.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed
"tests/unit/ui/waterfallInspector.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed
"tests/unit/ui/playground-compare-column.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed
"tests/unit/ui/playground-chat-tab.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed