mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
fix(ui): keep keyword tier rules that target operator-defined tiers when hydrating the edit modal (#37413)
This commit is contained in:
parent
d491a3d75c
commit
79cac36564
3 changed files with 35 additions and 9 deletions
|
|
@ -14,7 +14,8 @@ export type ComplexityTier = "SIMPLE" | "MEDIUM" | "COMPLEX" | "REASONING";
|
|||
export interface KeywordTierRule {
|
||||
id: string;
|
||||
keywords: string[];
|
||||
tier: ComplexityTier;
|
||||
/** A built-in tier name, or with a custom tier set, one of the defined tier names. */
|
||||
tier: string;
|
||||
}
|
||||
|
||||
interface KeywordTierRulesProps {
|
||||
|
|
@ -99,7 +100,7 @@ const KeywordTierRules: React.FC<KeywordTierRulesProps> = ({ rules, onChange, ti
|
|||
<Select
|
||||
items={tierOptions(tierLabels)}
|
||||
value={rule.tier}
|
||||
onValueChange={(tier: ComplexityTier | null) => tier && updateRule(rule.id, { tier })}
|
||||
onValueChange={(tier: string | null) => tier && updateRule(rule.id, { tier })}
|
||||
>
|
||||
<SelectTrigger aria-label={`Route keyword rule ${index + 1} to tier`} className="w-full">
|
||||
<SelectValue />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { hydrateKeywordTierRules, serializeKeywordTierRules } from "./complexity_router_keywords";
|
||||
|
||||
describe("hydrateKeywordTierRules", () => {
|
||||
it("keeps a rule whose tier is operator-defined instead of silently deleting it on edit", () => {
|
||||
const stored = [
|
||||
{ keywords: ["invoice"], tier: "MEDIUM" },
|
||||
{ keywords: ["pentest", "vulnerability"], tier: "SECURITY_REVIEW" },
|
||||
];
|
||||
expect(hydrateKeywordTierRules(stored)).toEqual([
|
||||
{ id: "stored-0", keywords: ["invoice"], tier: "MEDIUM" },
|
||||
{ id: "stored-1", keywords: ["pentest", "vulnerability"], tier: "SECURITY_REVIEW" },
|
||||
]);
|
||||
});
|
||||
|
||||
it("round-trips through serialize without loss", () => {
|
||||
const stored = [{ keywords: ["pentest"], tier: "SECURITY_REVIEW" }];
|
||||
expect(serializeKeywordTierRules(hydrateKeywordTierRules(stored))).toEqual(stored);
|
||||
});
|
||||
|
||||
it("still drops rows that are not rules at all", () => {
|
||||
expect(hydrateKeywordTierRules([{ keywords: [], tier: "MEDIUM" }, { keywords: ["x"] }, "junk", null])).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,18 +1,18 @@
|
|||
import { ComplexityTier, KeywordTierRule } from "./KeywordTierRules";
|
||||
import { KeywordTierRule } from "./KeywordTierRules";
|
||||
|
||||
/**
|
||||
* Stored shape of a keyword tier rule inside `complexity_router_config`. The UI's
|
||||
* KeywordTierRule carries an extra `id` used only as a React key, so it is stripped on the
|
||||
* way out and synthesized on the way back in. Both the create form and the edit modal go
|
||||
* through here so the two directions cannot drift.
|
||||
* through here so the two directions cannot drift. The tier is any active tier name: a
|
||||
* built-in one, or with tier_definitions, an operator-defined one, so hydration must not
|
||||
* filter on the built-in set or an edit would silently delete a custom tier's rules.
|
||||
*/
|
||||
export interface StoredKeywordTierRule {
|
||||
keywords: string[];
|
||||
tier: ComplexityTier;
|
||||
tier: string;
|
||||
}
|
||||
|
||||
const TIERS: ReadonlySet<string> = new Set<ComplexityTier>(["SIMPLE", "MEDIUM", "COMPLEX", "REASONING"]);
|
||||
|
||||
const asKeywords = (value: unknown): string[] =>
|
||||
Array.isArray(value)
|
||||
? value.filter((keyword): keyword is string => typeof keyword === "string").map((keyword) => keyword.trim())
|
||||
|
|
@ -40,7 +40,7 @@ export const hydrateKeywordTierRules = (value: unknown): KeywordTierRule[] => {
|
|||
const record = entry as Record<string, unknown>;
|
||||
const keywords = asKeywords(record.keywords).filter(Boolean);
|
||||
const tier = record.tier;
|
||||
if (keywords.length === 0 || typeof tier !== "string" || !TIERS.has(tier)) return [];
|
||||
return [{ id: `stored-${index}`, keywords, tier: tier as ComplexityTier }];
|
||||
if (keywords.length === 0 || typeof tier !== "string" || !tier.trim()) return [];
|
||||
return [{ id: `stored-${index}`, keywords, tier }];
|
||||
});
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue