mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-12 02:02:13 +03:00
* 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>
97 lines
3.6 KiB
TypeScript
97 lines
3.6 KiB
TypeScript
import { test } from "node:test";
|
|
import assert from "node:assert";
|
|
|
|
import {
|
|
resolveVisionBridgeRuntimeSettings,
|
|
MODALITY_BRIDGE_DEFAULTS,
|
|
} from "../../src/shared/constants/modalityBridgeDefaults.ts";
|
|
import { updateSettingsSchema } from "../../src/shared/validation/settingsSchemas.ts";
|
|
|
|
test("new keys win over legacy keys", () => {
|
|
const s = resolveVisionBridgeRuntimeSettings({
|
|
modalityBridgeVisionEnabled: false,
|
|
visionBridgeEnabled: true,
|
|
modalityBridgeVisionModel: "gemini/gemini-2.5-flash",
|
|
visionBridgeModel: "openai/gpt-4o-mini",
|
|
});
|
|
assert.equal(s.enabled, false);
|
|
assert.equal(s.model, "gemini/gemini-2.5-flash");
|
|
});
|
|
|
|
test("legacy keys used as fallback when new keys absent (rollback 1 ciclo)", () => {
|
|
const s = resolveVisionBridgeRuntimeSettings({
|
|
visionBridgeEnabled: false,
|
|
visionBridgePrompt: "legacy prompt",
|
|
});
|
|
assert.equal(s.enabled, false);
|
|
assert.equal(s.prompt, "legacy prompt");
|
|
});
|
|
|
|
test("defaults: mode auto, taskAware true, cache on", () => {
|
|
const s = resolveVisionBridgeRuntimeSettings({});
|
|
assert.equal(s.mode, "auto");
|
|
assert.equal(s.taskAware, true);
|
|
assert.equal(s.cacheEnabled, true);
|
|
assert.equal(s.cacheTtlMinutes, MODALITY_BRIDGE_DEFAULTS.cacheTtlMinutes);
|
|
});
|
|
|
|
test("wrong-typed stored values are skipped in favor of the next candidate/default", () => {
|
|
const s = resolveVisionBridgeRuntimeSettings({
|
|
modalityBridgeVisionEnabled: "off", // string in a boolean field
|
|
modalityBridgeVisionTimeout: "9000", // string in a number field
|
|
modalityBridgeVisionModel: 42, // number in a string field
|
|
});
|
|
assert.equal(s.enabled, true); // falls through to VISION_BRIDGE_DEFAULTS.enabled
|
|
assert.equal(s.timeoutMs, 30000);
|
|
assert.equal(s.model, "openai/gpt-4o-mini");
|
|
|
|
// A wrong-typed NEW key must still fall through to a well-typed LEGACY key.
|
|
const fallback = resolveVisionBridgeRuntimeSettings({
|
|
modalityBridgeVisionEnabled: "off",
|
|
visionBridgeEnabled: false,
|
|
});
|
|
assert.equal(fallback.enabled, false);
|
|
});
|
|
|
|
test("Modality Bridge settings are accepted by the settings PATCH schema", () => {
|
|
const validation = updateSettingsSchema.safeParse({
|
|
modalityBridgeVisionEnabled: true,
|
|
modalityBridgeVisionMode: "describe",
|
|
modalityBridgeVisionModel: "gemini/gemini-2.5-flash",
|
|
modalityBridgeVisionTaskAware: false,
|
|
modalityBridgeVisionPrompt: "Describe the image contents briefly.",
|
|
modalityBridgeVisionTimeout: 45000,
|
|
modalityBridgeVisionMaxImages: 6,
|
|
modalityBridgeAudioEnabled: true,
|
|
modalityBridgeAudioModel: "openai/gpt-4o-mini-transcribe",
|
|
modalityBridgeAudioTimeout: 60000,
|
|
modalityBridgeAudioMaxClips: 3,
|
|
modalityBridgeCacheEnabled: true,
|
|
modalityBridgeCacheTtlMinutes: 60,
|
|
modalityBridgeCacheMaxEntries: 200,
|
|
});
|
|
|
|
assert.equal(validation.success, true);
|
|
});
|
|
|
|
test("Modality Bridge settings keep numeric bounds enforced (each field individually)", () => {
|
|
const invalidByField: Record<string, number> = {
|
|
modalityBridgeVisionTimeout: 999999,
|
|
modalityBridgeVisionMaxImages: 0,
|
|
modalityBridgeAudioMaxClips: 11,
|
|
modalityBridgeCacheTtlMinutes: 0,
|
|
modalityBridgeCacheMaxEntries: 9,
|
|
};
|
|
for (const [field, value] of Object.entries(invalidByField)) {
|
|
const validation = updateSettingsSchema.safeParse({ [field]: value });
|
|
assert.equal(validation.success, false, `${field}=${value} should be rejected`);
|
|
}
|
|
});
|
|
|
|
test("Modality Bridge vision mode rejects values outside the enum", () => {
|
|
const validation = updateSettingsSchema.safeParse({
|
|
modalityBridgeVisionMode: "invalid-mode",
|
|
});
|
|
assert.equal(validation.success, false);
|
|
});
|