mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-06 02:48:13 +00:00
fix(ui): reset unsupported directional scope selections
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
6388bdf73e
commit
bc423af734
4 changed files with 72 additions and 19 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { screen, waitFor } from "@testing-library/react";
|
||||
import { fireEvent, screen, waitFor } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { chooseSelectOption, renderWithProviders } from "@/../tests/test-utils";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
|
@ -151,6 +151,34 @@ describe("AddGuardrailForm create payload characterization", () => {
|
|||
expect(screen.getByRole("option", { name: "Both (request and response)" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("clears a selected directional scope when switching to an unsupported provider", async () => {
|
||||
vi.mocked(networking.getGuardrailUISettings).mockResolvedValue({
|
||||
...uiSettings,
|
||||
supported_modes: ["pre_call", "logging_only"],
|
||||
providers_without_directional_logging_only_scope: ["xecguard"],
|
||||
});
|
||||
vi.mocked(networking.getGuardrailProviderSpecificParams).mockResolvedValue({
|
||||
...providerParams,
|
||||
xecguard: { ui_friendly_name: "XecGuard" },
|
||||
});
|
||||
const user = userEvent.setup({ delay: null });
|
||||
renderForm();
|
||||
|
||||
fireEvent.change(await screen.findByLabelText("Guardrail Name"), { target: { value: "switch-scope" } });
|
||||
await pickProvider(user, "Bedrock Guardrail");
|
||||
await user.click(screen.getByLabelText("Mode"));
|
||||
await user.click((await screen.findAllByText("logging_only")).at(-1) as HTMLElement);
|
||||
await chooseSelectOption(user, await screen.findByLabelText("Logging only scope"), "Output only (response)");
|
||||
expect(screen.getByLabelText("Logging only scope")).toHaveTextContent("Output only (response)");
|
||||
await pickProvider(user, "XecGuard");
|
||||
await user.click(screen.getByRole("button", { name: "Next" }));
|
||||
await user.click(await screen.findByRole("button", { name: "Create Guardrail" }));
|
||||
|
||||
await waitFor(() => expect(networking.createGuardrailCall).toHaveBeenCalledTimes(1));
|
||||
expect(payload()?.litellm_params.mode).toContain("logging_only");
|
||||
expect(payload()?.litellm_params).not.toHaveProperty("logging_only_scope");
|
||||
});
|
||||
|
||||
it("hides logging-only scope and omits it from a pre-call payload", async () => {
|
||||
const user = userEvent.setup({ delay: null });
|
||||
renderForm();
|
||||
|
|
|
|||
|
|
@ -243,6 +243,14 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
const providerValue = guardrail_provider_map[selectedProvider];
|
||||
return (providerValue || "").toLowerCase() === "tool_permission";
|
||||
}, [selectedProvider]);
|
||||
const directionalScopeSupported = supportsDirectionalLoggingOnlyScope(guardrailSettings, selectedProvider);
|
||||
|
||||
useEffect(() => {
|
||||
const scopeChoice = form.getValues("logging_only_scope_choice");
|
||||
if (!directionalScopeSupported && (scopeChoice === "input" || scopeChoice === "output")) {
|
||||
form.setValue("logging_only_scope_choice", "default");
|
||||
}
|
||||
}, [directionalScopeSupported, form]);
|
||||
|
||||
// Fetch guardrail UI settings + provider params on mount / accessToken change
|
||||
useEffect(() => {
|
||||
|
|
@ -690,7 +698,6 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
|
|||
const providerLabels: Record<string, string> = getGuardrailProviders();
|
||||
const providerKeys = Object.keys(providerLabels);
|
||||
const supportedModes = getSupportedModesForProvider(guardrailSettings, selectedProvider) ?? DEFAULT_MODES;
|
||||
const directionalScopeSupported = supportsDirectionalLoggingOnlyScope(guardrailSettings, selectedProvider);
|
||||
return (
|
||||
<FieldGroup>
|
||||
<GuardrailField
|
||||
|
|
|
|||
|
|
@ -204,6 +204,23 @@ describe("GuardrailInfoView update payload characterization", () => {
|
|||
expect(lastPayload()).toEqual({ litellm_params: { logging_only_scope: null } });
|
||||
});
|
||||
|
||||
it("clears a stored directional scope for a provider that does not support it", async () => {
|
||||
vi.mocked(networking.getGuardrailUISettings).mockResolvedValue({
|
||||
...uiSettings,
|
||||
providers_without_directional_logging_only_scope: ["bedrock"],
|
||||
});
|
||||
vi.mocked(networking.getGuardrailInfo).mockResolvedValue(
|
||||
guardrail({ guardrailIdentifier: "gr-abc", mode: "logging_only", logging_only_scope: "output" }),
|
||||
);
|
||||
const user = userEvent.setup({ delay: null });
|
||||
renderView();
|
||||
await openEditor(user);
|
||||
await saveChanges(user);
|
||||
|
||||
await waitFor(() => expect(networking.updateGuardrailCall).toHaveBeenCalledTimes(1));
|
||||
expect(lastPayload()).toEqual({ litellm_params: { logging_only_scope: null } });
|
||||
});
|
||||
|
||||
it("parses the guardrail information textarea into an object", async () => {
|
||||
const user = userEvent.setup({ delay: null });
|
||||
renderView();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import {
|
|||
getLoggingOnlyScopeUpdate,
|
||||
getGuardrailLogoAndName,
|
||||
guardrail_provider_map,
|
||||
choiceToLoggingOnlyScope,
|
||||
loggingOnlyScopeToChoice,
|
||||
skipSystemMessageToChoice,
|
||||
skipToolMessageToChoice,
|
||||
|
|
@ -224,27 +225,27 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
|
|||
// binds are seeded: an unbound key would otherwise be submitted as if the user had set it.
|
||||
useEffect(() => {
|
||||
if (!guardrailData) return;
|
||||
const litellmParams = guardrailData.litellm_params;
|
||||
form.setValue("guardrail_name", guardrailData.guardrail_name);
|
||||
form.setValue("default_on", guardrailData.litellm_params?.default_on);
|
||||
const storedLoggingOnlyScope = guardrailData.litellm_params?.logging_only_scope;
|
||||
form.setValue("logging_only_scope_choice", loggingOnlyScopeToChoice(storedLoggingOnlyScope));
|
||||
form.setValue(
|
||||
"skip_system_message_choice",
|
||||
skipSystemMessageToChoice(guardrailData.litellm_params?.skip_system_message_in_guardrail),
|
||||
);
|
||||
form.setValue(
|
||||
"skip_tool_message_choice",
|
||||
skipToolMessageToChoice(guardrailData.litellm_params?.skip_tool_message_in_guardrail),
|
||||
);
|
||||
form.setValue(
|
||||
"guardrail_info",
|
||||
guardrailData.guardrail_info ? JSON.stringify(guardrailData.guardrail_info, null, 2) : "",
|
||||
);
|
||||
if (guardrailData.litellm_params?.optional_params) {
|
||||
form.setValue("optional_params", guardrailData.litellm_params.optional_params);
|
||||
form.setValue("default_on", litellmParams?.default_on);
|
||||
form.setValue("logging_only_scope_choice", loggingOnlyScopeToChoice(litellmParams?.logging_only_scope));
|
||||
const skipSystemMessageChoice = skipSystemMessageToChoice(litellmParams?.skip_system_message_in_guardrail);
|
||||
form.setValue("skip_system_message_choice", skipSystemMessageChoice);
|
||||
form.setValue("skip_tool_message_choice", skipToolMessageToChoice(litellmParams?.skip_tool_message_in_guardrail));
|
||||
const guardrailInfo = guardrailData.guardrail_info ? JSON.stringify(guardrailData.guardrail_info, null, 2) : "";
|
||||
form.setValue("guardrail_info", guardrailInfo);
|
||||
if (litellmParams?.optional_params) {
|
||||
form.setValue("optional_params", litellmParams.optional_params);
|
||||
}
|
||||
}, [guardrailData, guardrailProviderSpecificParams, form]);
|
||||
|
||||
useEffect(() => {
|
||||
const scope = choiceToLoggingOnlyScope(form.getValues("logging_only_scope_choice"));
|
||||
if (!directionalScopeSupported && scope !== null && scope !== "both") {
|
||||
form.setValue("logging_only_scope_choice", "default");
|
||||
}
|
||||
}, [directionalScopeSupported, form, guardrailData]);
|
||||
|
||||
const resetToolPermissionEditor = useCallback(() => {
|
||||
if (guardrailData?.litellm_params?.guardrail === "tool_permission") {
|
||||
setToolPermissionConfig({
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue