From 3a004d05d62642fe67352f40268b9bc7cb40d4a5 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 18 Feb 2026 19:56:06 -0800 Subject: [PATCH] add streaming enrichPolicyTemplate networking function --- .../src/components/networking.tsx | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/ui/litellm-dashboard/src/components/networking.tsx b/ui/litellm-dashboard/src/components/networking.tsx index 9d9ff575c8c..2c76cd36f09 100644 --- a/ui/litellm-dashboard/src/components/networking.tsx +++ b/ui/litellm-dashboard/src/components/networking.tsx @@ -5555,19 +5555,24 @@ export const getPolicyTemplates = async (accessToken: string) => { export const enrichPolicyTemplate = async ( accessToken: string, templateId: string, - parameters: Record + parameters: Record, + model?: string, + competitors?: string[] ) => { try { const url = proxyBaseUrl ? `${proxyBaseUrl}/policy/templates/enrich` : `/policy/templates/enrich`; + const body: any = { template_id: templateId, parameters }; + if (model) body.model = model; + if (competitors) body.competitors = competitors; const response = await fetch(url, { method: "POST", headers: { [globalLitellmHeaderName]: `Bearer ${accessToken}`, "Content-Type": "application/json", }, - body: JSON.stringify({ template_id: templateId, parameters }), + body: JSON.stringify(body), }); if (!response.ok) { @@ -5585,6 +5590,72 @@ export const enrichPolicyTemplate = async ( } }; +export const enrichPolicyTemplateStream = async ( + accessToken: string, + templateId: string, + parameters: Record, + model: string, + onCompetitor: (name: string) => void, + onDone: (result: { + competitors: string[]; + competitor_variations: Record; + guardrailDefinitions: any[]; + }) => void, + onError?: (error: string) => void +) => { + const url = proxyBaseUrl + ? `${proxyBaseUrl}/policy/templates/enrich/stream` + : `/policy/templates/enrich/stream`; + const body: any = { template_id: templateId, parameters, model }; + + const response = await fetch(url, { + method: "POST", + headers: { + [globalLitellmHeaderName]: `Bearer ${accessToken}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + if (!response.ok) { + const errorData = await response.json(); + const errorMessage = deriveErrorMessage(errorData); + handleError(errorMessage); + throw new Error(errorMessage); + } + + const reader = response.body?.getReader(); + if (!reader) throw new Error("No response body"); + + const decoder = new TextDecoder(); + let buffer = ""; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + + buffer += decoder.decode(value, { stream: true }); + const lines = buffer.split("\n"); + buffer = lines.pop() || ""; + + for (const line of lines) { + if (!line.startsWith("data: ")) continue; + try { + const event = JSON.parse(line.slice(6)); + if (event.type === "competitor") { + onCompetitor(event.name); + } else if (event.type === "done") { + onDone(event); + } else if (event.type === "error") { + onError?.(event.message); + } + } catch { + // skip malformed events + } + } + } +}; + export const createPolicyCall = async (accessToken: string, policyData: any) => { try { const url = proxyBaseUrl ? `${proxyBaseUrl}/policies` : `/policies`;