diff --git a/app/(main)/guardrails/page.tsx b/app/(main)/guardrails/page.tsx index 4d31775d..f126ce08 100644 --- a/app/(main)/guardrails/page.tsx +++ b/app/(main)/guardrails/page.tsx @@ -17,6 +17,7 @@ import { SavedValidatorConfig, OrgContext, } from "@/app/lib/types/guardrails"; +import { buildValidatorUpdatePayload } from "@/app/lib/utils/guardrails"; import ValidatorConfigPanel from "@/app/components/guardrails/ValidatorConfigPanel"; import SavedConfigsList from "@/app/components/guardrails/SavedConfigsList"; @@ -61,9 +62,9 @@ export default function GuardrailsPage() { setValidatorsLoading(true); guardrailsFetch<{ validators?: Validator[] }>("/api/guardrails", apiKey) .then((data) => { - const list: Validator[] = Array.isArray(data?.validators) - ? data.validators - : []; + const list: Validator[] = ( + Array.isArray(data?.validators) ? data.validators : [] + ).filter((v) => v.type !== "llm_critic"); setValidators(list); }) .catch(() => toast.error("Failed to load validators")) @@ -74,28 +75,34 @@ export default function GuardrailsPage() { ? `?organization_id=${parseInt(String(orgContext.organization_id), 10)}&project_id=${parseInt(String(orgContext.project_id), 10)}` : null; - const fetchSavedConfigs = useCallback(() => { - if (!configsQueryString) return; + const fetchSavedConfigs = useCallback(async (): Promise< + SavedValidatorConfig[] + > => { + if (!configsQueryString) return []; setSavedConfigsLoading(true); - guardrailsFetch<{ - data?: { configs?: SavedValidatorConfig[] } | SavedValidatorConfig[]; - configs?: SavedValidatorConfig[]; - }>(`/api/guardrails/validators/configs${configsQueryString}`, apiKey) - .then((data) => { - const nested = data?.data; - const list: SavedValidatorConfig[] = Array.isArray( - (nested as { configs?: SavedValidatorConfig[] })?.configs, - ) - ? (nested as { configs: SavedValidatorConfig[] }).configs - : Array.isArray(nested) - ? (nested as SavedValidatorConfig[]) - : Array.isArray(data?.configs) - ? data.configs! - : []; - setSavedConfigs(list); - }) - .catch(() => toast.error("Failed to load saved configs")) - .finally(() => setSavedConfigsLoading(false)); + try { + const data = await guardrailsFetch<{ + data?: { configs?: SavedValidatorConfig[] } | SavedValidatorConfig[]; + configs?: SavedValidatorConfig[]; + }>(`/api/guardrails/validators/configs${configsQueryString}`, apiKey); + const nested = data?.data; + const list: SavedValidatorConfig[] = Array.isArray( + (nested as { configs?: SavedValidatorConfig[] })?.configs, + ) + ? (nested as { configs: SavedValidatorConfig[] }).configs + : Array.isArray(nested) + ? (nested as SavedValidatorConfig[]) + : Array.isArray(data?.configs) + ? data.configs! + : []; + setSavedConfigs(list); + return list; + } catch { + toast.error("Failed to load saved configs"); + return []; + } finally { + setSavedConfigsLoading(false); + } }, [configsQueryString, apiKey]); useEffect(() => { @@ -150,7 +157,9 @@ export default function GuardrailsPage() { ? `${base}/${selectedSavedConfig!.id}${configsQueryString}` : `${base}${configsQueryString}`; - const body = configValues; + const body = isUpdate + ? buildValidatorUpdatePayload(configValues) + : configValues; await guardrailsFetch(url, apiKey, { method: isUpdate ? "PATCH" : "POST", @@ -159,8 +168,15 @@ export default function GuardrailsPage() { toast.success( isUpdate ? `Config "${name}" updated` : `Config "${name}" saved`, ); - fetchSavedConfigs(); - setSelectedSavedConfig(null); + const savedConfigId = selectedSavedConfig?.id; + const freshList = await fetchSavedConfigs(); + if (isUpdate && savedConfigId) { + setSelectedSavedConfig( + freshList.find((c) => c.id === savedConfigId) ?? null, + ); + } else { + setSelectedSavedConfig(null); + } } catch (e) { toast.error(e instanceof Error ? e.message : "Failed to save config"); } finally { diff --git a/app/lib/types/guardrails.ts b/app/lib/types/guardrails.ts index b493db92..a93ddfbc 100644 --- a/app/lib/types/guardrails.ts +++ b/app/lib/types/guardrails.ts @@ -62,3 +62,11 @@ export interface OrgContext { organization_id: number; project_id: number; } + +export interface ValidatorUpdatePayload { + name?: string; + type?: string; + stage?: string; + on_fail_action?: string; //todo: to consider in future if this variable should be renamed as "on" prefix makes it seems like it is a function + is_enabled?: boolean; +} diff --git a/app/lib/utils/guardrails.ts b/app/lib/utils/guardrails.ts index d3743071..7b505153 100644 --- a/app/lib/utils/guardrails.ts +++ b/app/lib/utils/guardrails.ts @@ -2,6 +2,7 @@ import { NextRequest } from "next/server"; import type { ValidatorConfigSchema, ValidatorMeta, + ValidatorUpdatePayload, } from "@/app/lib/types/guardrails"; import { VALIDATOR_META } from "@/app/lib/data/guardrails/validators"; @@ -57,3 +58,16 @@ export function buildDefaultValues( } return values; } + +export function buildValidatorUpdatePayload( + configValues: Record, +): ValidatorUpdatePayload { + const { name, type, stage, on_fail_action, is_enabled } = configValues; + return { + name: name as string, + type: type as string, + stage: stage as string, + on_fail_action: on_fail_action as string, + is_enabled: is_enabled as boolean, + }; +}