mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-17 12:22:34 +03:00
fix(combo): name output_tokens as the exclusion reason instead of structured output (#12374)
When every combo target is excluded because the request's max_tokens exceeds each target's known output limit, the terminal 400 now says so — requested max_tokens against the pool's highest known ceiling — instead of the unrelated "supports structured output for this request". Diagnostics (unmet, excluded[].reason, terminalReason) are unchanged; only the message for the output_tokens primary reason moves. Validated in a combined worktree with all 25 PRs of this batch boarded together: typecheck:core clean, 443/443 node-runner tests plus 14/14 vitest across every test file the batch touches, and check-changelog-integrity, check:cycles (418 files), check:provider-consistency (272 REGISTRY entries, 355 canonical providers), check:docs-counts, check:docs-sync (42 locales) and check-file-size all green. Thanks @pacocartones.
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- **fix(combo):** capability-filter exhaustion caused by `max_tokens` above every target's known output limit now reports that reason (requested `max_tokens` vs the pool's highest known ceiling) instead of the unrelated "supports structured output" message ([#12229](https://github.com/diegosouzapw/OmniRoute/issues/12229)) — thanks @DW-MediaLab
|
||||
@@ -627,6 +627,18 @@ export type CompatFilterOptions = {
|
||||
failOpen?: boolean;
|
||||
};
|
||||
|
||||
function highestKnownOutputLimit(targets: ResolvedComboTarget[]): number {
|
||||
let ceiling = 0;
|
||||
for (const target of targets) {
|
||||
const limit = getResolvedModelCapabilities({
|
||||
provider: target.providerId || target.provider || null,
|
||||
model: target.modelStr,
|
||||
}).maxOutputTokens;
|
||||
if (typeof limit === "number" && limit > ceiling) ceiling = limit;
|
||||
}
|
||||
return ceiling;
|
||||
}
|
||||
|
||||
export function hasHardCapabilityFailure(reasons: string[]): boolean {
|
||||
return reasons.some((reason) => HARD_COMPAT_REASONS.has(reason));
|
||||
}
|
||||
@@ -668,6 +680,16 @@ export function describeCapabilityFilterExhaustion(
|
||||
message = `No target in combo ${name} supports tool calling; request carried ${toolCount} tools`;
|
||||
} else if (primary === "vision") {
|
||||
message = `No target in combo ${name} has confirmed vision support for this image request`;
|
||||
} else if (primary === "output_tokens") {
|
||||
// #12229: name the real reason. Collapsing this into the structured-output
|
||||
// message sent operators chasing response_format when the request's
|
||||
// max_tokens simply exceeded every target's known output ceiling.
|
||||
const ceiling = highestKnownOutputLimit(
|
||||
rejected.filter((entry) => entry.reasons.includes("output_tokens")).map((e) => e.target)
|
||||
);
|
||||
message =
|
||||
`No target in combo ${name} can produce the requested max_tokens=${requirements.requestedOutputTokens}; ` +
|
||||
`the highest known output limit in the pool is ${ceiling}`;
|
||||
} else {
|
||||
message = `No target in combo ${name} supports structured output for this request`;
|
||||
}
|
||||
|
||||
@@ -320,3 +320,32 @@ test("auto context estimate still dispatches when all known limits look too smal
|
||||
assert.equal(result.status, 200);
|
||||
assert.deepEqual(dispatches, ["openai/tiny"]);
|
||||
});
|
||||
|
||||
test("#12229 exhaustion: output_tokens exclusion names max_tokens vs the model ceiling", () => {
|
||||
saveModelsDevCapabilities({
|
||||
claude: {
|
||||
"claude-haiku-4-5-20251001": capabilityEntry(200000, {
|
||||
tool_call: true,
|
||||
structured_output: true,
|
||||
limit_output: 64000,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const targets = [target("claude", "claude/claude-haiku-4-5-20251001")];
|
||||
const body = {
|
||||
messages: [{ role: "user", content: "hoi wie ben je?" }],
|
||||
max_tokens: 100000,
|
||||
};
|
||||
|
||||
const exhaustion = describeCapabilityFilterExhaustion(targets, body, "hermes-main");
|
||||
assert.ok(exhaustion);
|
||||
assert.deepEqual(exhaustion!.unmet, ["output_tokens"]);
|
||||
assert.equal(exhaustion!.excluded[0].reason, "output_tokens");
|
||||
assert.equal(
|
||||
exhaustion!.message,
|
||||
"No target in combo hermes-main can produce the requested max_tokens=100000; the highest known output limit in the pool is 64000"
|
||||
);
|
||||
assert.doesNotMatch(exhaustion!.message, /structured output/i);
|
||||
assert.equal(exhaustion!.terminalReason, "capability_mismatch");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user