mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
Co-authored-by: RaviTharuma <ravitharuma@users.noreply.github.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
@@ -16,7 +16,24 @@ import { getModelContextOverride } from "@/lib/db/modelContextOverrides";
|
||||
import { getModelCapabilityOverride } from "@/lib/db/modelCapabilityOverrides";
|
||||
import { isVisionModelId } from "@/shared/constants/visionModels";
|
||||
|
||||
const TOOL_CALLING_UNSUPPORTED_PATTERNS: string[] = [];
|
||||
const TOOL_CALLING_UNSUPPORTED_PATTERNS: string[] = [
|
||||
// Specialty / non-chat surfaces must never inherit optimistic tool defaults (#8016)
|
||||
"whisper",
|
||||
"tts-1",
|
||||
"gpt-4o-mini-tts",
|
||||
"omni-moderation",
|
||||
"moderation",
|
||||
"eleven_multilingual",
|
||||
"eleven_turbo",
|
||||
"seedance",
|
||||
"/veo",
|
||||
"veo-",
|
||||
"rerank",
|
||||
"embedding",
|
||||
"dall-e",
|
||||
"flux-",
|
||||
"stable-diffusion",
|
||||
];
|
||||
const REASONING_UNSUPPORTED_PATTERNS = [
|
||||
"antigravity/claude-sonnet-4-6",
|
||||
"antigravity/claude-sonnet-4-5",
|
||||
@@ -26,8 +43,39 @@ const REASONING_UNSUPPORTED_PATTERNS = [
|
||||
"antigravity/gpt-oss-",
|
||||
"antigravity/gemini-3",
|
||||
"antigravity/tab_",
|
||||
// Specialty / non-chat surfaces (#8016)
|
||||
"whisper",
|
||||
"tts-1",
|
||||
"gpt-4o-mini-tts",
|
||||
"omni-moderation",
|
||||
"moderation",
|
||||
"eleven_multilingual",
|
||||
"eleven_turbo",
|
||||
"seedance",
|
||||
"/veo",
|
||||
"veo-",
|
||||
"rerank",
|
||||
"embedding",
|
||||
"dall-e",
|
||||
"flux-",
|
||||
"stable-diffusion",
|
||||
];
|
||||
|
||||
/** Catalog/API surface types that are not chat completions. */
|
||||
const NON_CHAT_SURFACE_TYPES = new Set([
|
||||
"audio",
|
||||
"video",
|
||||
"image",
|
||||
"moderation",
|
||||
"rerank",
|
||||
"embedding",
|
||||
"music",
|
||||
]);
|
||||
|
||||
export function isNonChatCatalogSurface(type: unknown): boolean {
|
||||
return typeof type === "string" && NON_CHAT_SURFACE_TYPES.has(type);
|
||||
}
|
||||
|
||||
const MAX_TOKENS_UNSUPPORTED_PATTERNS = [
|
||||
"o1-preview",
|
||||
"o1-mini",
|
||||
|
||||
@@ -2,7 +2,10 @@ import { randomUUID } from "node:crypto";
|
||||
import { parseModel } from "@omniroute/open-sse/services/model.ts";
|
||||
import { getModelInfo } from "@/sse/services/model";
|
||||
import { getModelAliases } from "@/lib/db/models";
|
||||
import { getResolvedModelCapabilities } from "@/lib/modelCapabilities";
|
||||
import {
|
||||
getResolvedModelCapabilities,
|
||||
isNonChatCatalogSurface,
|
||||
} from "@/lib/modelCapabilities";
|
||||
import {
|
||||
getAuthoritativeContextWindow,
|
||||
getAuthoritativeProviderContextWindow,
|
||||
@@ -351,12 +354,24 @@ export function enrichCatalogModelEntry<T extends JsonRecord>(
|
||||
getAuthoritativeProviderContextWindow(provider, model) ??
|
||||
getAuthoritativeContextWindow(metadata.model) ??
|
||||
getAuthoritativeContextWindow(model);
|
||||
const specialtySurface = isNonChatCatalogSurface(entry.type);
|
||||
const capabilityFields = {
|
||||
...(typeof metadata.capabilities.vision === "boolean"
|
||||
? { vision: metadata.capabilities.vision }
|
||||
: {}),
|
||||
tool_calling: metadata.capabilities.toolCalling,
|
||||
reasoning: metadata.capabilities.reasoning,
|
||||
// #8016: never invent chat tool/reasoning defaults onto specialty surfaces.
|
||||
// Only copy boolean true when authoritative metadata says so; specialty rows
|
||||
// default to false instead of optimistic chat heuristics.
|
||||
tool_calling: specialtySurface
|
||||
? metadata.capabilities.supportsTools === true || metadata.capabilities.toolCalling === true
|
||||
? true
|
||||
: false
|
||||
: metadata.capabilities.toolCalling,
|
||||
reasoning: specialtySurface
|
||||
? metadata.capabilities.supportsThinking === true || metadata.capabilities.reasoning === true
|
||||
? true
|
||||
: false
|
||||
: metadata.capabilities.reasoning,
|
||||
// #6241: surface thinking support + the canonical effort tiers so the frontend can
|
||||
// render the effort/thinking toggles. `thinking` is kept for back-compat; `supportsThinking`
|
||||
// is the explicit flag and `effort_tiers` lists the selectable reasoning levels
|
||||
@@ -403,10 +418,22 @@ export function enrichCatalogModelEntry<T extends JsonRecord>(
|
||||
}
|
||||
|
||||
if (
|
||||
!specialtySurface &&
|
||||
(typeof nextEntry.context_length !== "number" || authoritativeContextWindow !== null) &&
|
||||
typeof metadata.limits.contextWindow === "number"
|
||||
) {
|
||||
nextEntry.context_length = metadata.limits.contextWindow;
|
||||
} else if (
|
||||
specialtySurface &&
|
||||
authoritativeContextWindow !== null &&
|
||||
typeof authoritativeContextWindow === "number"
|
||||
) {
|
||||
// Only authoritative static windows may decorate specialty rows.
|
||||
nextEntry.context_length = authoritativeContextWindow;
|
||||
} else if (specialtySurface && typeof nextEntry.context_length === "number") {
|
||||
// Keep an explicit source-provided context if the emitter already set one.
|
||||
} else if (specialtySurface) {
|
||||
delete nextEntry.context_length;
|
||||
}
|
||||
|
||||
if (typeof metadata.limits.maxOutputTokens === "number" && metadata.limits.maxOutputTokens > 0) {
|
||||
|
||||
44
tests/unit/model-capabilities-specialty-8016.test.ts
Normal file
44
tests/unit/model-capabilities-specialty-8016.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
import {
|
||||
getResolvedModelCapabilities,
|
||||
isNonChatCatalogSurface,
|
||||
} from "../../src/lib/modelCapabilities.ts";
|
||||
import { enrichCatalogModelEntry } from "../../src/lib/modelMetadataRegistry.ts";
|
||||
|
||||
describe("specialty catalog surfaces (#8016)", () => {
|
||||
it("recognizes non-chat catalog types", () => {
|
||||
assert.equal(isNonChatCatalogSurface("audio"), true);
|
||||
assert.equal(isNonChatCatalogSurface("video"), true);
|
||||
assert.equal(isNonChatCatalogSurface("moderation"), true);
|
||||
assert.equal(isNonChatCatalogSurface("chat"), false);
|
||||
assert.equal(isNonChatCatalogSurface(undefined), false);
|
||||
});
|
||||
|
||||
it("does not optimistically enable tools/reasoning for specialty model ids", () => {
|
||||
const whisper = getResolvedModelCapabilities({ provider: "openai", model: "whisper-1" });
|
||||
assert.equal(whisper.toolCalling, false);
|
||||
assert.equal(whisper.reasoning, false);
|
||||
|
||||
const tts = getResolvedModelCapabilities({ provider: "openai", model: "tts-1" });
|
||||
assert.equal(tts.toolCalling, false);
|
||||
assert.equal(tts.reasoning, false);
|
||||
|
||||
const veo = getResolvedModelCapabilities({ provider: "veo-free", model: "veo" });
|
||||
assert.equal(veo.toolCalling, false);
|
||||
assert.equal(veo.reasoning, false);
|
||||
});
|
||||
|
||||
it("enrichment does not invent chat tool/reasoning on typed specialty rows", () => {
|
||||
const enriched = enrichCatalogModelEntry({
|
||||
id: "openai/whisper-1",
|
||||
owned_by: "openai",
|
||||
root: "whisper-1",
|
||||
type: "audio",
|
||||
subtype: "transcription",
|
||||
});
|
||||
const caps = (enriched.capabilities || {}) as Record<string, unknown>;
|
||||
assert.equal(caps.tool_calling, false);
|
||||
assert.equal(caps.reasoning, false);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user