diff --git a/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx b/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx
index 67948a075cd..379270aba82 100644
--- a/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx
+++ b/ui/litellm-dashboard/src/components/policies/template_parameter_modal.tsx
@@ -39,6 +39,9 @@ const TemplateParameterModal: React.FC = ({
const [competitorTags, setCompetitorTags] = useState([]);
const [variationsMap, setVariationsMap] = useState>({});
const [isGenerating, setIsGenerating] = useState(false);
+ const [refinementInput, setRefinementInput] = useState("");
+ const [isRefining, setIsRefining] = useState(false);
+ const [hasGenerated, setHasGenerated] = useState(false);
const parameters: TemplateParameter[] = template?.parameters || [];
const hasEnrichment = !!template?.llm_enrichment;
@@ -60,6 +63,9 @@ const TemplateParameterModal: React.FC = ({
setCompetitorTags([]);
setVariationsMap({});
setIsGenerating(false);
+ setRefinementInput("");
+ setIsRefining(false);
+ setHasGenerated(false);
}
}, [visible, template]);
@@ -108,6 +114,7 @@ const TemplateParameterModal: React.FC = ({
setCompetitorTags(result.competitors);
setVariationsMap(result.competitor_variations || {});
setIsGenerating(false);
+ setHasGenerated(true);
},
(error) => {
console.error("Streaming error:", error);
@@ -120,6 +127,43 @@ const TemplateParameterModal: React.FC = ({
}
};
+ const handleRefine = async () => {
+ if (!accessToken || !selectedModel || !template || !refinementInput.trim()) return;
+
+ setIsRefining(true);
+ try {
+ await enrichPolicyTemplateStream(
+ accessToken,
+ template.id,
+ parameterValues,
+ selectedModel,
+ (name) => {
+ setCompetitorTags((prev) => {
+ if (prev.some((t) => t.toLowerCase() === name.toLowerCase())) return prev;
+ return [...prev, name];
+ });
+ },
+ (result) => {
+ setCompetitorTags(result.competitors);
+ setVariationsMap(result.competitor_variations || {});
+ setIsRefining(false);
+ setRefinementInput("");
+ },
+ (error) => {
+ console.error("Refinement error:", error);
+ setIsRefining(false);
+ },
+ {
+ instruction: refinementInput.trim(),
+ existingCompetitors: competitorTags,
+ }
+ );
+ } catch (error) {
+ console.error("Error refining competitor names:", error);
+ setIsRefining(false);
+ }
+ };
+
const allNonEnrichmentFilled = nonEnrichmentParams
.filter((p) => p.required)
.every((p) => (parameterValues[p.name] || "").trim().length > 0);
@@ -284,6 +328,39 @@ const TemplateParameterModal: React.FC = ({
)}
+
+ {/* Refinement input — shown after initial generation in AI mode */}
+ {competitorMode === "ai" && hasGenerated && competitorTags.length > 0 && (
+
+
+
+ setRefinementInput(e.target.value)}
+ onKeyDown={(e) => {
+ if (e.key === "Enter" && refinementInput.trim() && !isRefining) {
+ handleRefine();
+ }
+ }}
+ disabled={isRefining}
+ />
+
+
+
+ Give instructions to add, remove, or change competitors. Press Enter to send.
+
+
+ )}
>
)}