mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(executor): strip provider prefix from versioned built-in tool model field (#3532)
Integrated into release/v3.8.20
This commit is contained in:
committed by
GitHub
parent
40d9c54516
commit
99281545fc
@@ -317,6 +317,27 @@ export function sanitizeReasoningEffortForProvider(
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip the OmniRoute provider prefix from versioned built-in tool model
|
||||
* fields (e.g. `cc/claude-opus-4-8` → `claude-opus-4-8`). Versioned built-in
|
||||
* tool types carry an 8-digit date suffix (`advisor_20260301`, `bash_20250124`);
|
||||
* the real Claude CLI sends a bare model id there, never a prefixed one, so a
|
||||
* leaked OmniRoute prefix makes Anthropic reject the request. Mutates in place.
|
||||
*/
|
||||
export function stripVersionedToolModelPrefix(tools: unknown): void {
|
||||
if (!Array.isArray(tools)) return;
|
||||
for (const t of tools as Array<Record<string, unknown>>) {
|
||||
if (
|
||||
typeof t.type === "string" &&
|
||||
/^[a-z][a-z0-9_]*_\d{8}$/.test(t.type) &&
|
||||
typeof t.model === "string" &&
|
||||
t.model.includes("/")
|
||||
) {
|
||||
t.model = t.model.split("/").pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BaseExecutor - Base class for provider executors.
|
||||
* Implements the Strategy pattern: subclasses override specific methods
|
||||
@@ -824,6 +845,9 @@ export class BaseExecutor {
|
||||
for (const t of tb.tools as Array<Record<string, unknown>>) {
|
||||
delete t.cache_control;
|
||||
}
|
||||
// Also strip OmniRoute provider prefix from versioned built-in tool
|
||||
// model fields (e.g. cc/claude-opus-4-8 → claude-opus-4-8).
|
||||
stripVersionedToolModelPrefix(tb.tools);
|
||||
}
|
||||
|
||||
// Per-request behavior overrides via custom client headers.
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
sanitizeClaudeToolSchema,
|
||||
sanitizeClaudeToolSchemas,
|
||||
} from "../../open-sse/translator/helpers/schemaCoercion.ts";
|
||||
import { stripVersionedToolModelPrefix } from "../../open-sse/executors/base.ts";
|
||||
|
||||
type AnyRecord = Record<string, unknown>;
|
||||
const schemaOf = (tools: unknown, i = 0): AnyRecord =>
|
||||
@@ -270,3 +271,50 @@ describe("review fixes — established aliases + kill-switch", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("native claude OAuth path — versioned built-in tool model prefix stripping", () => {
|
||||
// Exercises the REAL production helper from base.ts (not a re-implementation),
|
||||
// so reverting the fix in base.ts breaks these assertions.
|
||||
it("strips cc/ prefix from advisor_20260301 model field", () => {
|
||||
const tools: AnyRecord[] = [
|
||||
{ type: "advisor_20260301", name: "advisor", model: "cc/claude-opus-4-8" },
|
||||
{ type: "bash_20250124", name: "Bash", model: "kiro/claude-opus-4.8" },
|
||||
{ name: "Read", input_schema: { type: "object", properties: {} } },
|
||||
];
|
||||
stripVersionedToolModelPrefix(tools);
|
||||
assert.equal(tools[0].model, "claude-opus-4-8", "cc/ prefix stripped from advisor model");
|
||||
assert.equal(tools[1].model, "claude-opus-4.8", "kiro/ prefix stripped from bash model");
|
||||
assert.equal("model" in tools[2], false, "regular tool untouched");
|
||||
});
|
||||
|
||||
it("strips multi-segment prefix (claude/claude-sonnet-4-6) from versioned tool model", () => {
|
||||
const tools: AnyRecord[] = [
|
||||
{ type: "bash_20250124", name: "Bash", model: "claude/claude-sonnet-4-6" },
|
||||
];
|
||||
stripVersionedToolModelPrefix(tools);
|
||||
assert.equal(tools[0].model, "claude-sonnet-4-6");
|
||||
});
|
||||
|
||||
it("leaves bare model on versioned tool unchanged", () => {
|
||||
const tools: AnyRecord[] = [
|
||||
{ type: "advisor_20260301", name: "advisor", model: "claude-opus-4-8" },
|
||||
];
|
||||
stripVersionedToolModelPrefix(tools);
|
||||
assert.equal(tools[0].model, "claude-opus-4-8");
|
||||
});
|
||||
|
||||
it("leaves non-versioned tool types untouched even with a prefixed model", () => {
|
||||
const tools: AnyRecord[] = [
|
||||
{ type: "custom", name: "x", model: "cc/claude-opus-4-8" },
|
||||
{ type: "advisor_2026", name: "y", model: "cc/claude-opus-4-8" }, // not 8 digits
|
||||
];
|
||||
stripVersionedToolModelPrefix(tools);
|
||||
assert.equal(tools[0].model, "cc/claude-opus-4-8", "non-versioned type untouched");
|
||||
assert.equal(tools[1].model, "cc/claude-opus-4-8", "short date suffix untouched");
|
||||
});
|
||||
|
||||
it("is a no-op for non-array input", () => {
|
||||
assert.doesNotThrow(() => stripVersionedToolModelPrefix(undefined));
|
||||
assert.doesNotThrow(() => stripVersionedToolModelPrefix({ tools: [] }));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user