mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): i18n for guardrail params, table, LLM judge, and PII components
This commit is contained in:
parent
eccf54a990
commit
dc9c44f3b1
9 changed files with 316 additions and 91 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import { Form, Select, Typography, Input, Button } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import NumericalInput from "../shared/numerical_input";
|
||||
|
||||
const { Title } = Typography;
|
||||
|
|
@ -30,6 +31,7 @@ interface DictFieldProps {
|
|||
}
|
||||
|
||||
const DictField: React.FC<DictFieldProps> = ({ field, fieldKey, fullFieldKey, value }) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedEntries, setSelectedEntries] = React.useState<Array<{ key: string; id: string }>>([]);
|
||||
const [availableKeys, setAvailableKeys] = React.useState<string[]>(field.dict_key_options || []);
|
||||
|
||||
|
|
@ -87,19 +89,23 @@ const DictField: React.FC<DictFieldProps> = ({ field, fieldKey, fullFieldKey, va
|
|||
}
|
||||
>
|
||||
{field.dict_value_type === "number" ? (
|
||||
<NumericalInput step={1} width={200} placeholder={`Enter ${entry.key} value`} />
|
||||
<NumericalInput
|
||||
step={1}
|
||||
width={200}
|
||||
placeholder={t("guardrails.guardrailOptionalParams.enterValue", { key: entry.key })}
|
||||
/>
|
||||
) : field.dict_value_type === "boolean" ? (
|
||||
<Select placeholder={`Select ${entry.key} value`}>
|
||||
<Select placeholder={t("guardrails.guardrailOptionalParams.selectValue", { key: entry.key })}>
|
||||
<Select.Option value={true}>True</Select.Option>
|
||||
<Select.Option value={false}>False</Select.Option>
|
||||
</Select>
|
||||
) : (
|
||||
<Input placeholder={`Enter ${entry.key} value`} />
|
||||
<Input placeholder={t("guardrails.guardrailOptionalParams.enterValue", { key: entry.key })} />
|
||||
)}
|
||||
</Form.Item>
|
||||
</div>
|
||||
<Button type="text" danger size="small" onClick={() => removeEntry(entry.id, entry.key)}>
|
||||
Remove
|
||||
{t("common.remove")}
|
||||
</Button>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -108,7 +114,7 @@ const DictField: React.FC<DictFieldProps> = ({ field, fieldKey, fullFieldKey, va
|
|||
{availableKeys.length > 0 && (
|
||||
<div className="flex items-center space-x-3 mt-2">
|
||||
<Select
|
||||
placeholder="Select category to configure"
|
||||
placeholder={t("guardrails.guardrailOptionalParams.selectCategoryPlaceholder")}
|
||||
style={{ width: 200 }}
|
||||
onSelect={(value: string | undefined) => value && addEntry(value)}
|
||||
value={undefined}
|
||||
|
|
@ -119,7 +125,7 @@ const DictField: React.FC<DictFieldProps> = ({ field, fieldKey, fullFieldKey, va
|
|||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
<span className="text-sm text-gray-500">Select a category to add threshold configuration</span>
|
||||
<span className="text-sm text-gray-500">{t("guardrails.guardrailOptionalParams.selectCategoryHint")}</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -131,6 +137,8 @@ const GuardrailOptionalParams: React.FC<GuardrailOptionalParamsProps> = ({
|
|||
parentFieldKey,
|
||||
values,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const renderField = (fieldKey: string, field: ProviderParam) => {
|
||||
const fullFieldKey = `${parentFieldKey}.${fieldKey}`;
|
||||
const value = values?.[fieldKey];
|
||||
|
|
@ -156,7 +164,11 @@ const GuardrailOptionalParams: React.FC<GuardrailOptionalParamsProps> = ({
|
|||
<p className="text-sm text-gray-600 mt-1">{field.description}</p>
|
||||
</div>
|
||||
}
|
||||
rules={field.required ? [{ required: true, message: `${fieldKey} is required` }] : undefined}
|
||||
rules={
|
||||
field.required
|
||||
? [{ required: true, message: t("guardrails.guardrailOptionalParams.fieldRequired", { fieldKey }) }]
|
||||
: undefined
|
||||
}
|
||||
className="mb-0"
|
||||
initialValue={value !== undefined ? value : field.default_value}
|
||||
normalize={
|
||||
|
|
@ -210,10 +222,10 @@ const GuardrailOptionalParams: React.FC<GuardrailOptionalParamsProps> = ({
|
|||
<div className="guardrail-optional-params">
|
||||
<div className="mb-8 pb-4 border-b border-gray-100">
|
||||
<Title level={3} className="mb-2 font-semibold text-gray-900">
|
||||
Optional Parameters
|
||||
{t("guardrails.guardrailOptionalParams.title")}
|
||||
</Title>
|
||||
<p className="text-gray-600 text-sm">
|
||||
{optionalParams.description || "Configure additional settings for this guardrail provider"}
|
||||
{optionalParams.description || t("guardrails.guardrailOptionalParams.defaultDescription")}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Form, Select, Spin, Input, Slider } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
guardrail_provider_map,
|
||||
populateGuardrailProviders,
|
||||
|
|
@ -41,6 +42,7 @@ const GuardrailProviderFields: React.FC<GuardrailProviderFieldsProps> = ({
|
|||
providerParams: providerParamsProp = null,
|
||||
value = null,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [providerParams, setProviderParams] = useState<ProviderParamsResponse | null>(providerParamsProp);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
|
@ -69,7 +71,7 @@ const GuardrailProviderFields: React.FC<GuardrailProviderFieldsProps> = ({
|
|||
populateGuardrailProviderMap(data);
|
||||
} catch (error) {
|
||||
console.error("Error fetching provider params:", error);
|
||||
setError("Failed to load provider parameters");
|
||||
setError(t("guardrails.guardrailProviderFields.loadFailed"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -88,7 +90,7 @@ const GuardrailProviderFields: React.FC<GuardrailProviderFieldsProps> = ({
|
|||
|
||||
// Show loading state
|
||||
if (loading) {
|
||||
return <Spin tip="Loading provider parameters..." />;
|
||||
return <Spin tip={t("guardrails.guardrailProviderFields.loadingTip")} />;
|
||||
}
|
||||
|
||||
// Show error state
|
||||
|
|
@ -106,7 +108,7 @@ const GuardrailProviderFields: React.FC<GuardrailProviderFieldsProps> = ({
|
|||
console.log("Provider fields:", providerFields);
|
||||
|
||||
if (!providerFields || Object.keys(providerFields).length === 0) {
|
||||
return <div>No configuration fields available for this provider.</div>;
|
||||
return <div>{t("guardrails.guardrailProviderFields.noFields")}</div>;
|
||||
}
|
||||
|
||||
console.log("Value:", value);
|
||||
|
|
@ -166,7 +168,11 @@ const GuardrailProviderFields: React.FC<GuardrailProviderFieldsProps> = ({
|
|||
name={fullFieldKey}
|
||||
label={fieldKey}
|
||||
tooltip={field.description}
|
||||
rules={field.required ? [{ required: true, message: `${fieldKey} is required` }] : undefined}
|
||||
rules={
|
||||
field.required
|
||||
? [{ required: true, message: t("guardrails.guardrailProviderFields.fieldRequired", { fieldKey }) }]
|
||||
: undefined
|
||||
}
|
||||
initialValue={resolvedInitialValue}
|
||||
>
|
||||
{field.type === "select" && field.options ? (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow, Icon, Button } from "@tremor/react";
|
||||
import { TrashIcon, SwitchVerticalIcon, ChevronUpIcon, ChevronDownIcon } from "@heroicons/react/outline";
|
||||
import { Tooltip } from "antd";
|
||||
|
|
@ -39,6 +40,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
isAdmin = false,
|
||||
onGuardrailClick,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [sorting, setSorting] = useState<SortingState>([{ id: "created_at", desc: true }]);
|
||||
const [editModalVisible, setEditModalVisible] = useState(false);
|
||||
const [selectedGuardrail, setSelectedGuardrail] = useState<Guardrail | null>(null);
|
||||
|
|
@ -63,7 +65,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
|
||||
const columns: ColumnDef<Guardrail>[] = [
|
||||
{
|
||||
header: "Guardrail ID",
|
||||
header: t("guardrails.guardrailTable.colGuardrailId"),
|
||||
accessorKey: "guardrail_id",
|
||||
cell: (info: any) => (
|
||||
<Tooltip title={String(info.getValue() || "")}>
|
||||
|
|
@ -79,7 +81,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
),
|
||||
},
|
||||
{
|
||||
header: "Name",
|
||||
header: t("guardrails.guardrailTable.colName"),
|
||||
accessorKey: "guardrail_name",
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
|
|
@ -91,7 +93,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
},
|
||||
},
|
||||
{
|
||||
header: "Provider",
|
||||
header: t("guardrails.guardrailTable.colProvider"),
|
||||
accessorKey: "litellm_params.guardrail",
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
|
|
@ -115,7 +117,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
},
|
||||
},
|
||||
{
|
||||
header: "Mode",
|
||||
header: t("guardrails.guardrailTable.colMode"),
|
||||
accessorKey: "litellm_params.mode",
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
|
|
@ -123,7 +125,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
},
|
||||
},
|
||||
{
|
||||
header: "Default On",
|
||||
header: t("guardrails.guardrailTable.colDefaultOn"),
|
||||
accessorKey: "litellm_params.default_on",
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
|
|
@ -133,13 +135,15 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
className="text-xs font-normal"
|
||||
size="xs"
|
||||
>
|
||||
{guardrail.litellm_params?.default_on ? "Default On" : "Default Off"}
|
||||
{guardrail.litellm_params?.default_on
|
||||
? t("guardrails.guardrailTable.defaultOn")
|
||||
: t("guardrails.guardrailTable.defaultOff")}
|
||||
</Badge>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "Created At",
|
||||
header: t("common.createdAt"),
|
||||
accessorKey: "created_at",
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
|
|
@ -151,7 +155,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
},
|
||||
},
|
||||
{
|
||||
header: "Updated At",
|
||||
header: t("common.updatedAt"),
|
||||
accessorKey: "updated_at",
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
|
|
@ -164,31 +168,34 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
},
|
||||
{
|
||||
id: "actions",
|
||||
header: "Actions",
|
||||
header: t("common.actions"),
|
||||
cell: ({ row }) => {
|
||||
const guardrail = row.original;
|
||||
const isConfigGuardrail = guardrail.guardrail_definition_location === GuardrailDefinitionLocation.CONFIG;
|
||||
return (
|
||||
<div className="flex space-x-2">
|
||||
{isConfigGuardrail ? (
|
||||
<Tooltip title="Config guardrail cannot be deleted on the dashboard. Please delete it from the config file.">
|
||||
<Tooltip title={t("guardrails.guardrailTable.configDeleteTooltip")}>
|
||||
<Icon
|
||||
data-testid="config-delete-icon"
|
||||
icon={TrashIcon}
|
||||
size="sm"
|
||||
className="cursor-not-allowed text-gray-400"
|
||||
title="Config guardrail cannot be deleted on the dashboard. Please delete it from the config file."
|
||||
aria-label="Delete guardrail (config)"
|
||||
title={t("guardrails.guardrailTable.configDeleteTooltip")}
|
||||
aria-label={t("guardrails.guardrailTable.configDeleteAriaLabel")}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip title="Delete guardrail">
|
||||
<Tooltip title={t("guardrails.guardrailTable.deleteTooltip")}>
|
||||
<Icon
|
||||
icon={TrashIcon}
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
guardrail.guardrail_id &&
|
||||
onDeleteClick(guardrail.guardrail_id, guardrail.guardrail_name || "Unnamed Guardrail")
|
||||
onDeleteClick(
|
||||
guardrail.guardrail_id,
|
||||
guardrail.guardrail_name || t("guardrails.guardrailTable.unnamedGuardrail"),
|
||||
)
|
||||
}
|
||||
className="cursor-pointer hover:text-red-500"
|
||||
/>
|
||||
|
|
@ -254,7 +261,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-8 text-center">
|
||||
<div className="text-center text-gray-500">
|
||||
<p>Loading...</p>
|
||||
<p>{t("common.loading")}</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
@ -279,7 +286,7 @@ const GuardrailTable: React.FC<GuardrailTableProps> = ({
|
|||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-8 text-center">
|
||||
<div className="text-center text-gray-500">
|
||||
<p>No guardrails found</p>
|
||||
<p>{t("guardrails.guardrailTable.noGuardrails")}</p>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import React from "react";
|
|||
import { Form, Select, InputNumber, Input, Tooltip } from "antd";
|
||||
import { PlusOutlined, QuestionCircleOutlined } from "@ant-design/icons";
|
||||
import { Button } from "antd";
|
||||
import { useTranslation, Trans } from "react-i18next";
|
||||
|
||||
interface LLMJudgeFieldsProps {
|
||||
availableModels: string[];
|
||||
|
|
@ -11,6 +12,7 @@ interface LLMJudgeFieldsProps {
|
|||
}
|
||||
|
||||
const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
|
|
@ -24,25 +26,24 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
color: "#389e0d",
|
||||
}}
|
||||
>
|
||||
After each LLM response, the <strong>Judge Model</strong> scores it 0–100 against your criteria. If the weighted
|
||||
average falls below the threshold, the response is blocked (or logged).
|
||||
<Trans i18nKey="guardrails.lLMJudgeFields.description" components={{ strong: <strong /> }} />
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
name="judge_model"
|
||||
label={
|
||||
<span>
|
||||
Judge Model
|
||||
<Tooltip title="The LLM that reads each response and grades it. Pick a capable model — it never sees end-user data beyond what the LLM returned.">
|
||||
{t("guardrails.lLMJudgeFields.judgeModelLabel")}
|
||||
<Tooltip title={t("guardrails.lLMJudgeFields.judgeModelTooltip")}>
|
||||
<QuestionCircleOutlined style={{ color: "#8c8c8c" }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
rules={[{ required: true, message: "Select a judge model" }]}
|
||||
rules={[{ required: true, message: t("guardrails.lLMJudgeFields.judgeModelRequired") }]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
placeholder="Select a model"
|
||||
placeholder={t("guardrails.lLMJudgeFields.judgeModelPlaceholder")}
|
||||
options={availableModels.map((m) => ({ label: m, value: m }))}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
|
@ -51,8 +52,8 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
name="overall_threshold"
|
||||
label={
|
||||
<span>
|
||||
Minimum Score to Pass
|
||||
<Tooltip title="0–100. If the weighted average of criterion scores falls below this, the guardrail triggers. 80 is a good default.">
|
||||
{t("guardrails.lLMJudgeFields.minScoreLabel")}
|
||||
<Tooltip title={t("guardrails.lLMJudgeFields.minScoreTooltip")}>
|
||||
<QuestionCircleOutlined style={{ color: "#8c8c8c" }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -66,8 +67,8 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
name="on_failure"
|
||||
label={
|
||||
<span>
|
||||
On Failure
|
||||
<Tooltip title="Block: return HTTP 422 when the score is too low. Log: record the result but let the response through.">
|
||||
{t("guardrails.lLMJudgeFields.onFailureLabel")}
|
||||
<Tooltip title={t("guardrails.lLMJudgeFields.onFailureTooltip")}>
|
||||
<QuestionCircleOutlined style={{ color: "#8c8c8c" }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -75,16 +76,16 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
initialValue="block"
|
||||
>
|
||||
<Select>
|
||||
<Select.Option value="block">Block (return 422)</Select.Option>
|
||||
<Select.Option value="log">Log only</Select.Option>
|
||||
<Select.Option value="block">{t("guardrails.lLMJudgeFields.onFailureBlock")}</Select.Option>
|
||||
<Select.Option value="log">{t("guardrails.lLMJudgeFields.onFailureLog")}</Select.Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={
|
||||
<span>
|
||||
Evaluation Criteria
|
||||
<Tooltip title="Each criterion is something the judge checks. Weights must add up to 100%.">
|
||||
{t("guardrails.lLMJudgeFields.criteriaLabel")}
|
||||
<Tooltip title={t("guardrails.lLMJudgeFields.criteriaTooltip")}>
|
||||
<QuestionCircleOutlined style={{ color: "#8c8c8c" }} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
|
|
@ -107,22 +108,23 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, "name"]}
|
||||
rules={[{ required: true, message: "Enter criterion name" }]}
|
||||
rules={[{ required: true, message: t("guardrails.lLMJudgeFields.criterionNameRequired") }]}
|
||||
style={{ flex: 2, marginBottom: 8 }}
|
||||
>
|
||||
<Input placeholder="Criterion name (e.g. Policy accuracy)" />
|
||||
<Input placeholder={t("guardrails.lLMJudgeFields.criterionNamePlaceholder")} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, "weight"]}
|
||||
label={
|
||||
<Tooltip title="How much this criterion counts toward the final score. All weights must add up to 100%.">
|
||||
<Tooltip title={t("guardrails.lLMJudgeFields.weightTooltip")}>
|
||||
<span style={{ fontSize: 12, color: "#595959" }}>
|
||||
Weight <QuestionCircleOutlined style={{ color: "#bfbfbf" }} />
|
||||
{t("guardrails.lLMJudgeFields.weightLabel")}{" "}
|
||||
<QuestionCircleOutlined style={{ color: "#bfbfbf" }} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
}
|
||||
rules={[{ required: true, message: "Enter weight" }]}
|
||||
rules={[{ required: true, message: t("guardrails.lLMJudgeFields.weightRequired") }]}
|
||||
style={{ flex: 1, marginBottom: 8 }}
|
||||
>
|
||||
<InputNumber min={0} max={100} addonAfter="%" style={{ width: "100%" }} placeholder="e.g. 50" />
|
||||
|
|
@ -136,10 +138,10 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
<Form.Item
|
||||
{...restField}
|
||||
name={[name, "description"]}
|
||||
rules={[{ required: true, message: "Describe what to check" }]}
|
||||
rules={[{ required: true, message: t("guardrails.lLMJudgeFields.criterionDescRequired") }]}
|
||||
style={{ marginBottom: 8 }}
|
||||
>
|
||||
<Input placeholder="What should the judge check for this criterion?" />
|
||||
<Input placeholder={t("guardrails.lLMJudgeFields.criterionDescPlaceholder")} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -150,7 +152,7 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
onClick={() => add({ name: "", weight: 0, description: "" })}
|
||||
icon={<PlusOutlined />}
|
||||
>
|
||||
Add Criterion
|
||||
{t("guardrails.lLMJudgeFields.addCriterion")}
|
||||
</Button>
|
||||
{fields.length > 0 && (
|
||||
<Form.Item shouldUpdate noStyle>
|
||||
|
|
@ -160,7 +162,8 @@ const LLMJudgeFields: React.FC<LLMJudgeFieldsProps> = ({ availableModels, form }
|
|||
const weightOk = weightTotal === 100;
|
||||
return (
|
||||
<div style={{ marginTop: 6, fontSize: 12, color: weightOk ? "#52c41a" : "#faad14" }}>
|
||||
Weights total: {weightTotal}%{weightOk ? " ✓" : " — must add up to 100%"}
|
||||
{t("guardrails.lLMJudgeFields.weightsTotal", { weightTotal })}
|
||||
{weightOk ? " ✓" : ` — ${t("guardrails.lLMJudgeFields.weightsMustSum")}`}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from "react";
|
||||
import { Typography, Select, Button, Checkbox, Tooltip, Tag } from "antd";
|
||||
import { CloseOutlined, EyeInvisibleOutlined, StopOutlined, FilterOutlined } from "@ant-design/icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { PiiEntityCategory } from "./types";
|
||||
|
||||
const { Text } = Typography;
|
||||
|
|
@ -30,15 +31,16 @@ export interface CategoryFilterProps {
|
|||
}
|
||||
|
||||
export const CategoryFilter: React.FC<CategoryFilterProps> = ({ categories, selectedCategories, onChange }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-center mb-2">
|
||||
<FilterOutlined className="text-gray-500 mr-1" />
|
||||
<Text className="text-gray-500 font-medium">Filter by category</Text>
|
||||
<Text className="text-gray-500 font-medium">{t("guardrails.piiComponents.filterByCategory")}</Text>
|
||||
</div>
|
||||
<Select
|
||||
mode="multiple"
|
||||
placeholder="Select categories to filter by"
|
||||
placeholder={t("guardrails.piiComponents.selectCategoriesPlaceholder")}
|
||||
style={{ width: "100%" }}
|
||||
onChange={onChange}
|
||||
value={selectedCategories}
|
||||
|
|
@ -70,14 +72,15 @@ export interface QuickActionsProps {
|
|||
}
|
||||
|
||||
export const QuickActions: React.FC<QuickActionsProps> = ({ onSelectAll, onUnselectAll, hasSelectedEntities }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="bg-gray-50 p-5 rounded-lg mb-6 border border-gray-200 shadow-sm">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center">
|
||||
<Text strong className="text-gray-700 text-base">
|
||||
Quick Actions
|
||||
{t("guardrails.piiComponents.quickActions")}
|
||||
</Text>
|
||||
<Tooltip title="Apply action to all PII types at once">
|
||||
<Tooltip title={t("guardrails.piiComponents.quickActionsTooltip")}>
|
||||
<div className="ml-2 text-gray-400 cursor-help text-xs">ⓘ</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
@ -88,7 +91,7 @@ export const QuickActions: React.FC<QuickActionsProps> = ({ onSelectAll, onUnsel
|
|||
disabled={!hasSelectedEntities}
|
||||
icon={<CloseOutlined />}
|
||||
>
|
||||
Unselect All
|
||||
{t("guardrails.piiComponents.unselectAll")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
|
|
@ -100,7 +103,7 @@ export const QuickActions: React.FC<QuickActionsProps> = ({ onSelectAll, onUnsel
|
|||
block
|
||||
icon={<EyeInvisibleOutlined />}
|
||||
>
|
||||
Select All & Mask
|
||||
{t("guardrails.piiComponents.selectAllMask")}
|
||||
</Button>
|
||||
<Button
|
||||
color="danger"
|
||||
|
|
@ -110,7 +113,7 @@ export const QuickActions: React.FC<QuickActionsProps> = ({ onSelectAll, onUnsel
|
|||
block
|
||||
icon={<StopOutlined />}
|
||||
>
|
||||
Select All & Block
|
||||
{t("guardrails.piiComponents.selectAllBlock")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -137,19 +140,20 @@ export const PiiEntityList: React.FC<PiiEntityListProps> = ({
|
|||
onActionSelect,
|
||||
entityToCategoryMap,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="border rounded-lg overflow-hidden shadow-sm">
|
||||
<div className="bg-gray-50 px-5 py-3 border-b flex">
|
||||
<Text strong className="flex-1 text-gray-700">
|
||||
PII Type
|
||||
{t("guardrails.piiComponents.piiTypeHeader")}
|
||||
</Text>
|
||||
<Text strong className="w-32 text-right text-gray-700">
|
||||
Action
|
||||
{t("guardrails.piiComponents.actionHeader")}
|
||||
</Text>
|
||||
</div>
|
||||
<div className="max-h-[400px] overflow-y-auto">
|
||||
{entities.length === 0 ? (
|
||||
<div className="py-10 text-center text-gray-500">No PII types match your filter criteria</div>
|
||||
<div className="py-10 text-center text-gray-500">{t("guardrails.piiComponents.noMatch")}</div>
|
||||
) : (
|
||||
entities.map((entity) => (
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Typography } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { CategoryFilter, PiiEntityList, QuickActions } from "./pii_components";
|
||||
import { PiiConfigurationProps } from "./types";
|
||||
|
||||
|
|
@ -18,6 +19,7 @@ const PiiConfiguration: React.FC<PiiConfigurationProps> = ({
|
|||
onActionSelect,
|
||||
entityCategories = [],
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
|
||||
|
||||
// Create a lookup map to quickly find an entity's category
|
||||
|
|
@ -58,10 +60,12 @@ const PiiConfiguration: React.FC<PiiConfigurationProps> = ({
|
|||
<div className="flex justify-between items-center mb-5">
|
||||
<div className="flex items-center">
|
||||
<Title level={4} className="!m-0 font-semibold text-gray-800">
|
||||
Configure PII Protection
|
||||
{t("guardrails.piiConfiguration.title")}
|
||||
</Title>
|
||||
</div>
|
||||
<Text className="text-gray-500">{selectedEntities.length} items selected</Text>
|
||||
<Text className="text-gray-500">
|
||||
{t("guardrails.piiConfiguration.itemsSelected", { count: selectedEntities.length })}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className="mb-6">
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from "react";
|
|||
import { Card, Text } from "@tremor/react";
|
||||
import { Button, Divider, Empty, Input, Select, Space, Tooltip } from "antd";
|
||||
import { InfoCircleOutlined, PlusOutlined, DeleteOutlined } from "@ant-design/icons";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export type ToolPermissionDecision = "allow" | "deny";
|
||||
export type ToolPermissionDefaultAction = "allow" | "deny";
|
||||
|
|
@ -42,6 +43,7 @@ const ensureConfig = (config?: ToolPermissionConfig): ToolPermissionConfig => ({
|
|||
});
|
||||
|
||||
const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ value, onChange, disabled = false }) => {
|
||||
const { t } = useTranslation();
|
||||
const config = ensureConfig(value);
|
||||
|
||||
const updateConfig = (partial: Partial<ToolPermissionConfig>) => {
|
||||
|
|
@ -119,14 +121,14 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
size="small"
|
||||
onClick={() => updateRule(index, { allowed_param_patterns: { "": "" } })}
|
||||
>
|
||||
+ Restrict tool arguments (optional)
|
||||
{t("guardrails.toolPermissionRulesEditor.restrictArgs")}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Text className="text-sm text-gray-600">Argument constraints (dot or array paths)</Text>
|
||||
<Text className="text-sm text-gray-600">{t("guardrails.toolPermissionRulesEditor.argConstraints")}</Text>
|
||||
{entries.map(([path, pattern], patternIndex) => (
|
||||
<Space key={`${rule.id || index}-${patternIndex}`} align="start">
|
||||
<Input
|
||||
|
|
@ -165,7 +167,7 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
})
|
||||
}
|
||||
>
|
||||
+ Add another constraint
|
||||
{t("guardrails.toolPermissionRulesEditor.addConstraint")}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -175,11 +177,8 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
<Card>
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<Text className="text-lg font-semibold">LiteLLM Tool Permission Guardrail</Text>
|
||||
<Text className="text-sm text-gray-500">
|
||||
Provide regex patterns (e.g., ^mcp__github_.*$) for tool names or types and optionally constrain payload
|
||||
fields.
|
||||
</Text>
|
||||
<Text className="text-lg font-semibold">{t("guardrails.toolPermissionRulesEditor.title")}</Text>
|
||||
<Text className="text-sm text-gray-500">{t("guardrails.toolPermissionRulesEditor.subtitle")}</Text>
|
||||
</div>
|
||||
{!disabled && (
|
||||
<Button
|
||||
|
|
@ -188,7 +187,7 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
onClick={addRule}
|
||||
className="!bg-blue-600 !text-white hover:!bg-blue-500"
|
||||
>
|
||||
Add Rule
|
||||
{t("guardrails.toolPermissionRulesEditor.addRule")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -196,13 +195,15 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
<Divider />
|
||||
|
||||
{config.rules.length === 0 ? (
|
||||
<Empty description="No tool rules added yet" />
|
||||
<Empty description={t("guardrails.toolPermissionRulesEditor.noRules")} />
|
||||
) : (
|
||||
<div className="space-y-4">
|
||||
{config.rules.map((rule, index) => (
|
||||
<Card key={rule.id || index} className="bg-gray-50">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<Text className="font-semibold">Rule {index + 1}</Text>
|
||||
<Text className="font-semibold">
|
||||
{t("guardrails.toolPermissionRulesEditor.ruleLabel", { index: index + 1 })}
|
||||
</Text>
|
||||
<Button
|
||||
icon={<DeleteOutlined />}
|
||||
danger
|
||||
|
|
@ -210,12 +211,12 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
disabled={disabled}
|
||||
onClick={() => removeRule(index)}
|
||||
>
|
||||
Remove
|
||||
{t("common.remove")}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<Text className="text-sm font-medium">Rule ID</Text>
|
||||
<Text className="text-sm font-medium">{t("guardrails.toolPermissionRulesEditor.ruleId")}</Text>
|
||||
<Input
|
||||
disabled={disabled}
|
||||
placeholder="unique_rule_id"
|
||||
|
|
@ -224,7 +225,7 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-sm font-medium">Tool Name (optional)</Text>
|
||||
<Text className="text-sm font-medium">{t("guardrails.toolPermissionRulesEditor.toolName")}</Text>
|
||||
<Input
|
||||
disabled={disabled}
|
||||
placeholder="^mcp__github_.*$"
|
||||
|
|
@ -240,7 +241,7 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 mt-4">
|
||||
<div>
|
||||
<Text className="text-sm font-medium">Tool Type (optional)</Text>
|
||||
<Text className="text-sm font-medium">{t("guardrails.toolPermissionRulesEditor.toolType")}</Text>
|
||||
<Input
|
||||
disabled={disabled}
|
||||
placeholder="^function$"
|
||||
|
|
@ -255,15 +256,15 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
</div>
|
||||
|
||||
<div className="mt-4 flex flex-col gap-2">
|
||||
<Text className="text-sm font-medium">Decision</Text>
|
||||
<Text className="text-sm font-medium">{t("guardrails.toolPermissionRulesEditor.decision")}</Text>
|
||||
<Select
|
||||
disabled={disabled}
|
||||
value={rule.decision}
|
||||
style={{ width: 200 }}
|
||||
onChange={(value) => updateRule(index, { decision: value as ToolPermissionDecision })}
|
||||
>
|
||||
<Select.Option value="allow">Allow</Select.Option>
|
||||
<Select.Option value="deny">Deny</Select.Option>
|
||||
<Select.Option value="allow">{t("guardrails.toolPermissionRulesEditor.allow")}</Select.Option>
|
||||
<Select.Option value="deny">{t("guardrails.toolPermissionRulesEditor.deny")}</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
|
|
@ -277,20 +278,20 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
|
||||
<div className="grid gap-4 md:grid-cols-2">
|
||||
<div>
|
||||
<Text className="text-sm font-medium">Default action</Text>
|
||||
<Text className="text-sm font-medium">{t("guardrails.toolPermissionRulesEditor.defaultAction")}</Text>
|
||||
<Select
|
||||
disabled={disabled}
|
||||
value={config.default_action}
|
||||
onChange={(value) => updateConfig({ default_action: value as ToolPermissionDefaultAction })}
|
||||
>
|
||||
<Select.Option value="allow">Allow</Select.Option>
|
||||
<Select.Option value="deny">Deny</Select.Option>
|
||||
<Select.Option value="allow">{t("guardrails.toolPermissionRulesEditor.allow")}</Select.Option>
|
||||
<Select.Option value="deny">{t("guardrails.toolPermissionRulesEditor.deny")}</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Text className="text-sm font-medium flex items-center gap-1">
|
||||
On disallowed action
|
||||
<Tooltip title="Block returns an error when a forbidden tool is invoked. Rewrite strips the tool call but lets the rest of the response continue.">
|
||||
{t("guardrails.toolPermissionRulesEditor.onDisallowedAction")}
|
||||
<Tooltip title={t("guardrails.toolPermissionRulesEditor.onDisallowedTooltip")}>
|
||||
<InfoCircleOutlined />
|
||||
</Tooltip>
|
||||
</Text>
|
||||
|
|
@ -299,18 +300,18 @@ const ToolPermissionRulesEditor: React.FC<ToolPermissionRulesEditorProps> = ({ v
|
|||
value={config.on_disallowed_action}
|
||||
onChange={(value) => updateConfig({ on_disallowed_action: value as ToolPermissionOnDisallowedAction })}
|
||||
>
|
||||
<Select.Option value="block">Block</Select.Option>
|
||||
<Select.Option value="rewrite">Rewrite</Select.Option>
|
||||
<Select.Option value="block">{t("guardrails.toolPermissionRulesEditor.block")}</Select.Option>
|
||||
<Select.Option value="rewrite">{t("guardrails.toolPermissionRulesEditor.rewrite")}</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<Text className="text-sm font-medium">Violation message (optional)</Text>
|
||||
<Text className="text-sm font-medium">{t("guardrails.toolPermissionRulesEditor.violationMessage")}</Text>
|
||||
<Input.TextArea
|
||||
disabled={disabled}
|
||||
rows={3}
|
||||
placeholder="This violates our org policy..."
|
||||
placeholder={t("guardrails.toolPermissionRulesEditor.violationMessagePlaceholder")}
|
||||
value={config.violation_message_template}
|
||||
onChange={(e) => updateConfig({ violation_message_template: e.target.value })}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1365,6 +1365,100 @@
|
|||
"addAtLeastOneRule": "Add at least one tool permission rule",
|
||||
"createSuccess": "Guardrail created successfully",
|
||||
"createFailed": "Failed to create guardrail: {{error}}"
|
||||
},
|
||||
"guardrailOptionalParams": {
|
||||
"title": "Optional Parameters",
|
||||
"defaultDescription": "Configure additional settings for this guardrail provider",
|
||||
"enterValue": "Enter {{key}} value",
|
||||
"selectValue": "Select {{key}} value",
|
||||
"selectCategoryPlaceholder": "Select category to configure",
|
||||
"selectCategoryHint": "Select a category to add threshold configuration",
|
||||
"fieldRequired": "{{fieldKey}} is required"
|
||||
},
|
||||
"guardrailProviderFields": {
|
||||
"loadFailed": "Failed to load provider parameters",
|
||||
"loadingTip": "Loading provider parameters...",
|
||||
"noFields": "No configuration fields available for this provider.",
|
||||
"fieldRequired": "{{fieldKey}} is required"
|
||||
},
|
||||
"guardrailTable": {
|
||||
"colGuardrailId": "Guardrail ID",
|
||||
"colName": "Name",
|
||||
"colProvider": "Provider",
|
||||
"colMode": "Mode",
|
||||
"colDefaultOn": "Default On",
|
||||
"defaultOn": "Default On",
|
||||
"defaultOff": "Default Off",
|
||||
"deleteTooltip": "Delete guardrail",
|
||||
"configDeleteTooltip": "Config guardrail cannot be deleted on the dashboard. Please delete it from the config file.",
|
||||
"configDeleteAriaLabel": "Delete guardrail (config)",
|
||||
"unnamedGuardrail": "Unnamed Guardrail",
|
||||
"noGuardrails": "No guardrails found"
|
||||
},
|
||||
"lLMJudgeFields": {
|
||||
"description": "After each LLM response, the <strong>Judge Model</strong> scores it 0–100 against your criteria. If the weighted average falls below the threshold, the response is blocked (or logged).",
|
||||
"judgeModelLabel": "Judge Model",
|
||||
"judgeModelTooltip": "The LLM that reads each response and grades it. Pick a capable model — it never sees end-user data beyond what the LLM returned.",
|
||||
"judgeModelRequired": "Select a judge model",
|
||||
"judgeModelPlaceholder": "Select a model",
|
||||
"minScoreLabel": "Minimum Score to Pass",
|
||||
"minScoreTooltip": "0–100. If the weighted average of criterion scores falls below this, the guardrail triggers. 80 is a good default.",
|
||||
"onFailureLabel": "On Failure",
|
||||
"onFailureTooltip": "Block: return HTTP 422 when the score is too low. Log: record the result but let the response through.",
|
||||
"onFailureBlock": "Block (return 422)",
|
||||
"onFailureLog": "Log only",
|
||||
"criteriaLabel": "Evaluation Criteria",
|
||||
"criteriaTooltip": "Each criterion is something the judge checks. Weights must add up to 100%.",
|
||||
"criterionNameRequired": "Enter criterion name",
|
||||
"criterionNamePlaceholder": "Criterion name (e.g. Policy accuracy)",
|
||||
"weightLabel": "Weight",
|
||||
"weightTooltip": "How much this criterion counts toward the final score. All weights must add up to 100%.",
|
||||
"weightRequired": "Enter weight",
|
||||
"criterionDescRequired": "Describe what to check",
|
||||
"criterionDescPlaceholder": "What should the judge check for this criterion?",
|
||||
"addCriterion": "Add Criterion",
|
||||
"weightsTotal": "Weights total: {{weightTotal}}%",
|
||||
"weightsMustSum": "must add up to 100%"
|
||||
},
|
||||
"piiComponents": {
|
||||
"filterByCategory": "Filter by category",
|
||||
"selectCategoriesPlaceholder": "Select categories to filter by",
|
||||
"quickActions": "Quick Actions",
|
||||
"quickActionsTooltip": "Apply action to all PII types at once",
|
||||
"unselectAll": "Unselect All",
|
||||
"selectAllMask": "Select All & Mask",
|
||||
"selectAllBlock": "Select All & Block",
|
||||
"piiTypeHeader": "PII Type",
|
||||
"actionHeader": "Action",
|
||||
"noMatch": "No PII types match your filter criteria"
|
||||
},
|
||||
"piiConfiguration": {
|
||||
"title": "Configure PII Protection",
|
||||
"itemsSelected_one": "{{count}} item selected",
|
||||
"itemsSelected_other": "{{count}} items selected"
|
||||
},
|
||||
"toolPermissionRulesEditor": {
|
||||
"title": "LiteLLM Tool Permission Guardrail",
|
||||
"subtitle": "Provide regex patterns (e.g., ^mcp__github_.*$) for tool names or types and optionally constrain payload fields.",
|
||||
"addRule": "Add Rule",
|
||||
"noRules": "No tool rules added yet",
|
||||
"ruleLabel": "Rule {{index}}",
|
||||
"ruleId": "Rule ID",
|
||||
"toolName": "Tool Name (optional)",
|
||||
"toolType": "Tool Type (optional)",
|
||||
"decision": "Decision",
|
||||
"allow": "Allow",
|
||||
"deny": "Deny",
|
||||
"restrictArgs": "+ Restrict tool arguments (optional)",
|
||||
"argConstraints": "Argument constraints (dot or array paths)",
|
||||
"addConstraint": "+ Add another constraint",
|
||||
"defaultAction": "Default action",
|
||||
"onDisallowedAction": "On disallowed action",
|
||||
"onDisallowedTooltip": "Block returns an error when a forbidden tool is invoked. Rewrite strips the tool call but lets the rest of the response continue.",
|
||||
"block": "Block",
|
||||
"rewrite": "Rewrite",
|
||||
"violationMessage": "Violation message (optional)",
|
||||
"violationMessagePlaceholder": "This violates our org policy..."
|
||||
}
|
||||
},
|
||||
"keyValueInput": {
|
||||
|
|
|
|||
|
|
@ -1365,6 +1365,100 @@
|
|||
"addAtLeastOneRule": "请至少添加一条工具权限规则",
|
||||
"createSuccess": "护栏创建成功",
|
||||
"createFailed": "创建护栏失败:{{error}}"
|
||||
},
|
||||
"guardrailOptionalParams": {
|
||||
"title": "可选参数",
|
||||
"defaultDescription": "为此护栏提供商配置附加设置",
|
||||
"enterValue": "输入 {{key}} 的值",
|
||||
"selectValue": "选择 {{key}} 的值",
|
||||
"selectCategoryPlaceholder": "选择要配置的类别",
|
||||
"selectCategoryHint": "选择类别以添加阈值配置",
|
||||
"fieldRequired": "{{fieldKey}} 为必填项"
|
||||
},
|
||||
"guardrailProviderFields": {
|
||||
"loadFailed": "加载提供商参数失败",
|
||||
"loadingTip": "正在加载提供商参数...",
|
||||
"noFields": "此提供商暂无可配置字段。",
|
||||
"fieldRequired": "{{fieldKey}} 为必填项"
|
||||
},
|
||||
"guardrailTable": {
|
||||
"colGuardrailId": "护栏 ID",
|
||||
"colName": "名称",
|
||||
"colProvider": "提供商",
|
||||
"colMode": "模式",
|
||||
"colDefaultOn": "默认启用",
|
||||
"defaultOn": "默认启用",
|
||||
"defaultOff": "默认关闭",
|
||||
"deleteTooltip": "删除护栏",
|
||||
"configDeleteTooltip": "配置文件中的护栏无法在仪表盘上删除,请从配置文件中删除。",
|
||||
"configDeleteAriaLabel": "删除护栏(配置文件)",
|
||||
"unnamedGuardrail": "未命名护栏",
|
||||
"noGuardrails": "未找到护栏"
|
||||
},
|
||||
"lLMJudgeFields": {
|
||||
"description": "每次 LLM 响应后,<strong>Judge Model</strong> 会根据您的标准对其评分(0–100)。若加权平均分低于阈值,响应将被拦截(或记录)。",
|
||||
"judgeModelLabel": "Judge Model",
|
||||
"judgeModelTooltip": "读取每条响应并评分的 LLM。请选择能力较强的模型——它仅能看到 LLM 返回的内容,不会接触最终用户数据。",
|
||||
"judgeModelRequired": "请选择 Judge Model",
|
||||
"judgeModelPlaceholder": "选择模型",
|
||||
"minScoreLabel": "最低通过分数",
|
||||
"minScoreTooltip": "0–100。若标准分数的加权平均值低于此值,护栏将触发。建议默认值为 80。",
|
||||
"onFailureLabel": "失败时的处理",
|
||||
"onFailureTooltip": "拦截:分数过低时返回 HTTP 422。仅记录:记录结果但允许响应通过。",
|
||||
"onFailureBlock": "拦截(返回 422)",
|
||||
"onFailureLog": "仅记录",
|
||||
"criteriaLabel": "评估标准",
|
||||
"criteriaTooltip": "每个标准是 Judge 需要检查的一项内容,权重之和必须为 100%。",
|
||||
"criterionNameRequired": "请输入标准名称",
|
||||
"criterionNamePlaceholder": "标准名称(例如:策略准确性)",
|
||||
"weightLabel": "权重",
|
||||
"weightTooltip": "此标准在最终分数中所占的比重,所有权重之和必须为 100%。",
|
||||
"weightRequired": "请输入权重",
|
||||
"criterionDescRequired": "请描述要检查的内容",
|
||||
"criterionDescPlaceholder": "Judge 应针对此标准检查什么?",
|
||||
"addCriterion": "添加标准",
|
||||
"weightsTotal": "权重合计:{{weightTotal}}%",
|
||||
"weightsMustSum": "必须合计为 100%"
|
||||
},
|
||||
"piiComponents": {
|
||||
"filterByCategory": "按类别筛选",
|
||||
"selectCategoriesPlaceholder": "选择要筛选的类别",
|
||||
"quickActions": "快速操作",
|
||||
"quickActionsTooltip": "一次性对所有 PII 类型应用操作",
|
||||
"unselectAll": "取消全选",
|
||||
"selectAllMask": "全选并脱敏",
|
||||
"selectAllBlock": "全选并拦截",
|
||||
"piiTypeHeader": "PII 类型",
|
||||
"actionHeader": "操作",
|
||||
"noMatch": "没有 PII 类型匹配您的筛选条件"
|
||||
},
|
||||
"piiConfiguration": {
|
||||
"title": "配置 PII 保护",
|
||||
"itemsSelected_one": "已选择 {{count}} 项",
|
||||
"itemsSelected_other": "已选择 {{count}} 项"
|
||||
},
|
||||
"toolPermissionRulesEditor": {
|
||||
"title": "LiteLLM 工具权限护栏",
|
||||
"subtitle": "为工具名称或类型提供正则表达式模式(例如 ^mcp__github_.*$),并可选择性地约束载荷字段。",
|
||||
"addRule": "添加规则",
|
||||
"noRules": "尚未添加工具规则",
|
||||
"ruleLabel": "规则 {{index}}",
|
||||
"ruleId": "规则 ID",
|
||||
"toolName": "工具名称(可选)",
|
||||
"toolType": "工具类型(可选)",
|
||||
"decision": "决策",
|
||||
"allow": "允许",
|
||||
"deny": "拒绝",
|
||||
"restrictArgs": "+ 限制工具参数(可选)",
|
||||
"argConstraints": "参数约束(点路径或数组路径)",
|
||||
"addConstraint": "+ 添加另一个约束",
|
||||
"defaultAction": "默认动作",
|
||||
"onDisallowedAction": "禁止时的处理",
|
||||
"onDisallowedTooltip": "拦截:调用被禁止工具时返回错误。改写:去除工具调用但允许响应的其余部分继续。",
|
||||
"block": "拦截",
|
||||
"rewrite": "改写",
|
||||
"violationMessage": "违规消息(可选)",
|
||||
"violationMessagePlaceholder": "这违反了我们的组织策略..."
|
||||
}
|
||||
},
|
||||
"keyValueInput": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue