feat(dashboard): skip_tool_message_in_guardrail in guardrail UI

Adds a tri-state control (inherit / yes / no) when creating or editing
guardrails so admins can set litellm_params.skip_tool_message_in_guardrail
without YAML, mirroring the existing skip_system_message control.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
shivam 2026-05-07 19:11:41 -07:00
parent f58f8927f2
commit bdb2b0e708
No known key found for this signature in database
6 changed files with 120 additions and 1 deletions

View File

@ -5,6 +5,7 @@ import { createGuardrailCall, getGuardrailProviderSpecificParams, getGuardrailUI
import ContentFilterConfiguration from "./content_filter/ContentFilterConfiguration";
import {
choiceToSkipSystemForCreate,
choiceToSkipToolForCreate,
getGuardrailProviders,
guardrail_provider_map,
guardrailLogoMap,
@ -188,6 +189,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
mode: preset.mode,
default_on: preset.defaultOn,
skip_system_message_choice: "inherit",
skip_tool_message_choice: "inherit",
};
if (preset.provider === "BlockCodeExecution") {
baseValues.confidence_threshold = 0.5;
@ -433,6 +435,11 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
guardrailData.litellm_params.skip_system_message_in_guardrail = skipForCreate;
}
const skipToolForCreate = choiceToSkipToolForCreate(values.skip_tool_message_choice);
if (skipToolForCreate !== undefined) {
guardrailData.litellm_params.skip_tool_message_in_guardrail = skipToolForCreate;
}
// For Presidio PII, add the entity and action configurations
if (values.provider === "PresidioPII" && selectedEntities.length > 0) {
const piiEntitiesConfig: { [key: string]: string } = {};
@ -804,6 +811,18 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
</Select>
</Form.Item>
<Form.Item
name="skip_tool_message_choice"
label="Skip tool messages in guardrail"
tooltip="Unified guardrails only: omit role: tool from guardrail evaluation input (OpenAI chat + Anthropic messages). The model still receives full messages. Use global default follows litellm_settings.skip_tool_message_in_guardrail."
>
<Select>
<Select.Option value="inherit">Use global default</Select.Option>
<Select.Option value="yes">Yes exclude from guardrail scan</Select.Option>
<Select.Option value="no">No always include in scan</Select.Option>
</Select>
</Form.Item>
{/* Use the GuardrailProviderFields component to render provider-specific fields */}
{!isToolPermissionProvider && !shouldRenderContentFilterConfigSettings(selectedProvider) && !shouldRenderLLMJudgeFields(selectedProvider) && (
<GuardrailProviderFields
@ -1155,6 +1174,7 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ visible, onClose, a
mode: "pre_call",
default_on: false,
skip_system_message_choice: "inherit",
skip_tool_message_choice: "inherit",
}}
>
{stepConfigs.map((step, index) => {

View File

@ -6,6 +6,7 @@ import {
guardrailLogoMap,
getGuardrailProviders,
type SkipSystemMessageChoice,
type SkipToolMessageChoice,
} from "./guardrail_info_helpers";
import { getGuardrailUISettings, getGlobalLitellmHeaderName } from "../networking";
import PiiConfiguration from "./pii_configuration";
@ -29,6 +30,7 @@ interface EditGuardrailFormProps {
default_on: boolean;
pii_entities_config?: { [key: string]: string };
skip_system_message_choice?: SkipSystemMessageChoice;
skip_tool_message_choice?: SkipToolMessageChoice;
[key: string]: any;
};
}
@ -138,6 +140,15 @@ const EditGuardrailForm: React.FC<EditGuardrailFormProps> = ({
delete litellm_params.skip_system_message_in_guardrail;
}
const skipToolChoice = values.skip_tool_message_choice as SkipToolMessageChoice | undefined;
if (skipToolChoice === "yes") {
litellm_params.skip_tool_message_in_guardrail = true;
} else if (skipToolChoice === "no") {
litellm_params.skip_tool_message_in_guardrail = false;
} else {
delete litellm_params.skip_tool_message_in_guardrail;
}
let guardrail_info: any = {};
// For Presidio PII, add the entity and action configurations
@ -432,6 +443,18 @@ const EditGuardrailForm: React.FC<EditGuardrailFormProps> = ({
</Select>
</Form.Item>
<Form.Item
name="skip_tool_message_choice"
label="Skip tool messages in guardrail"
tooltip="Unified guardrails only: whether role: tool content is omitted from guardrail input (LLM still receives full messages). Use global default follows litellm_settings.skip_tool_message_in_guardrail."
>
<Select>
<Option value="inherit">Use global default</Option>
<Option value="yes">Yes exclude from guardrail scan</Option>
<Option value="no">No always include in scan</Option>
</Select>
</Form.Item>
{renderProviderSpecificFields()}
<div className="flex justify-end space-x-2 mt-4">

View File

@ -29,7 +29,9 @@ import {
getGuardrailLogoAndName,
guardrail_provider_map,
skipSystemMessageToChoice,
skipToolMessageToChoice,
type SkipSystemMessageChoice,
type SkipToolMessageChoice,
} from "./guardrail_info_helpers";
import GuardrailOptionalParams from "./guardrail_optional_params";
import GuardrailProviderFields from "./guardrail_provider_fields";
@ -214,12 +216,16 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
if (guardrailData && form) {
const lp = { ...(guardrailData.litellm_params || {}) };
delete lp.skip_system_message_in_guardrail;
delete lp.skip_tool_message_in_guardrail;
form.setFieldsValue({
guardrail_name: guardrailData.guardrail_name,
...lp,
skip_system_message_choice: skipSystemMessageToChoice(
guardrailData.litellm_params?.skip_system_message_in_guardrail,
),
skip_tool_message_choice: skipToolMessageToChoice(
guardrailData.litellm_params?.skip_tool_message_in_guardrail,
),
guardrail_info: guardrailData.guardrail_info ? JSON.stringify(guardrailData.guardrail_info, null, 2) : "",
// Include any optional_params if they exist
...(guardrailData.litellm_params?.optional_params && {
@ -302,6 +308,20 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
}
}
const prevSkipToolChoice = skipToolMessageToChoice(
guardrailData.litellm_params?.skip_tool_message_in_guardrail,
);
const nextSkipToolChoice = values.skip_tool_message_choice as SkipToolMessageChoice | undefined;
if (nextSkipToolChoice !== undefined && nextSkipToolChoice !== prevSkipToolChoice) {
if (nextSkipToolChoice === "inherit") {
updateData.litellm_params.skip_tool_message_in_guardrail = null;
} else if (nextSkipToolChoice === "yes") {
updateData.litellm_params.skip_tool_message_in_guardrail = true;
} else {
updateData.litellm_params.skip_tool_message_in_guardrail = false;
}
}
// Only include guardrail_info if it has changed
const originalGuardrailInfo = guardrailData.guardrail_info;
const newGuardrailInfo = values.guardrail_info ? JSON.parse(values.guardrail_info) : undefined;
@ -674,11 +694,15 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
...(() => {
const lp = { ...(guardrailData.litellm_params || {}) };
delete lp.skip_system_message_in_guardrail;
delete lp.skip_tool_message_in_guardrail;
return lp;
})(),
skip_system_message_choice: skipSystemMessageToChoice(
guardrailData.litellm_params?.skip_system_message_in_guardrail,
),
skip_tool_message_choice: skipToolMessageToChoice(
guardrailData.litellm_params?.skip_tool_message_in_guardrail,
),
guardrail_info: guardrailData.guardrail_info
? JSON.stringify(guardrailData.guardrail_info, null, 2)
: "",
@ -716,6 +740,18 @@ const GuardrailInfoView: React.FC<GuardrailInfoProps> = ({ guardrailId, onClose,
</Select>
</Form.Item>
<Form.Item
label="Skip tool messages in guardrail"
name="skip_tool_message_choice"
tooltip="Unified guardrails: omit role: tool from guardrail input (LLM still gets full messages). Use global default follows litellm_settings.skip_tool_message_in_guardrail."
>
<Select>
<Select.Option value="inherit">Use global default</Select.Option>
<Select.Option value="yes">Yes exclude from guardrail scan</Select.Option>
<Select.Option value="no">No always include in scan</Select.Option>
</Select>
</Form.Item>
{guardrailData.litellm_params?.guardrail === "presidio" && (
<>
<Divider orientation="left">PII Protection</Divider>

View File

@ -12,6 +12,8 @@ import {
GuardrailProviders,
skipSystemMessageToChoice,
choiceToSkipSystemForCreate,
skipToolMessageToChoice,
choiceToSkipToolForCreate,
} from "./guardrail_info_helpers";
describe("guardrail_info_helpers", () => {
@ -215,4 +217,18 @@ describe("guardrail_info_helpers", () => {
expect(choiceToSkipSystemForCreate("no")).toBe(false);
});
});
describe("skipToolMessageToChoice / choiceToSkipToolForCreate", () => {
it("maps API values to form choices and back for create", () => {
expect(skipToolMessageToChoice(undefined)).toBe("inherit");
expect(skipToolMessageToChoice(null)).toBe("inherit");
expect(skipToolMessageToChoice(true)).toBe("yes");
expect(skipToolMessageToChoice(false)).toBe("no");
expect(choiceToSkipToolForCreate("inherit")).toBeUndefined();
expect(choiceToSkipToolForCreate(undefined)).toBeUndefined();
expect(choiceToSkipToolForCreate("yes")).toBe(true);
expect(choiceToSkipToolForCreate("no")).toBe(false);
});
});
});

View File

@ -179,3 +179,19 @@ export function choiceToSkipSystemForCreate(choice: SkipSystemMessageChoice | un
if (choice === "no") return false;
return undefined;
}
/** Tri-state UI value for `litellm_params.skip_tool_message_in_guardrail` (inherit = use global). */
export type SkipToolMessageChoice = "inherit" | "yes" | "no";
export function skipToolMessageToChoice(v: boolean | null | undefined): SkipToolMessageChoice {
if (v === true) return "yes";
if (v === false) return "no";
return "inherit";
}
/** Create flow: omit key when inheriting global default. */
export function choiceToSkipToolForCreate(choice: SkipToolMessageChoice | undefined): boolean | undefined {
if (choice === "yes") return true;
if (choice === "no") return false;
return undefined;
}

View File

@ -11,7 +11,12 @@ import {
SortingState,
useReactTable,
} from "@tanstack/react-table";
import { getGuardrailLogoAndName, guardrail_provider_map, skipSystemMessageToChoice } from "./guardrail_info_helpers";
import {
getGuardrailLogoAndName,
guardrail_provider_map,
skipSystemMessageToChoice,
skipToolMessageToChoice,
} from "./guardrail_info_helpers";
import EditGuardrailForm from "./edit_guardrail_form";
import { Guardrail, GuardrailDefinitionLocation } from "./types";
@ -304,6 +309,9 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
skip_system_message_choice: skipSystemMessageToChoice(
selectedGuardrail.litellm_params?.skip_system_message_in_guardrail,
),
skip_tool_message_choice: skipToolMessageToChoice(
selectedGuardrail.litellm_params?.skip_tool_message_in_guardrail,
),
...selectedGuardrail.guardrail_info,
}}
/>