mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-11 09:42:15 +03:00
feat(modality-bridge): resolve audio input capability
This commit is contained in:
@@ -50,6 +50,7 @@ export interface RegistryModel {
|
||||
supportsReasoning?: boolean;
|
||||
supportedThinkingEfforts?: readonly string[];
|
||||
supportsVision?: boolean;
|
||||
supportsAudio?: boolean;
|
||||
supportsXHighEffort?: boolean;
|
||||
maxOutputTokens?: number;
|
||||
targetFormat?: string;
|
||||
|
||||
@@ -121,6 +121,7 @@ export interface ResolvedModelCapabilities {
|
||||
supportsThinking: boolean | null;
|
||||
supportsTools: boolean | null;
|
||||
supportsVision: boolean | null;
|
||||
supportsAudio: boolean | null;
|
||||
supportsMaxTokens: boolean;
|
||||
attachment: boolean | null;
|
||||
structuredOutput: boolean | null;
|
||||
@@ -539,6 +540,25 @@ function resolveVisionCapability(
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve whether a chat model accepts audio input.
|
||||
*
|
||||
* Explicit catalog metadata wins. Synced input modalities are authoritative
|
||||
* only when they contain at least one declared modality; an empty list means
|
||||
* that no source knows the answer and remains `null` so Audio Bridge can act
|
||||
* conservatively.
|
||||
*/
|
||||
export function resolveAudioCapability(
|
||||
spec: Pick<ModelSpec, "supportsAudio"> | undefined,
|
||||
registryModel: { supportsAudio?: boolean } | null,
|
||||
modalitiesInput: readonly string[]
|
||||
): boolean | null {
|
||||
if (typeof registryModel?.supportsAudio === "boolean") return registryModel.supportsAudio;
|
||||
if (typeof spec?.supportsAudio === "boolean") return spec.supportsAudio;
|
||||
if (modalitiesInput.length === 0) return null;
|
||||
return modalitiesInput.some((entry) => String(entry).toLowerCase().includes("audio"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue #6524: an operator-set `max_output_tokens` capability override (see
|
||||
* `src/lib/db/modelCapabilityOverrides.ts`) is the manual escape hatch for a
|
||||
@@ -719,6 +739,7 @@ export function getResolvedModelCapabilities(
|
||||
lookupKey,
|
||||
customVisionOverride
|
||||
);
|
||||
const supportsAudio = resolveAudioCapability(spec, registryModel, modalitiesInput);
|
||||
|
||||
// #8250: when resolve promoted vision over a contradictory attachment=false,
|
||||
// expose attachment=true so catalog / Vision Bridge / clients see one verdict.
|
||||
@@ -736,6 +757,7 @@ export function getResolvedModelCapabilities(
|
||||
supportsThinking,
|
||||
supportsTools,
|
||||
supportsVision,
|
||||
supportsAudio,
|
||||
supportsMaxTokens: heuristicMaxTokens(lookupKey),
|
||||
attachment,
|
||||
structuredOutput: synced?.structured_output ?? null,
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface ModelSpec {
|
||||
supportsThinking?: boolean;
|
||||
supportsTools?: boolean;
|
||||
supportsVision?: boolean;
|
||||
supportsAudio?: boolean;
|
||||
// Model defaults to adaptive thinking and REJECTS an explicit `thinking.type:"disabled"`
|
||||
// (upstream returns 400). Used to normalize the request when a combo/route substitutes
|
||||
// this model after the client already chose `disabled`. See issue #3554.
|
||||
|
||||
21
tests/unit/model-capabilities-audio.test.ts
Normal file
21
tests/unit/model-capabilities-audio.test.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import { resolveAudioCapability } from "../../src/lib/modelCapabilities.ts";
|
||||
|
||||
test("explicit registry audio capability wins", () => {
|
||||
assert.equal(resolveAudioCapability(undefined, { supportsAudio: true }, []), true);
|
||||
});
|
||||
|
||||
test("explicit static audio capability is used when registry is silent", () => {
|
||||
assert.equal(resolveAudioCapability({ supportsAudio: false }, null, []), false);
|
||||
});
|
||||
|
||||
test("synced input modalities identify audio-capable and text-only models", () => {
|
||||
assert.equal(resolveAudioCapability(undefined, null, ["text", "audio"]), true);
|
||||
assert.equal(resolveAudioCapability(undefined, null, ["text"]), false);
|
||||
});
|
||||
|
||||
test("missing audio capability evidence stays unknown", () => {
|
||||
assert.equal(resolveAudioCapability(undefined, null, []), null);
|
||||
});
|
||||
Reference in New Issue
Block a user