mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 20:32:20 +03:00
* fix(combo): clamp reasoning buffer to model output cap * fix(routing): preserve near-cap reasoning max tokens * fix(routing): getExplicitModelOutputCap falls through to registry cap on non-numeric synced limit_output getExplicitModelOutputCap short-circuited to null whenever a synced capability row existed, even if that row's limit_output was not a number (models.dev commonly omits it). That silently disabled the reasoning-token buffer clamp for any model with a synced row lacking an output limit. Now only return the synced value when it IS a number; otherwise fall through to registryModel.maxOutputTokens / spec.maxOutputTokens, matching the ??-chain precedence already used by getResolvedModelCapabilities(). Adds a standalone regression test (proves the fallthrough returns the real registry cap, not null) and hardens the #6274 fixture id so its no-output-cap case does not prefix-match the real glm-5.2 static spec. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> * chore(stryker): register ollama-quota covering tests (release drift from merge burst) Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com> --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
import {
|
|
getExplicitModelOutputCap,
|
|
getResolvedModelCapabilities,
|
|
} from "../../src/lib/modelCapabilities.ts";
|
|
|
|
/**
|
|
* Below this caller-supplied `max_tokens`, the request is treated as a probe
|
|
* (e.g. Claude Code's `/model` capability check sends `max_tokens: 1`) rather
|
|
* than a genuine reasoning budget, so no headroom is added. Keeping it a named
|
|
* constant makes the threshold easy to tune. See issue #6274 (probe inflated to
|
|
* 1001 upstream) vs. issue #3587 (headroom for real reasoning budgets).
|
|
*/
|
|
export const REASONING_BUFFER_MIN_TRIGGER = 256;
|
|
|
|
export function toPositiveInteger(value: unknown): number | null {
|
|
const numericValue =
|
|
typeof value === "number"
|
|
? value
|
|
: typeof value === "string" && value.trim() !== ""
|
|
? Number(value)
|
|
: null;
|
|
if (numericValue === null || !Number.isFinite(numericValue)) return null;
|
|
const normalized = Math.floor(numericValue);
|
|
return normalized > 0 ? normalized : null;
|
|
}
|
|
|
|
export function resolveReasoningBufferedMaxTokens(
|
|
modelStr: string,
|
|
currentMaxTokens: unknown,
|
|
options: { enabled?: boolean } = {}
|
|
): number | null {
|
|
if (options.enabled === false) return null;
|
|
|
|
const current = toPositiveInteger(currentMaxTokens);
|
|
if (current === null) return null;
|
|
|
|
const capabilities = getResolvedModelCapabilities(modelStr);
|
|
if (capabilities.supportsThinking !== true) return null;
|
|
|
|
const maxOutputTokens = toPositiveInteger(getExplicitModelOutputCap(modelStr));
|
|
if (maxOutputTokens === null) return null;
|
|
if (current > maxOutputTokens) return maxOutputTokens;
|
|
|
|
// Issue #6274: a tiny explicit budget is a capability probe, not a reasoning
|
|
// request. Respect it verbatim instead of inflating (e.g. 1 -> 1001).
|
|
if (current < REASONING_BUFFER_MIN_TRIGGER) return current;
|
|
|
|
const buffered = Math.max(current + 1000, Math.ceil(current * 1.5));
|
|
return buffered > maxOutputTokens ? current : buffered;
|
|
}
|