mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-26 01:12:21 +00:00
fix(ui): adapt the jev dashboard pieces to stable/1.102.x
(cherry picked from commit 4bfac88281)
This commit is contained in:
parent
4bfd03e3de
commit
ba74b6a3b6
7 changed files with 24 additions and 94 deletions
|
|
@ -1,3 +1,4 @@
|
|||
import { transitionClassifierType } from "./classifier_type_transition";
|
||||
import JevClassifierConfig from "./JevClassifierConfig";
|
||||
import { Info } from "lucide-react";
|
||||
import { SimpleTooltip } from "@/components/ui/tooltip";
|
||||
|
|
@ -33,12 +34,10 @@ import {
|
|||
DEFAULT_CLASSIFIER_FALLBACK,
|
||||
DEFAULT_CLASSIFIER_TIMEOUT_MS,
|
||||
DEFAULT_CLASSIFICATION_RUBRIC,
|
||||
NEW_CLASSIFIER_CLASSIFICATION_RUBRIC,
|
||||
ClassificationRubric,
|
||||
effectiveTierLabel,
|
||||
heuristicScoringRole,
|
||||
usesLlmClassifier,
|
||||
DEFAULT_HEURISTIC_FIRST_MAX_TIER,
|
||||
usesClassifierContext,
|
||||
DEFAULT_HYBRID_BOUNDARY_MARGIN,
|
||||
HEURISTIC_FIRST_MAX_TIER_KEYS,
|
||||
|
|
@ -270,34 +269,8 @@ const ClassificationMethodConfig: React.FC<ClassificationMethodConfigProps> = ({
|
|||
const explicitlySupportedClassifierEfforts = effortOptionsByModel[classifierModel];
|
||||
|
||||
const handleClassifierTypeChange = (classifierType: ClassifierType) => {
|
||||
const nextValue: ComplexityRouterConfigValue = {
|
||||
...value,
|
||||
classifier_type: classifierType,
|
||||
classifier_llm_config: usesLlmClassifier(classifierType)
|
||||
? value.classifier_llm_config ?? {
|
||||
model: "",
|
||||
timeout_ms: DEFAULT_CLASSIFIER_TIMEOUT_MS,
|
||||
classification_rubric: NEW_CLASSIFIER_CLASSIFICATION_RUBRIC,
|
||||
}
|
||||
: undefined,
|
||||
classifier_context_window_size: usesLlmClassifier(classifierType)
|
||||
? value.classifier_context_window_size ?? DEFAULT_CLASSIFIER_CONTEXT_WINDOW_SIZE
|
||||
: undefined,
|
||||
classifier_context_budget_chars: usesLlmClassifier(classifierType)
|
||||
? value.classifier_context_budget_chars ?? DEFAULT_CLASSIFIER_CONTEXT_BUDGET_CHARS
|
||||
: undefined,
|
||||
classifier_context_include_assistant_turns: usesLlmClassifier(classifierType)
|
||||
? value.classifier_context_include_assistant_turns
|
||||
: undefined,
|
||||
classifier_fallback: usesLlmClassifier(classifierType) ? value.classifier_fallback : undefined,
|
||||
heuristic_first_max_tier:
|
||||
classifierType === "heuristic_first"
|
||||
? value.heuristic_first_max_tier ?? DEFAULT_HEURISTIC_FIRST_MAX_TIER
|
||||
: undefined,
|
||||
hybrid_boundary_margin:
|
||||
classifierType === "hybrid" ? value.hybrid_boundary_margin ?? DEFAULT_HYBRID_BOUNDARY_MARGIN : undefined,
|
||||
};
|
||||
onChange(nextValue);
|
||||
|
||||
onChange(transitionClassifierType(value, classifierType));
|
||||
};
|
||||
|
||||
const handleHeuristicFirstMaxTierChange = (tier: string) => {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import { afterEach, describe, expect, it, vi } from "vitest";
|
|||
import { fireEvent, renderWithProviders, screen } from "../../../tests/test-utils";
|
||||
import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized";
|
||||
import ClassificationMethodConfig from "./ClassificationMethodConfig";
|
||||
import AutoRouterClassifierTabs from "./AutoRouterClassifierTabs";
|
||||
import JevEditor from "./JevClassifierConfig";
|
||||
import { type ComplexityRouterConfigValue } from "./ComplexityRouterConfig";
|
||||
import {
|
||||
|
|
@ -50,7 +49,7 @@ const initial: ComplexityRouterConfigValue = {
|
|||
function Form() {
|
||||
const [value, setValue] = useState(initial);
|
||||
return (
|
||||
<AutoRouterClassifierTabs value={value} onChange={setValue}>
|
||||
<>
|
||||
<ClassificationMethodConfig
|
||||
value={value}
|
||||
onChange={setValue}
|
||||
|
|
@ -90,7 +89,7 @@ function Form() {
|
|||
>
|
||||
Probe current config
|
||||
</button>
|
||||
</AutoRouterClassifierTabs>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +102,6 @@ describe("JEV classifier editor", () => {
|
|||
expect(screen.getByText("Classifier Prompt")).toBeInTheDocument();
|
||||
expect(screen.getByRole("switch", { name: "Use images for classification" })).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole("radio", { name: /JEV Classifier/ }));
|
||||
expect(screen.getByRole("tab", { name: "Complexity" })).toHaveAttribute("aria-selected", "true");
|
||||
expect(screen.getByLabelText("JEV Model")).toHaveValue("jev-latest");
|
||||
expect(screen.getByLabelText("JEV Instructions")).toBeDisabled();
|
||||
expect(screen.queryByLabelText("Classifier Model")).not.toBeInTheDocument();
|
||||
|
|
|
|||
|
|
@ -531,6 +531,17 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
|
|||
setIsTestModalVisible(true);
|
||||
};
|
||||
|
||||
const jevConnectionTestParams =
|
||||
effectiveClassifierType(complexityRouterConfig) === "jev"
|
||||
? {
|
||||
prompt: JEV_CONNECTION_TEST_PROMPT,
|
||||
config: buildComplexityRouterConfig(complexityRouterConfigParams),
|
||||
defaultModel: resolveComplexityDefaultModel(complexityRouterConfig, complexityRouterConfig.default_model),
|
||||
routerName: watchedName,
|
||||
teamId: requiresTeamScope ? watchedTeamId ?? undefined : undefined,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Card>
|
||||
|
|
@ -801,20 +812,7 @@ const AddAutoRouterTab: React.FC<AddAutoRouterTabProps> = ({
|
|||
testId={connectionTestId}
|
||||
accessToken={accessToken}
|
||||
targets={testTargets}
|
||||
jevRequest={
|
||||
effectiveClassifierType(complexityRouterConfig) === "jev"
|
||||
? buildAutoRouterRoutingTestRequest({
|
||||
prompt: JEV_CONNECTION_TEST_PROMPT,
|
||||
config: buildComplexityRouterConfig(complexityRouterConfigParams),
|
||||
defaultModel: resolveComplexityDefaultModel(
|
||||
complexityRouterConfig,
|
||||
complexityRouterConfig.default_model,
|
||||
),
|
||||
routerName: watchedName,
|
||||
teamId: requiresTeamScope ? watchedTeamId ?? undefined : undefined,
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
jevRequest={jevConnectionTestParams && buildAutoRouterRoutingTestRequest(jevConnectionTestParams)}
|
||||
onTestComplete={() => setIsTestingConnection(false)}
|
||||
/>
|
||||
</TooltipProvider>
|
||||
|
|
|
|||
|
|
@ -66,39 +66,6 @@ describe("transitionClassifierType", () => {
|
|||
expect(result).toMatchObject(expectedSettings);
|
||||
});
|
||||
|
||||
it.each(["capability", "llm_v2"] as const)("requires explicit policy input for a new %s classifier", (target) => {
|
||||
const result = transitionClassifierType(standard, target);
|
||||
expect(result.classifier_llm_config).toEqual({ model: "judge", timeout_ms: 20000 });
|
||||
expect(result.classifier_fallback).toBeUndefined();
|
||||
if (target === "capability") {
|
||||
expect(result.capability_classifier_config?.base_threshold).toBeNaN();
|
||||
} else {
|
||||
expect(result.llm_v2_config).toMatchObject({ efficient_profile: "", capable_profile: "", harness: "" });
|
||||
expect(result.llm_v2_config?.max_quality_gap).toBeNaN();
|
||||
}
|
||||
expect(standard.tiers.MEDIUM).toEqual(["middle"]);
|
||||
expect(standard.classifier_llm_config?.classification_rubric).toBe("business");
|
||||
});
|
||||
|
||||
it.each([
|
||||
["capability", "llm"],
|
||||
["capability", "heuristic_first"],
|
||||
["capability", "hybrid"],
|
||||
["llm_v2", "llm"],
|
||||
["llm_v2", "heuristic_first"],
|
||||
["llm_v2", "hybrid"],
|
||||
] as const)("restores the complexity rubric from %s to %s while preserving the judge", (source, target) => {
|
||||
const forecast = transitionClassifierType(standard, source);
|
||||
const result = transitionClassifierType(forecast, target);
|
||||
expect(result.classifier_llm_config).toEqual({
|
||||
model: "judge",
|
||||
timeout_ms: 20000,
|
||||
classification_rubric: "agentic",
|
||||
});
|
||||
expect(result.capability_classifier_config).toBeUndefined();
|
||||
expect(result.llm_v2_config).toBeUndefined();
|
||||
});
|
||||
|
||||
it("clears the inactive non-reasoning pool and plan floor when switching to local classification", () => {
|
||||
const initial: ComplexityRouterConfigValue = {
|
||||
...standard,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export const transitionClassifierType = (
|
|||
const judgeConfig = value.classifier_llm_config ?? { model: "", timeout_ms: DEFAULT_CLASSIFIER_TIMEOUT_MS };
|
||||
const nextValue: ComplexityRouterConfigValue = {
|
||||
...value,
|
||||
classifier_type: classifierType,
|
||||
jev_classifier_config:
|
||||
classifierType === "jev" ? value.jev_classifier_config ?? defaultJevClassifierConfig() : undefined,
|
||||
classification_prompt: classifierType === "jev" ? undefined : value.classification_prompt,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,7 @@
|
|||
export type ClassifierType =
|
||||
| "heuristic"
|
||||
| "heuristic_v2"
|
||||
| "llm"
|
||||
| "jev"
|
||||
| "heuristic_first"
|
||||
| "hybrid"
|
||||
| "capability"
|
||||
| "llm_v2";
|
||||
export type ClassifierType = "heuristic" | "heuristic_v2" | "llm" | "jev" | "heuristic_first" | "hybrid";
|
||||
|
||||
export const usesLlmClassifier = (classifierType: ClassifierType): boolean =>
|
||||
(["llm", "heuristic_first", "hybrid", "capability", "llm_v2"] as const).some((type) => type === classifierType);
|
||||
(["llm", "heuristic_first", "hybrid"] as const).some((type) => type === classifierType);
|
||||
|
||||
export const usesClassifierContext = (classifierType: ClassifierType): boolean =>
|
||||
classifierType === "jev" || usesLlmClassifier(classifierType);
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ import ComplexityRouterConfig, {
|
|||
ClassifierLLMConfig,
|
||||
ClassifierType,
|
||||
ComplexityRouterConfigValue,
|
||||
ComplexityTiers,
|
||||
|
||||
effectiveClassifierType,
|
||||
heuristicScoringRole,
|
||||
DEFAULT_ADAPTIVE_WEIGHTS,
|
||||
DEFAULT_SESSION_AFFINITY,
|
||||
DEFAULT_DEPLOYMENT_AFFINITY,
|
||||
|
|
@ -340,9 +342,8 @@ export const buildUpdatedComplexityRouterConfig = (
|
|||
keywordMatching?: KeywordMatchingState,
|
||||
): Record<string, unknown> => {
|
||||
const isManaged = (key: string): boolean => {
|
||||
if (key === "classifier_context_per_turn_chars") {
|
||||
if (key === "classifier_context_per_turn_chars")
|
||||
return !usesClassifierContext(effectiveClassifierType(value)) || Object.prototype.hasOwnProperty.call(value, key);
|
||||
}
|
||||
if (MANAGED_COMPLEXITY_ROUTER_KEYS.has(key)) return true;
|
||||
if (keywordMatching !== undefined && KEYWORD_MATCHING_KEYS.has(key)) return true;
|
||||
return customTechnicalKeywords !== undefined && key === "custom_technical_keywords";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue