fix(bridge): allow explicit 0 to disable the describe cap

updateSettingsSchema previously rejected modalityBridgeVisionMaxChars: 0
because the field's range was min(100).max(50000), so a dashboard PATCH
sending the explicit "unlimited" sentinel would 400. Widen the schema to
z.union([z.literal(0), z.number().int().min(100).max(50000)]) so 0
validates as its own valid value, not just an implicit default.
This commit is contained in:
Xiangzhe
2026-08-13 17:42:43 -03:00
parent 4fd2cd4de5
commit 6cf1381938
2 changed files with 35 additions and 1 deletions

View File

@@ -349,7 +349,9 @@ export const updateSettingsSchema = z.object({
modalityBridgeVisionPrompt: z.string().max(5000).optional(),
modalityBridgeVisionTimeout: z.number().int().min(1000).max(300000).optional(),
modalityBridgeVisionMaxImages: z.number().int().min(1).max(20).optional(),
modalityBridgeVisionMaxChars: z.number().int().min(100).max(50000).optional(),
modalityBridgeVisionMaxChars: z
.union([z.literal(0), z.number().int().min(100).max(50000)])
.optional(),
modalityBridgeAudioEnabled: z.boolean().optional(),
modalityBridgeAudioModel: z.string().max(200).optional(),
modalityBridgeAudioTimeout: z.number().int().min(1000).max(300000).optional(),

View File

@@ -14,6 +14,7 @@ import assert from "node:assert/strict";
const { VisionBridgeGuardrail } = await import("../../src/lib/guardrails/visionBridge.ts");
const { resolveVisionBridgeRuntimeSettings } =
await import("../../src/shared/constants/modalityBridgeDefaults.ts");
const { updateSettingsSchema } = await import("../../src/shared/validation/settingsSchemas.ts");
import type { GuardrailContext } from "../../src/lib/guardrails/base.ts";
import type { VisionModelConfig } from "../../src/lib/guardrails/visionBridgeHelpers.ts";
@@ -108,3 +109,34 @@ test("resolveVisionBridgeRuntimeSettings({}) defaults maxChars to 0 (no cap)", (
const runtime = resolveVisionBridgeRuntimeSettings({});
assert.equal(runtime.maxChars, 0);
});
test("updateSettingsSchema accepts an explicit modalityBridgeVisionMaxChars: 0 to disable the cap", async () => {
const parsed = updateSettingsSchema.safeParse({ modalityBridgeVisionMaxChars: 0 });
assert.equal(parsed.success, true, "explicit 0 must validate (disables the cap)");
const guardrail = new VisionBridgeGuardrail({
deps: {
getSettings: async () => ({
visionBridgeEnabled: true,
modalityBridgeVisionMaxChars: 0,
}),
callVisionModel: async (_imageDataUri: string, _config: VisionModelConfig) =>
LONG_DESCRIPTION,
},
});
const body = imageBody("maxchars-explicit-zero-test");
const context: GuardrailContext = { model: TEXT_ONLY_MODEL, log: console };
const result = await guardrail.preCall(body, context);
const text = findImageDescriptionText(result.modifiedPayload);
assert.ok(text, "expected a [Image 1]: text part in the modified payload");
const description = text!.slice("[Image 1]: ".length);
assert.equal(description, LONG_DESCRIPTION, "explicit 0 must disable truncation entirely");
assert.ok(!description.endsWith("…"), "explicit 0 must never add an ellipsis");
});
test("updateSettingsSchema rejects a value below the 100 floor that is not the explicit-0 sentinel", () => {
const parsed = updateSettingsSchema.safeParse({ modalityBridgeVisionMaxChars: 50 });
assert.equal(parsed.success, false, "50 is neither the 0 sentinel nor >= 100");
});