Files
OmniRoute/tests/unit/modality-bridge-cache.test.ts
Diego Rodrigues de Sa e Souza 71c85f31cd feat(guardrails): modality bridge core — vision mode/task-aware/cache/input_image + modalityBridge settings (#9759)
* feat(sse): unified media-part detection helper (image+audio, input_image)

* refactor(guardrails): extractImageParts/comboStructure delegate to unified media detector

* fix(sse): media detector — audio parts no longer shadow sibling/nested image indicators

* fix(guardrails): close extract↔replace contract for input_image (allowlist + splice)

* perf(guardrails): skip media traversal when bridge disabled; short-circuit combo image check

* feat(guardrails): in-memory LRU bridge cache (sha256 keyed)

* feat(settings): modalityBridge* schema with legacy visionBridge* fallback

* feat(db): migrate visionBridge* settings to modalityBridge* (idempotent)

* refactor(guardrails): harden bridge cache key/config + settings resolution (review minors)

* feat(guardrails): vision bridge mode selector (auto/describe/reroute) short-circuit

* feat(guardrails): task-aware vision description prompt (default on)

* feat(guardrails): describe-path cache integration

* docs(guardrails): review polish — cache-key coupling notes + helper header

* feat(guardrails): in-memory bridge stats + modality-bridge response header

* feat(api): modality bridge stats endpoint + header wiring in chat handler

* docs(guardrails): document modality bridge mode/task-aware/cache/header + stats endpoint

* chore: untrack _tasks symlink (inherited from base tip; blocks pre-commit tracked-artifacts gate)

* fix(db): renumber modality bridge migration 139->140 (base renumbered ccr_blocks to 139)

* docs(guardrails): migration filename touch-up 139->140

* docs(db): stale comment touch-ups after 139->140 renumber and #9688 landing

* fix(db): renumber modality bridge migration 140->141 (base renumbered connection_runtime_state to 140)

* test(db): migration test titles 139->141

---------

Co-authored-by: diegosouzapw <diegosouzapw@users.noreply.github.com>
2026-08-08 01:59:11 -03:00

64 lines
2.3 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert";
import {
BridgeCache,
bridgeCacheKey,
getSharedBridgeCacheFor,
} from "../../src/lib/guardrails/modalityBridge/bridgeCache.ts";
import { resolveVisionBridgeRuntimeSettings } from "../../src/shared/constants/modalityBridgeDefaults.ts";
test("key is stable sha256 of content+prompt+model", () => {
const a = bridgeCacheKey("data:image/png;base64,AAA", "describe", "gpt-4o-mini");
const b = bridgeCacheKey("data:image/png;base64,AAA", "describe", "gpt-4o-mini");
assert.equal(a, b);
assert.match(a, /^[a-f0-9]{64}$/);
assert.notEqual(a, bridgeCacheKey("data:image/png;base64,AAA", "other", "gpt-4o-mini"));
});
test("key framing prevents boundary-shift collisions between fields", () => {
// Without length-prefix framing ("ab","c") and ("a","bc") would hash the
// same concatenated bytes.
assert.notEqual(bridgeCacheKey("ab", "c", "m"), bridgeCacheKey("a", "bc", "m"));
assert.notEqual(bridgeCacheKey("x", "yz", "m"), bridgeCacheKey("x", "y", "zm"));
});
test("get/set roundtrip and TTL expiry", () => {
let now = 1000;
const cache = new BridgeCache({ maxEntries: 10, ttlMs: 500, now: () => now });
cache.set("k1", "desc");
assert.equal(cache.get("k1"), "desc");
now = 1600;
assert.equal(cache.get("k1"), undefined);
});
test("LRU evicts oldest when full", () => {
const cache = new BridgeCache({ maxEntries: 2, ttlMs: 60000, now: () => 0 });
cache.set("a", "1");
cache.set("b", "2");
cache.get("a");
cache.set("c", "3");
assert.equal(cache.get("b"), undefined);
assert.equal(cache.get("a"), "1");
});
test("getSharedBridgeCacheFor reuses the instance for the same config and recreates on change", () => {
const base = resolveVisionBridgeRuntimeSettings({});
const a = getSharedBridgeCacheFor(base);
const b = getSharedBridgeCacheFor({ ...base });
assert.equal(a, b);
const c = getSharedBridgeCacheFor({ ...base, cacheTtlMinutes: base.cacheTtlMinutes + 5 });
assert.notEqual(c, a);
const d = getSharedBridgeCacheFor({ ...base, cacheTtlMinutes: base.cacheTtlMinutes + 5 });
assert.equal(d, c);
const e = getSharedBridgeCacheFor({
...base,
cacheTtlMinutes: base.cacheTtlMinutes + 5,
cacheMaxEntries: base.cacheMaxEntries + 1,
});
assert.notEqual(e, d);
});