Files
OmniRoute/tests/unit/vision-bridge-native-skip.test.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

113 lines
3.8 KiB
TypeScript

/**
* Explicit guard for the "target model already supports vision natively" skip
* path (openclaw `runner.ts:711` prompted this — OmniRoute already relied on
* the behavior implicitly, this test makes the contract explicit and asserts
* the dedicated skip log).
*
* Follows the DI harness pattern from `vision-bridge-cc-no-reroute.test.ts`:
* settings/vision-call/combo-mapping are all injected, so this exercises
* `VisionBridgeGuardrail.preCall` without going through any real network call.
*/
import test from "node:test";
import assert from "node:assert/strict";
const { VisionBridgeGuardrail } = await import("../../src/lib/guardrails/visionBridge.ts");
import type { GuardrailContext } from "../../src/lib/guardrails/base.ts";
import type { VisionModelConfig } from "../../src/lib/guardrails/visionBridgeHelpers.ts";
// Known registry model with supportsVision: true (see
// vision-bridge-cc-no-reroute.test.ts CC-VB-SANITY).
const VISION_CAPABLE_MODEL = "command-code/gpt-5.5";
function imagePayload(model: string): Record<string, unknown> {
return {
model,
messages: [
{
role: "user",
content: [
{ type: "text", text: "What is in this image?" },
{
type: "image_url",
image_url: { url: "https://example.com/image.png" },
},
],
},
],
};
}
/** Records every (level, category, message) call so the test can assert on it. */
class LogSpy {
calls: Array<{ level: string; category: string; message: string }> = [];
private record(level: string) {
return (category: string, message: string) => {
this.calls.push({ level, category, message });
};
}
debug = this.record("debug");
info = this.record("info");
warn = this.record("warn");
error = this.record("error");
}
test("native-vision skip: messages untouched, zero vision calls, dedicated skip log", async () => {
let visionCallCount = 0;
const guardrail = new VisionBridgeGuardrail({
deps: {
getSettings: async () => ({
visionBridgeEnabled: true,
visionBridgeModel: "openai/gpt-4o-mini",
}),
callVisionModel: async (_imageDataUri: string, _config: VisionModelConfig) => {
visionCallCount++;
return "should never be produced";
},
// No `checkModelHasComboMapping` override: let the real (DB-backed)
// combo lookup run, which resolves to "not-combo" for a plain model
// string that is neither a combo name nor combo-mapped — exactly the
// path that must hit the native-vision skip + log.
},
});
const originalPayload = imagePayload(VISION_CAPABLE_MODEL);
const payloadSnapshot = JSON.parse(JSON.stringify(originalPayload));
const logSpy = new LogSpy();
const context: GuardrailContext = {
model: VISION_CAPABLE_MODEL,
log: logSpy as unknown as GuardrailContext["log"],
};
const result = await guardrail.preCall(originalPayload, context);
// (a) messages intact — guardrail must not modify the payload at all.
assert.strictEqual(result.block, false);
assert.strictEqual(
result.modifiedPayload,
undefined,
"native-vision skip must not rewrite payload"
);
assert.deepStrictEqual(
originalPayload,
payloadSnapshot,
"native-vision skip must not mutate the original messages"
);
// (b) zero calls to the vision (describe) model.
assert.strictEqual(
visionCallCount,
0,
"must not call the vision model when target has native vision"
);
// (c) dedicated skip log emitted.
const skipLog = logSpy.calls.find((c) =>
c.message.includes("Skipping: target model supports vision natively")
);
assert.ok(
skipLog,
`expected a skip log containing "Skipping: target model supports vision natively", got: ${JSON.stringify(logSpy.calls)}`
);
assert.equal(skipLog?.category, "VISION_BRIDGE");
});