From 464887cc179f143c40e052c8dfec99d2cbdf2d58 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 9 Mar 2026 03:56:26 +0530
Subject: [PATCH 01/13] Evals UI: fixing score and config display

---
 app/api/evaluations/[id]/route.ts             |   3 +-
 app/components/ConfigModal.tsx                | 170 ++++++++++--------
 app/components/ConfigSelector.tsx             | 140 ++++++++++-----
 app/components/ScoreDisplay.tsx               |  59 +++---
 .../prompt-editor/ConfigEditorPane.tsx        |  71 +++++++-
 app/evaluations/[id]/page.tsx                 |  95 +++++++++-
 app/lib/useConfigs.ts                         |  16 +-
 7 files changed, 391 insertions(+), 163 deletions(-)

diff --git a/app/api/evaluations/[id]/route.ts b/app/api/evaluations/[id]/route.ts
index bdf4fc5..98961ad 100644
--- a/app/api/evaluations/[id]/route.ts
+++ b/app/api/evaluations/[id]/route.ts
@@ -53,11 +53,12 @@ export async function GET(
 
     const searchParams = request.nextUrl.searchParams;
     const exportFormat = searchParams.get('export_format') || 'row';
+    const resyncScore = searchParams.get('resync_score') || 'false';
 
     // Build URL with query parameters
     const url = new URL(`${backendUrl}/api/v1/evaluations/${id}`);
     url.searchParams.set('get_trace_info', 'true');
-    url.searchParams.set('resync_score', 'false');
+    url.searchParams.set('resync_score', resyncScore);
     url.searchParams.set('export_format', exportFormat);
 
     console.log(`[REAL BACKEND] Fetching evaluation ${id} from ${url.toString()}`);
diff --git a/app/components/ConfigModal.tsx b/app/components/ConfigModal.tsx
index 15b0269..1e98b7f 100644
--- a/app/components/ConfigModal.tsx
+++ b/app/components/ConfigModal.tsx
@@ -23,6 +23,7 @@ interface ConfigVersionInfo {
   tools?: any[];
   provider?: string;
   type?: 'text' | 'stt' | 'tts';
+  knowledge_base_ids?: string[];
 }
 
 export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: ConfigModalProps) {
@@ -83,6 +84,25 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
           const blob = versionData.data.config_blob;
           const params = blob?.completion?.params || {};
 
+          // Extract knowledge base IDs from multiple sources
+          const knowledgeBaseIds: string[] = [];
+
+          // 1. Check direct params.knowledge_base_ids
+          if (Array.isArray(params.knowledge_base_ids)) {
+            knowledgeBaseIds.push(...params.knowledge_base_ids);
+          }
+
+          // 2. Check tools array for knowledge_base_ids
+          if (params.tools) {
+            const toolKbIds = params.tools
+              .filter((tool: any) => Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0)
+              .flatMap((tool: any) => tool.knowledge_base_ids);
+            knowledgeBaseIds.push(...toolKbIds);
+          }
+
+          // Remove duplicates
+          const uniqueKbIds = [...new Set(knowledgeBaseIds)];
+
           setConfigVersionInfo({
             name: configName || 'Unknown Config',
             version: job.config_version!,
@@ -92,6 +112,7 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
             tools: params.tools,
             provider: blob?.completion?.provider,
             type: blob?.completion?.type || 'text',
+            knowledge_base_ids: uniqueKbIds.length > 0 ? uniqueKbIds : undefined,
           });
         }
       } catch (error) {
@@ -124,13 +145,16 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
       >
         {/* Header */}
         <div className="px-6 py-4 border-b" style={{ borderColor: '#e5e5e5' }}>
-          <div className="flex items-center justify-between mb-3">
+          <div className="flex items-center justify-between">
             <div className="flex items-center gap-2">
               <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: '#737373' }}>
                 <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
                 <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
               </svg>
-              <h3 className="text-lg font-semibold" style={{ color: '#171717' }}>Detailed Configuration</h3>
+              <h3 className="text-lg font-semibold" style={{ color: '#171717' }}>
+                {configVersionInfo?.name || 'Detailed Configuration'}
+                {configVersionInfo?.version && <span className="text-sm font-normal" style={{ color: '#737373' }}> v{configVersionInfo.version}</span>}
+              </h3>
             </div>
             <button
               onClick={onClose}
@@ -154,47 +178,6 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
               </svg>
             </button>
           </div>
-
-          {/* Config Name and Version */}
-          {job.config_id && job.config_version && (
-            <div className="mt-2 px-4 py-3 rounded-lg" style={{ backgroundColor: '#f0f9ff', borderWidth: '1px', borderColor: '#bae6fd' }}>
-              {isLoadingConfig ? (
-                <div className="text-sm" style={{ color: '#0369a1' }}>Loading config info...</div>
-              ) : configVersionInfo ? (
-                <div>
-                  <div className="flex items-center gap-2 mb-2">
-                    <svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: '#0369a1' }}>
-                      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
-                    </svg>
-                    <span className="text-sm font-semibold" style={{ color: '#0369a1' }}>
-                      {configVersionInfo.name} <span className="font-normal">v{configVersionInfo.version}</span>
-                    </span>
-                  </div>
-                  <div className="text-xs ml-6 space-y-1" style={{ color: '#0369a1' }}>
-                    {configVersionInfo.provider && configVersionInfo.model && (
-                      <div>
-                        <span className="font-medium">Model:</span> {configVersionInfo.provider}/{configVersionInfo.model}
-                      </div>
-                    )}
-                    {configVersionInfo.type && (
-                      <div>
-                        <span className="font-medium">Type:</span> {configVersionInfo.type.toUpperCase()}
-                      </div>
-                    )}
-                    {configVersionInfo.temperature !== undefined && (
-                      <div>
-                        <span className="font-medium">Temperature:</span> {configVersionInfo.temperature}
-                      </div>
-                    )}
-                  </div>
-                </div>
-              ) : (
-                <div className="text-sm" style={{ color: '#0369a1' }}>
-                  Config ID: {job.config_id} (v{job.config_version})
-                </div>
-              )}
-            </div>
-          )}
         </div>
 
         {/* Content */}
@@ -220,6 +203,19 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
             </div>
           </div>
 
+          {configVersionInfo?.knowledge_base_ids && configVersionInfo.knowledge_base_ids.length > 0 && (
+            <div>
+              <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#737373' }}>Knowledge Base IDs</div>
+              <div className="text-sm font-mono p-3 rounded-md border mb-4" style={{
+                backgroundColor: '#fafafa',
+                borderColor: '#e5e5e5',
+                color: '#171717'
+              }}>
+                {configVersionInfo.knowledge_base_ids.join(', ')}
+              </div>
+            </div>
+          )}
+
           {(configVersionInfo?.temperature !== undefined || assistantConfig?.temperature !== undefined || job.config?.temperature !== undefined) && (
             <div>
               <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#737373' }}>Temperature</div>
@@ -258,7 +254,7 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
                       backgroundColor: '#fafafa',
                       borderWidth: '1px',
                       borderColor: '#e5e5e5',
-                      color: '#171717'
+                      color: '#000000'
                     }}
                   >
                     {tool.type}
@@ -266,20 +262,36 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
                 ))}
               </div>
               {configVersionInfo.tools.map((tool, idx) => (
-                Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0 && (
-                  <div key={`vs-${idx}`} className="mb-4">
-                    <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#737373' }}>
-                      Vector Store IDs ({tool.type})
+                <div key={`tool-details-${idx}`}>
+                  {Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0 && (
+                    <div className="mb-3">
+                      <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>
+                        Vector Store IDs ({tool.type})
+                      </div>
+                      <div className="text-sm font-mono p-3 rounded-md border" style={{
+                        backgroundColor: '#fafafa',
+                        borderColor: '#e5e5e5',
+                        color: '#171717'
+                      }}>
+                        {tool.knowledge_base_ids.join(', ')}
+                      </div>
                     </div>
-                    <div className="text-sm font-mono p-3 rounded-md border" style={{
-                      backgroundColor: '#fafafa',
-                      borderColor: '#e5e5e5',
-                      color: '#171717'
-                    }}>
-                      {tool.knowledge_base_ids.join(', ')}
+                  )}
+                  {tool.max_num_results !== undefined && (
+                    <div className="mb-4">
+                      <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>
+                        Max Results ({tool.type})
+                      </div>
+                      <div className="text-sm font-mono p-3 rounded-md border" style={{
+                        backgroundColor: '#fafafa',
+                        borderColor: '#e5e5e5',
+                        color: '#171717'
+                      }}>
+                        {tool.max_num_results}
+                      </div>
                     </div>
-                  </div>
-                )
+                  )}
+                </div>
               ))}
             </div>
           )}
@@ -296,7 +308,7 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
                       backgroundColor: '#fafafa',
                       borderWidth: '1px',
                       borderColor: '#e5e5e5',
-                      color: '#171717'
+                      color: '#000000'
                     }}
                   >
                     {tool.type}
@@ -304,27 +316,43 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
                 ))}
               </div>
               {job.config.tools.map((tool, idx) => (
-                Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0 && (
-                  <div key={`vs-${idx}`} className="mb-4">
-                    <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#737373' }}>
-                      Vector Store IDs ({tool.type})
+                <div key={`tool-details-${idx}`}>
+                  {Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0 && (
+                    <div className="mb-3">
+                      <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>
+                        Vector Store IDs ({tool.type})
+                      </div>
+                      <div className="text-sm font-mono p-3 rounded-md border" style={{
+                        backgroundColor: '#fafafa',
+                        borderColor: '#e5e5e5',
+                        color: '#171717'
+                      }}>
+                        {tool.knowledge_base_ids.join(', ')}
+                      </div>
                     </div>
-                    <div className="text-sm font-mono p-3 rounded-md border" style={{
-                      backgroundColor: '#fafafa',
-                      borderColor: '#e5e5e5',
-                      color: '#171717'
-                    }}>
-                      {tool.knowledge_base_ids.join(', ')}
+                  )}
+                  {tool.max_num_results !== undefined && (
+                    <div className="mb-4">
+                      <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>
+                        Max Results ({tool.type})
+                      </div>
+                      <div className="text-sm font-mono p-3 rounded-md border" style={{
+                        backgroundColor: '#fafafa',
+                        borderColor: '#e5e5e5',
+                        color: '#171717'
+                      }}>
+                        {tool.max_num_results}
+                      </div>
                     </div>
-                  </div>
-                )
+                  )}
+                </div>
               ))}
             </div>
           )}
 
           {Array.isArray(assistantConfig?.knowledge_base_ids) && assistantConfig.knowledge_base_ids.length > 0 && (
             <div>
-              <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#737373' }}>Vector Store IDs</div>
+              <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>Vector Store IDs</div>
               <div className="text-sm font-mono p-3 rounded-md border" style={{
                 backgroundColor: '#fafafa',
                 borderColor: '#e5e5e5',
@@ -377,4 +405,4 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
       </div>
     </div>
   );
-}
+}
\ No newline at end of file
diff --git a/app/components/ConfigSelector.tsx b/app/components/ConfigSelector.tsx
index 84f9263..e0c7893 100644
--- a/app/components/ConfigSelector.tsx
+++ b/app/components/ConfigSelector.tsx
@@ -4,7 +4,7 @@
  */
 
 "use client"
-import React, { useState, useEffect } from 'react';
+import { useState } from 'react';
 import { useRouter } from 'next/navigation';
 import { colors } from '@/app/lib/colors';
 import { useConfigs, SavedConfig, formatRelativeTime } from '@/app/lib/useConfigs';
@@ -30,16 +30,31 @@ export default function ConfigSelector({
   const router = useRouter();
   const { configs, configGroups, isLoading, error } = useConfigs();
   const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+  const [searchQuery, setSearchQuery] = useState('');
 
   // Find currently selected config
   const selectedConfig = configs.find(
     c => c.config_id === selectedConfigId && c.version === selectedVersion
   );
 
+  // Filter config groups based on search query
+  const filteredConfigGroups = searchQuery.trim()
+    ? configGroups.filter(group =>
+        group.name.toLowerCase().includes(searchQuery.toLowerCase())
+      )
+    : configGroups;
+
   // Handle config selection
   const handleSelect = (config: SavedConfig) => {
     onConfigSelect(config.config_id, config.version);
     setIsDropdownOpen(false);
+    setSearchQuery(''); // Clear search on selection
+  };
+
+  // Handle dropdown close
+  const handleCloseDropdown = () => {
+    setIsDropdownOpen(false);
+    setSearchQuery(''); // Clear search on close
   };
 
   // Build URL params preserving evaluation context
@@ -204,48 +219,82 @@ export default function ConfigSelector({
         <>
           {/* Dropdown Selector */}
           <div className="relative">
-            <button
-              onClick={() => !disabled && setIsDropdownOpen(!isDropdownOpen)}
-              disabled={disabled}
-              className="w-full px-4 py-3 rounded-md text-left flex items-center justify-between transition-colors"
-              style={{
-                backgroundColor: disabled ? colors.bg.secondary : colors.bg.primary,
-                border: `1px solid ${selectedConfig ? colors.accent.primary : colors.border}`,
-                color: colors.text.primary,
-                cursor: disabled ? 'not-allowed' : 'pointer',
-              }}
-            >
-              {selectedConfig ? (
-                <div className="flex-1 min-w-0">
-                  <div className="flex items-center gap-2">
-                    <span className="font-medium truncate">{selectedConfig.name}</span>
-                    <span
-                      className="text-xs px-1.5 py-0.5 rounded"
-                      style={{ backgroundColor: colors.bg.secondary, color: colors.text.secondary }}
-                    >
-                      v{selectedConfig.version}
-                    </span>
-                  </div>
-                  <div className="text-xs mt-0.5" style={{ color: colors.text.secondary }}>
-                    {selectedConfig.provider}/{selectedConfig.modelName} • T:{selectedConfig.temperature.toFixed(2)}
-                  </div>
-                </div>
-              ) : (
-                <span style={{ color: colors.text.secondary }}>Select a configuration...</span>
-              )}
-              <svg
-                className="w-5 h-5 flex-shrink-0 ml-2 transition-transform"
+            {isDropdownOpen ? (
+              /* Search Input when dropdown is open */
+              <div
+                className="w-full px-4 py-3 rounded-md flex items-center justify-between"
+                style={{
+                  backgroundColor: colors.bg.primary,
+                  border: `1px solid ${colors.accent.primary}`,
+                }}
+              >
+                <input
+                  type="text"
+                  value={searchQuery}
+                  onChange={(e) => setSearchQuery(e.target.value)}
+                  placeholder="Search configurations..."
+                  className="flex-1 bg-transparent text-sm focus:outline-none"
+                  style={{ color: colors.text.primary }}
+                  autoFocus
+                />
+                <svg
+                  className="w-5 h-5 flex-shrink-0 ml-2 transition-transform"
+                  style={{
+                    color: colors.text.secondary,
+                    transform: 'rotate(180deg)'
+                  }}
+                  fill="none"
+                  viewBox="0 0 24 24"
+                  stroke="currentColor"
+                >
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
+                </svg>
+              </div>
+            ) : (
+              /* Button when dropdown is closed */
+              <button
+                onClick={() => !disabled && setIsDropdownOpen(!isDropdownOpen)}
+                disabled={disabled}
+                className="w-full px-4 py-3 rounded-md text-left flex items-center justify-between transition-colors"
                 style={{
-                  color: colors.text.secondary,
-                  transform: isDropdownOpen ? 'rotate(180deg)' : 'rotate(0deg)'
+                  backgroundColor: disabled ? colors.bg.secondary : colors.bg.primary,
+                  border: `1px solid ${selectedConfig ? colors.accent.primary : colors.border}`,
+                  color: colors.text.primary,
+                  cursor: disabled ? 'not-allowed' : 'pointer',
                 }}
-                fill="none"
-                viewBox="0 0 24 24"
-                stroke="currentColor"
               >
-                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
-              </svg>
-            </button>
+                {selectedConfig ? (
+                  <div className="flex-1 min-w-0">
+                    <div className="flex items-center gap-2">
+                      <span className="font-medium truncate">{selectedConfig.name}</span>
+                      <span
+                        className="text-xs px-1.5 py-0.5 rounded"
+                        style={{ backgroundColor: colors.bg.secondary, color: colors.text.secondary }}
+                      >
+                        v{selectedConfig.version}
+                      </span>
+                    </div>
+                    <div className="text-xs mt-0.5" style={{ color: colors.text.secondary }}>
+                      {selectedConfig.provider}/{selectedConfig.modelName} • T:{selectedConfig.temperature.toFixed(2)}
+                    </div>
+                  </div>
+                ) : (
+                  <span style={{ color: colors.text.secondary }}>Select a configuration...</span>
+                )}
+                <svg
+                  className="w-5 h-5 flex-shrink-0 ml-2 transition-transform"
+                  style={{
+                    color: colors.text.secondary,
+                    transform: 'rotate(0deg)'
+                  }}
+                  fill="none"
+                  viewBox="0 0 24 24"
+                  stroke="currentColor"
+                >
+                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
+                </svg>
+              </button>
+            )}
 
             {/* Dropdown Menu */}
             {isDropdownOpen && (
@@ -256,7 +305,12 @@ export default function ConfigSelector({
                   border: `1px solid ${colors.border}`,
                 }}
               >
-                {configGroups.map((group) => (
+                {filteredConfigGroups.length === 0 ? (
+                  <div className="px-4 py-6 text-center text-sm" style={{ color: colors.text.secondary }}>
+                    {searchQuery ? `No configurations match "${searchQuery}"` : 'No configurations available'}
+                  </div>
+                ) : (
+                  filteredConfigGroups.map((group) => (
                   <div key={group.config_id}>
                     {/* Config group header */}
                     <div
@@ -309,7 +363,7 @@ export default function ConfigSelector({
                       </button>
                     ))}
                   </div>
-                ))}
+                )))}
               </div>
             )}
           </div>
@@ -381,7 +435,7 @@ export default function ConfigSelector({
       {isDropdownOpen && (
         <div
           className="fixed inset-0 z-40"
-          onClick={() => setIsDropdownOpen(false)}
+          onClick={handleCloseDropdown}
         />
       )}
     </div>
diff --git a/app/components/ScoreDisplay.tsx b/app/components/ScoreDisplay.tsx
index cbefccf..a3d4f9b 100644
--- a/app/components/ScoreDisplay.tsx
+++ b/app/components/ScoreDisplay.tsx
@@ -5,7 +5,7 @@
 
 "use client"
 import React from 'react';
-import { ScoreObject, isNewScoreObject, isNewScoreObjectV2 } from './types';
+import { ScoreObject } from './types';
 
 interface ScoreDisplayProps {
   score: ScoreObject | null;
@@ -36,10 +36,8 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
     );
   }
 
-  // Handle new score format (V1 or V2) - show summary scores
-  const isNewFormat = isNewScoreObject(score) || isNewScoreObjectV2(score);
-
-  if (isNewFormat && 'summary_scores' in score) {
+  // Handle score format with summary_scores
+  if ('summary_scores' in score) {
     const summaryScores = score.summary_scores || [];
 
     if (summaryScores.length === 0) {
@@ -81,33 +79,32 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
       );
     }
 
-    // Display numeric scores in a compact format
+    // Display each numeric score in its own box
     return (
-      <div className="inline-flex items-center gap-3 flex-wrap">
-        {numericScores.map((summary) => (
-          <div
-            key={summary.name}
-            className="inline-flex items-center gap-2 px-3 py-1.5 rounded-md text-sm"
-            style={{
-              backgroundColor: 'hsl(0, 0%, 98%)',
-              borderWidth: '1px',
-              borderColor: 'hsl(0, 0%, 85%)',
-              color: 'hsl(330, 3%, 19%)'
-            }}
-          >
-            <span className="font-medium text-xs" style={{ color: 'hsl(330, 3%, 49%)' }}>
-              {summary.name}:
-            </span>
-            <span className="font-semibold">
-              {summary.avg !== undefined ? summary.avg.toFixed(2) : 'N/A'}
-            </span>
-            {summary.std !== undefined && (
-              <span className="text-xs" style={{ color: 'hsl(330, 3%, 49%)' }}>
-                ±{summary.std.toFixed(2)}
-              </span>
-            )}
-          </div>
-        ))}
+      <div className="inline-flex items-center gap-3">
+        {numericScores.map((summary, idx) => {
+          const value = summary.avg !== undefined ? summary.avg.toFixed(2) : 'N/A';
+          const std = summary.std !== undefined ? summary.std.toFixed(2) : null;
+
+          return (
+            <div
+              key={idx}
+              className="inline-flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm"
+              style={{
+                backgroundColor: '#ffffff',
+                borderWidth: '1px',
+                borderColor: '#e5e5e5',
+                color: '#737373'
+              }}
+            >
+              <span>{summary.name}:</span>
+              <span className="font-bold" style={{ color: '#171717' }}>{value}</span>
+              {std !== null && (
+                <span>±{std}</span>
+              )}
+            </div>
+          );
+        })}
       </div>
     );
   }
diff --git a/app/components/prompt-editor/ConfigEditorPane.tsx b/app/components/prompt-editor/ConfigEditorPane.tsx
index d63e2e6..ce4d23a 100644
--- a/app/components/prompt-editor/ConfigEditorPane.tsx
+++ b/app/components/prompt-editor/ConfigEditorPane.tsx
@@ -66,6 +66,7 @@ export default function ConfigEditorPane({
   onToggle,
 }: ConfigEditorPaneProps) {
   const [isDropdownOpen, setIsDropdownOpen] = useState(false);
+  const [showTooltip, setShowTooltip] = useState<number | null>(null);
 
   const provider = configBlob.completion.provider;
   const params = configBlob.completion.params;
@@ -587,7 +588,7 @@ export default function ConfigEditorPane({
                 }}
               >
                 <div className="flex justify-between items-center mb-2">
-                  <span className="text-xs font-semibold">File Search</span>
+                  <span className="text-xs font-semibold" style={{ color: '#000000' }}>File Search</span>
                   <button
                     onClick={() => handleRemoveTool(index)}
                     className="text-xs"
@@ -604,7 +605,7 @@ export default function ConfigEditorPane({
                 <div className="mb-2">
                   <label
                     className="block text-xs mb-1"
-                    style={{ color: colors.text.secondary }}
+                    style={{ color: '#000000' }}
                   >
                     Vector Store ID
                   </label>
@@ -619,16 +620,69 @@ export default function ConfigEditorPane({
                     style={{
                       border: `1px solid ${colors.border}`,
                       backgroundColor: colors.bg.primary,
+                      color: colors.text.primary,
                     }}
                   />
                 </div>
                 <div>
-                  <label
-                    className="block text-xs mb-1"
-                    style={{ color: colors.text.secondary }}
-                  >
-                    Max Results
-                  </label>
+                  <div className="flex items-center gap-1 mb-1">
+                    <label
+                      className="text-xs"
+                      style={{ color: '#000000' }}
+                    >
+                      Max Results
+                    </label>
+                    <div
+                      className="relative inline-flex items-center justify-center cursor-help"
+                      style={{ width: '14px', height: '14px' }}
+                      onMouseEnter={() => setShowTooltip(index)}
+                      onMouseLeave={() => setShowTooltip(null)}
+                    >
+                      <svg
+                        className="w-3.5 h-3.5"
+                        fill="none"
+                        viewBox="0 0 24 24"
+                        stroke="currentColor"
+                        style={{ color: colors.text.secondary }}
+                      >
+                        <path
+                          strokeLinecap="round"
+                          strokeLinejoin="round"
+                          strokeWidth={2}
+                          d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
+                        />
+                      </svg>
+                      {showTooltip === index && (
+                        <div
+                          className="absolute left-full ml-2 px-2 py-1.5 rounded text-xs z-50"
+                          style={{
+                            backgroundColor: '#1f2937',
+                            color: '#ffffff',
+                            top: '50%',
+                            transform: 'translateY(-50%)',
+                            boxShadow: '0 2px 8px rgba(0, 0, 0, 0.15)',
+                            whiteSpace: 'nowrap',
+                            lineHeight: '1.4',
+                          }}
+                        >
+                          Controls how many matching results are returned<br />from the search
+                          <div
+                            style={{
+                              position: 'absolute',
+                              right: '100%',
+                              top: '50%',
+                              transform: 'translateY(-50%)',
+                              width: 0,
+                              height: 0,
+                              borderTop: '4px solid transparent',
+                              borderBottom: '4px solid transparent',
+                              borderRight: '4px solid #1f2937',
+                            }}
+                          />
+                        </div>
+                      )}
+                    </div>
+                  </div>
                   <input
                     type="number"
                     value={tool.max_num_results}
@@ -643,6 +697,7 @@ export default function ConfigEditorPane({
                     style={{
                       border: `1px solid ${colors.border}`,
                       backgroundColor: colors.bg.primary,
+                      color: colors.text.primary,
                     }}
                   />
                 </div>
diff --git a/app/evaluations/[id]/page.tsx b/app/evaluations/[id]/page.tsx
index 3844142..596e29b 100644
--- a/app/evaluations/[id]/page.tsx
+++ b/app/evaluations/[id]/page.tsx
@@ -42,7 +42,7 @@ export default function EvaluationReport() {
   const [isConfigModalOpen, setIsConfigModalOpen] = useState(false);
   const [configVersionInfo, setConfigVersionInfo] = useState<ConfigVersionInfo | null>(null);
   const [exportFormat, setExportFormat] = useState<'row' | 'grouped'>('row');
-  
+  const [isResyncing, setIsResyncing] = useState(false);
 
   // Load API keys from localStorage
   useEffect(() => {
@@ -358,6 +358,57 @@ export default function EvaluationReport() {
     }
   };
 
+  // Resync metrics from backend
+  const handleResync = async () => {
+    if (!selectedKeyId || !jobId) return;
+
+    const selectedKey = apiKeys.find(k => k.id === selectedKeyId);
+    if (!selectedKey) return;
+
+    setIsResyncing(true);
+
+    try {
+      // Fetch with resync_score=true to trigger backend resync
+      const response = await fetch(`/api/evaluations/${jobId}?export_format=${exportFormat}&resync_score=true&get_trace_info=true`, {
+        method: 'GET',
+        headers: {
+          'X-API-KEY': selectedKey.key,
+        },
+      });
+
+      if (!response.ok) {
+        const errorData = await response.json().catch(() => ({}));
+        throw new Error(errorData.error || errorData.message || `Failed to resync: ${response.status}`);
+      }
+
+      const data = await response.json();
+      const foundJob = data.data || data;
+
+      if (!foundJob) {
+        throw new Error('Evaluation job not found');
+      }
+
+      setJob(foundJob);
+
+      // Fetch assistant config if assistant_id exists
+      if (foundJob.assistant_id) {
+        fetchAssistantConfig(foundJob.assistant_id, selectedKey.key);
+      }
+
+      // Fetch config info if config_id exists
+      if (foundJob.config_id && foundJob.config_version) {
+        fetchConfigInfo(foundJob.config_id, foundJob.config_version, selectedKey.key);
+      }
+
+      toast.success('Metrics resynced successfully');
+    } catch (error: any) {
+      console.error('Resync error:', error);
+      toast.error(`Failed to resync metrics: ${error.message || 'Unknown error'}`);
+    } finally {
+      setIsResyncing(false);
+    }
+  };
+
 
   if (isLoading) {
     return (
@@ -512,6 +563,16 @@ export default function EvaluationReport() {
                               {configVersionInfo.provider}/{configVersionInfo.model}
                             </span>
                           )}
+                          {configVersionInfo.tools && configVersionInfo.tools.length > 0 && (() => {
+                            const knowledgeBaseIds = configVersionInfo.tools
+                              .filter(tool => Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0)
+                              .flatMap(tool => tool.knowledge_base_ids);
+                            return knowledgeBaseIds.length > 0 ? (
+                              <span className="text-[10px]" style={{ color: '#0369a1', opacity: 0.8 }}>
+                                KB: {knowledgeBaseIds.join(', ')}
+                              </span>
+                            ) : null;
+                          })()}
                         </div>
                       </div>
                     </>
@@ -638,11 +699,33 @@ export default function EvaluationReport() {
               {/* Metrics Section */}
               {hasScore && isNewFormat ? (
                 <div>
-                  <div className="flex items-center gap-2 mb-3">
-                    <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: colors.text.secondary }}>
-                      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
-                    </svg>
-                    <h3 className="text-lg font-semibold" style={{ color: colors.text.primary }}>Metrics Overview</h3>
+                  <div className="flex items-center justify-between mb-3">
+                    <div className="flex items-center gap-2">
+                      <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: colors.text.secondary }}>
+                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M16 8v8m-4-5v5m-4-2v2m-2 4h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
+                      </svg>
+                      <h3 className="text-lg font-semibold" style={{ color: colors.text.primary }}>Metrics Overview</h3>
+                    </div>
+                    <button
+                      onClick={handleResync}
+                      disabled={isResyncing}
+                      className="px-4 py-2 rounded-md text-sm font-medium transition-colors"
+                      style={{
+                        backgroundColor: isResyncing ? colors.bg.secondary : colors.bg.primary,
+                        borderWidth: '1px',
+                        borderColor: colors.border,
+                        color: isResyncing ? colors.text.secondary : colors.text.primary,
+                        cursor: isResyncing ? 'not-allowed' : 'pointer'
+                      }}
+                      onMouseEnter={(e) => {
+                        if (!isResyncing) e.currentTarget.style.backgroundColor = colors.bg.secondary;
+                      }}
+                      onMouseLeave={(e) => {
+                        if (!isResyncing) e.currentTarget.style.backgroundColor = colors.bg.primary;
+                      }}
+                    >
+                      {isResyncing ? 'Resyncing...' : 'Resync'}
+                    </button>
                   </div>
                   <div className="border rounded-lg p-6" style={{ backgroundColor: colors.bg.primary, borderColor: colors.border }}>
                     {summaryScores.length > 0 ? (
diff --git a/app/lib/useConfigs.ts b/app/lib/useConfigs.ts
index 0e74044..6ec6a9b 100644
--- a/app/lib/useConfigs.ts
+++ b/app/lib/useConfigs.ts
@@ -455,11 +455,21 @@ async function fetchAllConfigs(apiKey: string): Promise<FetchResult> {
 // ============ UTILITY FUNCTIONS ============
 
 // Format timestamp as relative time
+// Handles UTC timestamps from the database and converts them to local time
 export const formatRelativeTime = (timestamp: string | number): string => {
   const now = Date.now();
-  const date = typeof timestamp === 'string'
-    ? new Date(timestamp).getTime()
-    : timestamp;
+
+  let date: number;
+  if (typeof timestamp === 'string') {
+    // If timestamp doesn't include timezone info, assume it's UTC
+    // and append 'Z' to ensure it's interpreted as UTC
+    const utcTimestamp = timestamp.endsWith('Z') || timestamp.includes('+') || timestamp.includes('T') && timestamp.split('T')[1].includes('-')
+      ? timestamp
+      : timestamp + 'Z';
+    date = new Date(utcTimestamp).getTime();
+  } else {
+    date = timestamp;
+  }
 
   const diff = now - date;
   const minutes = Math.floor(diff / 60000);

From da559ec84619ad7fb137e9291a7ad3552fd40b98 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 9 Mar 2026 11:51:11 +0530
Subject: [PATCH 02/13] score display fix

---
 app/components/ScoreDisplay.tsx | 61 +++++++++++++++++----------------
 app/components/types.ts         | 14 +++++++-
 2 files changed, 45 insertions(+), 30 deletions(-)

diff --git a/app/components/ScoreDisplay.tsx b/app/components/ScoreDisplay.tsx
index a3d4f9b..3ceedc8 100644
--- a/app/components/ScoreDisplay.tsx
+++ b/app/components/ScoreDisplay.tsx
@@ -5,7 +5,7 @@
 
 "use client"
 import React from 'react';
-import { ScoreObject } from './types';
+import { ScoreObject, isNewScoreObject, isNewScoreObjectV2, isBasicScoreObject } from './types';
 
 interface ScoreDisplayProps {
   score: ScoreObject | null;
@@ -36,8 +36,10 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
     );
   }
 
-  // Handle score format with summary_scores
-  if ('summary_scores' in score) {
+  // Handle new score format (V1 or V2) - show summary scores
+  const isNewFormat = (isNewScoreObject(score) || isNewScoreObjectV2(score) || isBasicScoreObject(score));
+
+  if (isNewFormat && 'summary_scores' in score) {
     const summaryScores = score.summary_scores || [];
 
     if (summaryScores.length === 0) {
@@ -79,32 +81,33 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
       );
     }
 
-    // Display each numeric score in its own box
+    // Display numeric scores in a compact format
     return (
-      <div className="inline-flex items-center gap-3">
-        {numericScores.map((summary, idx) => {
-          const value = summary.avg !== undefined ? summary.avg.toFixed(2) : 'N/A';
-          const std = summary.std !== undefined ? summary.std.toFixed(2) : null;
-
-          return (
-            <div
-              key={idx}
-              className="inline-flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm"
-              style={{
-                backgroundColor: '#ffffff',
-                borderWidth: '1px',
-                borderColor: '#e5e5e5',
-                color: '#737373'
-              }}
-            >
-              <span>{summary.name}:</span>
-              <span className="font-bold" style={{ color: '#171717' }}>{value}</span>
-              {std !== null && (
-                <span>±{std}</span>
-              )}
-            </div>
-          );
-        })}
+      <div className="inline-flex items-center gap-3 flex-wrap">
+        {numericScores.map((summary) => (
+          <div
+            key={summary.name}
+            className="inline-flex items-center gap-2 px-3 py-1.5 rounded-md text-sm"
+            style={{
+              backgroundColor: 'hsl(0, 0%, 98%)',
+              borderWidth: '1px',
+              borderColor: 'hsl(0, 0%, 85%)',
+              color: 'hsl(330, 3%, 19%)'
+            }}
+          >
+            <span className="font-medium text-xs" style={{ color: 'hsl(330, 3%, 49%)' }}>
+              {summary.name}:
+            </span>
+            <span className="font-semibold">
+              {summary.avg !== undefined ? summary.avg.toFixed(2) : 'N/A'}
+            </span>
+            {summary.std !== undefined && (
+              <span className="text-xs" style={{ color: 'hsl(330, 3%, 49%)' }}>
+                ±{summary.std.toFixed(2)}
+              </span>
+            )}
+          </div>
+        ))}
       </div>
     );
   }
@@ -124,4 +127,4 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
       <span>Unsupported format</span>
     </div>
   );
-}
+}
\ No newline at end of file
diff --git a/app/components/types.ts b/app/components/types.ts
index bfae124..eccb8be 100644
--- a/app/components/types.ts
+++ b/app/components/types.ts
@@ -67,6 +67,11 @@ export interface NewScoreObject {
   individual_scores: IndividualScore[];
 }
 
+// Basic score object with only summary scores (no individual scores or traces)
+export interface BasicScoreObject {
+  summary_scores: SummaryScore[];
+}
+
 // Legacy score structure (for backward compatibility)
 export interface PerItemScore {
   trace_id: string;
@@ -85,7 +90,7 @@ export interface LegacyScoreObject {
 }
 
 // Union type to support both old and new structures
-export type ScoreObject = NewScoreObjectV2 | NewScoreObject | LegacyScoreObject;
+export type ScoreObject = NewScoreObjectV2 | NewScoreObject | BasicScoreObject | LegacyScoreObject;
 
 export interface AssistantConfig {
   name: string;
@@ -140,11 +145,18 @@ export function isNewScoreObjectV2(score: ScoreObject | null | undefined): score
   return 'summary_scores' in score && 'traces' in score;
 }
 
+// V1 with individual_scores
 export function isNewScoreObject(score: ScoreObject | null | undefined): score is NewScoreObject {
   if (!score) return false;
   return 'summary_scores' in score && 'individual_scores' in score;
 }
 
+// NEW: Fallback for scores with only summary_scores
+export function isBasicScoreObject(score: ScoreObject | null | undefined): score is BasicScoreObject {
+  if (!score) return false;
+  return 'summary_scores' in score && !('individual_scores' in score) && !('traces' in score);
+}
+
 export function isLegacyScoreObject(score: ScoreObject | null | undefined): score is LegacyScoreObject {
   if (!score) return false;
   return 'cosine_similarity' in score;

From 067ea27ebae2b742831576820f77ded57ec901f9 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 9 Mar 2026 11:52:21 +0530
Subject: [PATCH 03/13] removing un-needed words from comment

---
 app/components/types.ts | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/components/types.ts b/app/components/types.ts
index eccb8be..0d6de10 100644
--- a/app/components/types.ts
+++ b/app/components/types.ts
@@ -140,6 +140,7 @@ export interface EvalJob {
 }
 
 // Type guard functions
+// V2 with traces
 export function isNewScoreObjectV2(score: ScoreObject | null | undefined): score is NewScoreObjectV2 {
   if (!score) return false;
   return 'summary_scores' in score && 'traces' in score;
@@ -151,7 +152,7 @@ export function isNewScoreObject(score: ScoreObject | null | undefined): score i
   return 'summary_scores' in score && 'individual_scores' in score;
 }
 
-// NEW: Fallback for scores with only summary_scores
+// Fallback for scores with only summary_scores
 export function isBasicScoreObject(score: ScoreObject | null | undefined): score is BasicScoreObject {
   if (!score) return false;
   return 'summary_scores' in score && !('individual_scores' in score) && !('traces' in score);

From 99a46103e0208dea8850e0fc3b3e60829228d182 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 9 Mar 2026 15:05:26 +0530
Subject: [PATCH 04/13] coderabbit review

---
 app/components/DetailedResultsTable.tsx | 21 ++++---
 app/components/ScoreDisplay.tsx         | 59 +++++++++----------
 app/components/types.ts                 | 77 ++++++++++++++-----------
 app/evaluations/[id]/page.tsx           | 10 ++--
 4 files changed, 90 insertions(+), 77 deletions(-)

diff --git a/app/components/DetailedResultsTable.tsx b/app/components/DetailedResultsTable.tsx
index e63c66d..8b7f7ef 100644
--- a/app/components/DetailedResultsTable.tsx
+++ b/app/components/DetailedResultsTable.tsx
@@ -5,7 +5,7 @@
  * Supports both row format (individual traces) and grouped format (multiple answers per question)
  */
 
-import { IndividualScore, TraceScore, getScoreObject, normalizeToIndividualScores, isNewScoreObject, isNewScoreObjectV2, isGroupedFormat, GroupedTraceItem } from './types';
+import { IndividualScore, TraceScore, getScoreObject, normalizeToIndividualScores, hasSummaryScores, isNewScoreObjectV2, isGroupedFormat, GroupedTraceItem } from './types';
 import { EvalJob } from './types';
 
 interface DetailedResultsTableProps {
@@ -15,7 +15,8 @@ interface DetailedResultsTableProps {
 export default function DetailedResultsTable({ job }: DetailedResultsTableProps) {
   const scoreObject = getScoreObject(job);
 
-  if (!scoreObject || (!isNewScoreObject(scoreObject) && !isNewScoreObjectV2(scoreObject))) {
+  // 1. First check: Does it have summary_scores at all?
+  if (!scoreObject || !hasSummaryScores(scoreObject)) {
     return (
       <div className="border rounded-lg p-6 text-center" style={{ backgroundColor: '#fef3c7', borderColor: '#fbbf24' }}>
         <p className="text-sm" style={{ color: '#92400e' }}>
@@ -25,19 +26,25 @@ export default function DetailedResultsTable({ job }: DetailedResultsTableProps)
     );
   }
 
-  // Check if grouped format
-  if (isNewScoreObjectV2(scoreObject) && isGroupedFormat(scoreObject.traces)) {
-    return <GroupedResultsTable traces={scoreObject.traces as GroupedTraceItem[]} />;
+  // 2. Second check: Does it have traces? (NewScoreObjectV2)
+  if (isNewScoreObjectV2(scoreObject)) {
+    // Check if grouped format
+    if (isGroupedFormat(scoreObject.traces)) {
+      return <GroupedResultsTable traces={scoreObject.traces as GroupedTraceItem[]} />;
+    }
+    // Otherwise show row format
   }
 
-  // Normalize to IndividualScore format for backward compatibility
+  // 3. Try to normalize to IndividualScore format
+  // This handles NewScoreObjectV2 (with traces)
   const individual_scores = normalizeToIndividualScores(scoreObject);
 
+  // 4. If no individual scores available (e.g., BasicScoreObject with only summary_scores)
   if (!individual_scores || individual_scores.length === 0) {
     return (
       <div className="border rounded-lg p-6 text-center" style={{ backgroundColor: '#fef3c7', borderColor: '#fbbf24' }}>
         <p className="text-sm" style={{ color: '#92400e' }}>
-          No individual scores available
+          No individual scores available. Only summary metrics are available for this evaluation.
         </p>
       </div>
     );
diff --git a/app/components/ScoreDisplay.tsx b/app/components/ScoreDisplay.tsx
index 3ceedc8..8299e0f 100644
--- a/app/components/ScoreDisplay.tsx
+++ b/app/components/ScoreDisplay.tsx
@@ -5,7 +5,7 @@
 
 "use client"
 import React from 'react';
-import { ScoreObject, isNewScoreObject, isNewScoreObjectV2, isBasicScoreObject } from './types';
+import { ScoreObject, hasSummaryScores } from './types';
 
 interface ScoreDisplayProps {
   score: ScoreObject | null;
@@ -36,10 +36,8 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
     );
   }
 
-  // Handle new score format (V1 or V2) - show summary scores
-  const isNewFormat = (isNewScoreObject(score) || isNewScoreObjectV2(score) || isBasicScoreObject(score));
-
-  if (isNewFormat && 'summary_scores' in score) {
+  // Handle score format with summary_scores (V1, V2, or Basic)
+  if (hasSummaryScores(score)) {
     const summaryScores = score.summary_scores || [];
 
     if (summaryScores.length === 0) {
@@ -81,33 +79,32 @@ export default function ScoreDisplay({ score, errorMessage }: ScoreDisplayProps)
       );
     }
 
-    // Display numeric scores in a compact format
+    // Display each numeric score in its own box
     return (
-      <div className="inline-flex items-center gap-3 flex-wrap">
-        {numericScores.map((summary) => (
-          <div
-            key={summary.name}
-            className="inline-flex items-center gap-2 px-3 py-1.5 rounded-md text-sm"
-            style={{
-              backgroundColor: 'hsl(0, 0%, 98%)',
-              borderWidth: '1px',
-              borderColor: 'hsl(0, 0%, 85%)',
-              color: 'hsl(330, 3%, 19%)'
-            }}
-          >
-            <span className="font-medium text-xs" style={{ color: 'hsl(330, 3%, 49%)' }}>
-              {summary.name}:
-            </span>
-            <span className="font-semibold">
-              {summary.avg !== undefined ? summary.avg.toFixed(2) : 'N/A'}
-            </span>
-            {summary.std !== undefined && (
-              <span className="text-xs" style={{ color: 'hsl(330, 3%, 49%)' }}>
-                ±{summary.std.toFixed(2)}
-              </span>
-            )}
-          </div>
-        ))}
+      <div className="inline-flex items-center gap-3">
+        {numericScores.map((summary, idx) => {
+          const value = summary.avg !== undefined ? summary.avg.toFixed(2) : 'N/A';
+          const std = summary.std !== undefined ? summary.std.toFixed(2) : null;
+
+          return (
+            <div
+              key={idx}
+              className="inline-flex items-center gap-1.5 px-4 py-2 rounded-lg text-sm"
+              style={{
+                backgroundColor: '#ffffff',
+                borderWidth: '1px',
+                borderColor: '#e5e5e5',
+                color: '#737373'
+              }}
+            >
+              <span>{summary.name}:</span>
+              <span className="font-bold" style={{ color: '#171717' }}>{value}</span>
+              {std !== null && (
+                <span>±{std}</span>
+              )}
+            </div>
+          );
+        })}
       </div>
     );
   }
diff --git a/app/components/types.ts b/app/components/types.ts
index 0d6de10..8dad6e3 100644
--- a/app/components/types.ts
+++ b/app/components/types.ts
@@ -61,17 +61,6 @@ export interface NewScoreObjectV2 {
   traces: TraceItem[] | GroupedTraceItem[];
 }
 
-// Original new score object with individual_scores
-export interface NewScoreObject {
-  summary_scores: SummaryScore[];
-  individual_scores: IndividualScore[];
-}
-
-// Basic score object with only summary scores (no individual scores or traces)
-export interface BasicScoreObject {
-  summary_scores: SummaryScore[];
-}
-
 // Legacy score structure (for backward compatibility)
 export interface PerItemScore {
   trace_id: string;
@@ -89,8 +78,13 @@ export interface LegacyScoreObject {
   cosine_similarity: CosineSimilarity;
 }
 
+// Basic score object with only summary scores (no individual scores or traces)
+export interface BasicScoreObject {
+  summary_scores: SummaryScore[];
+}
+
 // Union type to support both old and new structures
-export type ScoreObject = NewScoreObjectV2 | NewScoreObject | BasicScoreObject | LegacyScoreObject;
+export type ScoreObject = NewScoreObjectV2 | BasicScoreObject | LegacyScoreObject;
 
 export interface AssistantConfig {
   name: string;
@@ -140,22 +134,30 @@ export interface EvalJob {
 }
 
 // Type guard functions
-// V2 with traces
-export function isNewScoreObjectV2(score: ScoreObject | null | undefined): score is NewScoreObjectV2 {
+
+// Shared guard: Check if score has summary_scores and intelligently narrow to NewScoreObjectV2 or BasicScoreObject
+// Priority: If it has traces → NewScoreObjectV2, otherwise → BasicScoreObject
+export function hasSummaryScores(score: ScoreObject | null | undefined): score is NewScoreObjectV2 | BasicScoreObject {
   if (!score) return false;
-  return 'summary_scores' in score && 'traces' in score;
+  if (!('summary_scores' in score)) return false;
+
+  // Prioritize traces format if available
+  if ('traces' in score) {
+    return true; 
+  }
+
+  // Otherwise, it's BasicScoreObject (summary_scores only, no traces, no individual_scores)
+  return true;
 }
 
-// V1 with individual_scores
-export function isNewScoreObject(score: ScoreObject | null | undefined): score is NewScoreObject {
+export function isNewScoreObjectV2(score: ScoreObject | null | undefined): score is NewScoreObjectV2 {
   if (!score) return false;
-  return 'summary_scores' in score && 'individual_scores' in score;
+  return 'summary_scores' in score && 'traces' in score;
 }
 
-// Fallback for scores with only summary_scores
 export function isBasicScoreObject(score: ScoreObject | null | undefined): score is BasicScoreObject {
   if (!score) return false;
-  return 'summary_scores' in score && !('individual_scores' in score) && !('traces' in score);
+  return 'summary_scores' in score && !('traces' in score);
 }
 
 export function isLegacyScoreObject(score: ScoreObject | null | undefined): score is LegacyScoreObject {
@@ -173,24 +175,31 @@ export function isGroupedFormat(traces: TraceItem[] | GroupedTraceItem[]): trace
   return "llm_answers" in traces[0] && Array.isArray(traces[0].llm_answers);
 }
 
-// Normalize traces to IndividualScore format for backward compatibility
+// Normalize traces to IndividualScore format for table display
 export function normalizeToIndividualScores(score: ScoreObject | null | undefined): IndividualScore[] {
   if (!score) return [];
 
   if (isNewScoreObjectV2(score)) {
-    // Convert TraceItem[] to IndividualScore[]
-    return score.traces.map(trace => ({
-      trace_id: trace.trace_id,
-      input: { question: trace.question },
-      output: { answer: trace.llm_answer },
-      metadata: { ground_truth: trace.ground_truth_answer },
-      trace_scores: trace.scores
-    }));
-  }
-
-  if (isNewScoreObject(score)) {
-    return score.individual_scores;
+    // Convert TraceItem[] to IndividualScore[] for table display
+    // Note: Grouped traces should be detected earlier and handled separately
+    return score.traces.map((trace: TraceItem | GroupedTraceItem) => {
+      // Handle regular TraceItem format
+      if ('llm_answer' in trace) {
+        return {
+          trace_id: trace.trace_id,
+          input: { question: trace.question },
+          output: { answer: trace.llm_answer },
+          metadata: { ground_truth: trace.ground_truth_answer },
+          trace_scores: trace.scores
+        };
+      }
+      // Should not reach here if grouped format is handled properly
+      return {
+        trace_id: '',
+        trace_scores: []
+      };
+    });
   }
 
   return [];
-}
+}
\ No newline at end of file
diff --git a/app/evaluations/[id]/page.tsx b/app/evaluations/[id]/page.tsx
index 596e29b..45da5ea 100644
--- a/app/evaluations/[id]/page.tsx
+++ b/app/evaluations/[id]/page.tsx
@@ -8,7 +8,7 @@
 import { useState, useEffect, useCallback } from 'react';
 import { useRouter, useParams } from 'next/navigation';
 import { APIKey, STORAGE_KEY } from '../../keystore/page';
-import { EvalJob, AssistantConfig, isNewScoreObject, isNewScoreObjectV2, getScoreObject, normalizeToIndividualScores, GroupedTraceItem, isGroupedFormat } from '../../components/types';
+import { EvalJob, AssistantConfig, hasSummaryScores, isNewScoreObjectV2, getScoreObject, normalizeToIndividualScores, GroupedTraceItem, isGroupedFormat } from '../../components/types';
 import { formatDate, getStatusColor } from '../../components/utils';
 import ConfigModal from '../../components/ConfigModal';
 import Sidebar from '../../components/Sidebar';
@@ -369,7 +369,7 @@ export default function EvaluationReport() {
 
     try {
       // Fetch with resync_score=true to trigger backend resync
-      const response = await fetch(`/api/evaluations/${jobId}?export_format=${exportFormat}&resync_score=true&get_trace_info=true`, {
+      const response = await fetch(`/api/evaluations/${jobId}?get_trace_info=true&resync_score=true&export_format=${exportFormat}`, {
         method: 'GET',
         headers: {
           'X-API-KEY': selectedKey.key,
@@ -457,11 +457,11 @@ export default function EvaluationReport() {
   const hasScore = !!scoreObject;
   const statusColors = getStatusColor(job.status);
 
-  // Check if we have new score structure (V1 or V2)
-  const isNewFormat = isNewScoreObject(scoreObject) || isNewScoreObjectV2(scoreObject);
+  // Check if we have new score structure (V1, V2, or Basic)
+  const isNewFormat = hasSummaryScores(scoreObject);
 
   // Safe access to summary scores
-  const summaryScores = (isNewFormat && scoreObject && 'summary_scores' in scoreObject)
+  const summaryScores = (isNewFormat && scoreObject)
     ? scoreObject.summary_scores || []
     : [];
 

From 9cc6b145c389cac76b6743e7e20006bda44ccdfb Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 9 Mar 2026 15:10:05 +0530
Subject: [PATCH 05/13] vector store id to knowledge base id

---
 app/components/ConfigCard.tsx                     | 2 +-
 app/components/ConfigDrawer.tsx                   | 2 +-
 app/components/ConfigModal.tsx                    | 6 +++---
 app/components/prompt-editor/ConfigEditorPane.tsx | 2 +-
 app/components/prompt-editor/CurrentConfigTab.tsx | 2 +-
 app/components/prompt-editor/DiffView.tsx         | 4 ++--
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/app/components/ConfigCard.tsx b/app/components/ConfigCard.tsx
index 446665b..096d180 100644
--- a/app/components/ConfigCard.tsx
+++ b/app/components/ConfigCard.tsx
@@ -181,7 +181,7 @@ export default function ConfigCard({
                         }}
                       >
                         <span style={{ color: colors.text.secondary, fontSize: '11px' }}>
-                          Vector Store IDs ({allVectorStoreIds.length})
+                          Knowledge Base IDs ({allVectorStoreIds.length})
                         </span>
                         <svg
                           className={`w-3 h-3 transition-transform ${showVectorStores ? 'rotate-180' : ''}`}
diff --git a/app/components/ConfigDrawer.tsx b/app/components/ConfigDrawer.tsx
index e78025c..5070268 100644
--- a/app/components/ConfigDrawer.tsx
+++ b/app/components/ConfigDrawer.tsx
@@ -635,7 +635,7 @@ export default function ConfigDrawer({
                           marginBottom: '4px',
                         }}
                       >
-                        Vector Store ID
+                        Knowledge Base ID
                       </label>
                       <input
                         type="text"
diff --git a/app/components/ConfigModal.tsx b/app/components/ConfigModal.tsx
index 1e98b7f..1994b49 100644
--- a/app/components/ConfigModal.tsx
+++ b/app/components/ConfigModal.tsx
@@ -266,7 +266,7 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
                   {Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0 && (
                     <div className="mb-3">
                       <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>
-                        Vector Store IDs ({tool.type})
+                        Knowledge Base IDs ({tool.type})
                       </div>
                       <div className="text-sm font-mono p-3 rounded-md border" style={{
                         backgroundColor: '#fafafa',
@@ -320,7 +320,7 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
                   {Array.isArray(tool.knowledge_base_ids) && tool.knowledge_base_ids.length > 0 && (
                     <div className="mb-3">
                       <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>
-                        Vector Store IDs ({tool.type})
+                        Knowledge Base IDs ({tool.type})
                       </div>
                       <div className="text-sm font-mono p-3 rounded-md border" style={{
                         backgroundColor: '#fafafa',
@@ -352,7 +352,7 @@ export default function ConfigModal({ isOpen, onClose, job, assistantConfig }: C
 
           {Array.isArray(assistantConfig?.knowledge_base_ids) && assistantConfig.knowledge_base_ids.length > 0 && (
             <div>
-              <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>Vector Store IDs</div>
+              <div className="text-xs uppercase font-semibold mb-2" style={{ color: '#000000' }}>Knowledge Base IDs</div>
               <div className="text-sm font-mono p-3 rounded-md border" style={{
                 backgroundColor: '#fafafa',
                 borderColor: '#e5e5e5',
diff --git a/app/components/prompt-editor/ConfigEditorPane.tsx b/app/components/prompt-editor/ConfigEditorPane.tsx
index ce4d23a..bee82ce 100644
--- a/app/components/prompt-editor/ConfigEditorPane.tsx
+++ b/app/components/prompt-editor/ConfigEditorPane.tsx
@@ -607,7 +607,7 @@ export default function ConfigEditorPane({
                     className="block text-xs mb-1"
                     style={{ color: '#000000' }}
                   >
-                    Vector Store ID
+                    Knowledge Base ID
                   </label>
                   <input
                     type="text"
diff --git a/app/components/prompt-editor/CurrentConfigTab.tsx b/app/components/prompt-editor/CurrentConfigTab.tsx
index aba579b..0656078 100644
--- a/app/components/prompt-editor/CurrentConfigTab.tsx
+++ b/app/components/prompt-editor/CurrentConfigTab.tsx
@@ -393,7 +393,7 @@ export default function CurrentConfigTab({
                   marginBottom: '4px',
                 }}
               >
-                Vector Store ID
+                Knowledge Base ID
               </label>
               <input
                 type="text"
diff --git a/app/components/prompt-editor/DiffView.tsx b/app/components/prompt-editor/DiffView.tsx
index a2bba25..a11304d 100644
--- a/app/components/prompt-editor/DiffView.tsx
+++ b/app/components/prompt-editor/DiffView.tsx
@@ -212,10 +212,10 @@ export default function DiffView({
                         <div className="text-sm space-y-2">
                           {selectedCommit.tools.map((tool, idx) => (
                             <div key={idx} className="p-2 rounded" style={{ backgroundColor: colors.bg.secondary }}>
-                              <div className="text-xs font-semibold">{tool.type}</div>
+                              <div className="text-xs font-semibold" style={{ color: colors.text.secondary }}>{tool.type}</div>
                               {tool.knowledge_base_ids && (
                                 <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
-                                  Vector Store: {tool.knowledge_base_ids[0]}
+                                  Knowledge Base: {tool.knowledge_base_ids[0]}
                                 </div>
                               )}
                             </div>

From 2bbcfbdf06aedd62ab849219d05dd044e41a9647 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 9 Mar 2026 14:54:06 +0530
Subject: [PATCH 06/13] ciderabbit and vector store to knowledge base

enter the commit message for your changes. Lines starting
merge conflicts resolve
---
 app/components/ConfigCard.tsx  | 10 +++++-----
 app/components/ConfigModal.tsx |  2 +-
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/app/components/ConfigCard.tsx b/app/components/ConfigCard.tsx
index 096d180..248844a 100644
--- a/app/components/ConfigCard.tsx
+++ b/app/components/ConfigCard.tsx
@@ -24,7 +24,7 @@ export default function ConfigCard({
   const router = useRouter();
   const { latestVersion, totalVersions } = configGroup;
   const [showTools, setShowTools] = useState(false);
-  const [showVectorStores, setShowVectorStores] = useState(false);
+  const [showKnowledgeBases, setShowKnowledgeBases] = useState(false);
 
   const handleEdit = () => {
     router.push(`/configurations/prompt-editor?config=${latestVersion.config_id}&version=${latestVersion.version}`);
@@ -164,7 +164,7 @@ export default function ConfigCard({
                   </div>
                 ))}
 
-                {/* Vector Stores Section inside Tools */}
+                {/* Knowledge Bases Section inside Tools */}
                 {(() => {
                   // Collect all knowledge_base_ids from all tools
                   const allVectorStoreIds = latestVersion.tools
@@ -174,7 +174,7 @@ export default function ConfigCard({
                   return allVectorStoreIds.length > 0 && (
                     <div className="mt-3 pt-2" style={{ borderTop: `1px solid ${colors.border}` }}>
                       <button
-                        onClick={() => setShowVectorStores(!showVectorStores)}
+                        onClick={() => setShowKnowledgeBases(!showKnowledgeBases)}
                         className="w-full flex items-center justify-between px-2 py-1 rounded-md transition-colors"
                         style={{
                           backgroundColor: colors.bg.primary,
@@ -184,7 +184,7 @@ export default function ConfigCard({
                           Knowledge Base IDs ({allVectorStoreIds.length})
                         </span>
                         <svg
-                          className={`w-3 h-3 transition-transform ${showVectorStores ? 'rotate-180' : ''}`}
+                          className={`w-3 h-3 transition-transform ${showKnowledgeBases ? 'rotate-180' : ''}`}
                           style={{ color: colors.text.secondary }}
                           fill="none"
                           viewBox="0 0 24 24"
@@ -193,7 +193,7 @@ export default function ConfigCard({
                           <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
                         </svg>
                       </button>
-                      {showVectorStores && (
+                      {showKnowledgeBases && (
                         <div
                           className="mt-1 p-2 rounded-md space-y-1"
                           style={{
diff --git a/app/components/ConfigModal.tsx b/app/components/ConfigModal.tsx
index 1994b49..bf10ea8 100644
--- a/app/components/ConfigModal.tsx
+++ b/app/components/ConfigModal.tsx
@@ -1,6 +1,6 @@
 /**
  * ConfigModal - Displays detailed configuration for an evaluation job
- * Shows assistant config, model, temperature, instructions, tools, and vector stores
+ * Shows assistant config, model, temperature, instructions, tools, and knowledge bases
  */
 
 "use client"

From 855281aa43d4720c666b2be1574893f1c1d3e4b8 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Tue, 10 Mar 2026 12:19:01 +0530
Subject: [PATCH 07/13] Guardrails UI: add guardrails to config

---
 .../validators/configs/[config_id]/route.ts   |   0
 .../guardrails/validators/configs/route.ts    |   0
 .../prompt-editor/ConfigEditorPane.tsx        | 177 +++++++++++++++++-
 .../prompt-editor/ValidatorListPane.tsx       | 123 ++++++++++++
 app/configurations/prompt-editor/page.tsx     |  58 +++++-
 5 files changed, 351 insertions(+), 7 deletions(-)
 create mode 100644 app/api/guardrails/validators/configs/[config_id]/route.ts
 create mode 100644 app/api/guardrails/validators/configs/route.ts
 create mode 100644 app/components/prompt-editor/ValidatorListPane.tsx

diff --git a/app/api/guardrails/validators/configs/[config_id]/route.ts b/app/api/guardrails/validators/configs/[config_id]/route.ts
new file mode 100644
index 0000000..e69de29
diff --git a/app/api/guardrails/validators/configs/route.ts b/app/api/guardrails/validators/configs/route.ts
new file mode 100644
index 0000000..e69de29
diff --git a/app/components/prompt-editor/ConfigEditorPane.tsx b/app/components/prompt-editor/ConfigEditorPane.tsx
index bee82ce..8140029 100644
--- a/app/components/prompt-editor/ConfigEditorPane.tsx
+++ b/app/components/prompt-editor/ConfigEditorPane.tsx
@@ -2,6 +2,7 @@ import React, { useState, useMemo } from 'react';
 import { colors } from '@/app/lib/colors';
 import { ConfigBlob, Tool } from '@/app/configurations/prompt-editor/types';
 import { SavedConfig, formatRelativeTime } from '@/app/lib/useConfigs';
+import { Validator, AVAILABLE_VALIDATORS } from './ValidatorListPane';
 
 interface ConfigEditorPaneProps {
   configBlob: ConfigBlob;
@@ -19,6 +20,14 @@ interface ConfigEditorPaneProps {
   // Collapse functionality
   collapsed?: boolean;
   onToggle?: () => void;
+  // Guardrails mode
+  isGuardrailsMode?: boolean;
+  onEnterGuardrailsMode?: () => void;
+  onExitGuardrailsMode?: () => void;
+  selectedValidator?: string | null;
+  savedValidators?: Validator[];
+  onSaveValidator?: (validator: Validator) => void;
+  onRemoveValidator?: (index: number) => void;
 }
 
 // Group configs by name for nested dropdown
@@ -64,9 +73,17 @@ export default function ConfigEditorPane({
   isSaving = false,
   collapsed = false,
   onToggle,
+  isGuardrailsMode = false,
+  onEnterGuardrailsMode,
+  onExitGuardrailsMode,
+  selectedValidator = null,
+  savedValidators = [],
+  onSaveValidator,
+  onRemoveValidator,
 }: ConfigEditorPaneProps) {
   const [isDropdownOpen, setIsDropdownOpen] = useState(false);
   const [showTooltip, setShowTooltip] = useState<number | null>(null);
+  const [validatorConfig, setValidatorConfig] = useState<any>({});
 
   const provider = configBlob.completion.provider;
   const params = configBlob.completion.params;
@@ -272,7 +289,7 @@ export default function ConfigEditorPane({
       )}
 
       {/* Content - hidden when collapsed */}
-      {!collapsed && (
+      {!collapsed && !isGuardrailsMode && (
       <div className="flex-1 overflow-auto p-4">
         <div className="space-y-4">
           {/* Load Saved Config - Nested dropdown matching Evaluations page pattern */}
@@ -727,6 +744,23 @@ export default function ConfigEditorPane({
             />
           </div>
 
+          {/* Add Guardrails Button */}
+          <button
+            onClick={onEnterGuardrailsMode}
+            className="w-full px-4 py-2 rounded-md text-sm font-semibold"
+            style={{
+              backgroundColor: colors.bg.primary,
+              color: colors.text.primary,
+              border: `1px solid ${colors.border}`,
+              cursor: 'pointer',
+              transition: 'all 0.15s ease',
+            }}
+            onMouseEnter={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+            onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.primary}
+          >
+            Add Guardrails
+          </button>
+
           {/* Save Button */}
           <button
             onClick={onSave}
@@ -745,6 +779,147 @@ export default function ConfigEditorPane({
         </div>
       </div>
       )}
+
+      {/* Guardrails Mode - Configuration Panel Only */}
+      {!collapsed && isGuardrailsMode && (
+        <div className="flex-1 flex flex-col overflow-hidden">
+          <div className="flex-1 overflow-auto p-4">
+            {/* Validator Configuration Form */}
+            {selectedValidator && (
+              <div className="mb-6">
+                <h3 className="text-sm font-semibold mb-3" style={{ color: colors.text.primary }}>
+                  Configure {AVAILABLE_VALIDATORS.find(v => v.id === selectedValidator)?.name}
+                </h3>
+                <div
+                  className="p-4 rounded-lg space-y-3"
+                  style={{
+                    border: `1px solid ${colors.border}`,
+                    backgroundColor: colors.bg.secondary,
+                  }}
+                >
+                  <div>
+                    <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                      <input
+                        type="checkbox"
+                        checked={validatorConfig.enabled || false}
+                        onChange={(e) => setValidatorConfig({ ...validatorConfig, enabled: e.target.checked })}
+                        style={{ accentColor: colors.accent.primary }}
+                      />
+                      Enabled
+                    </label>
+                  </div>
+                  <div>
+                    <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                      Threshold: {validatorConfig.threshold || 0.8}
+                    </label>
+                    <input
+                      type="range"
+                      min="0"
+                      max="1"
+                      step="0.1"
+                      value={validatorConfig.threshold || 0.8}
+                      onChange={(e) => setValidatorConfig({ ...validatorConfig, threshold: parseFloat(e.target.value) })}
+                      className="w-full"
+                      style={{ accentColor: colors.accent.primary }}
+                    />
+                  </div>
+                  <button
+                    onClick={() => {
+                      const validator = AVAILABLE_VALIDATORS.find(v => v.id === selectedValidator);
+                      if (validator && onSaveValidator) {
+                        onSaveValidator({ ...validator, config: validatorConfig });
+                        setValidatorConfig({});
+                      }
+                    }}
+                    className="w-full px-4 py-2 rounded-md text-sm font-semibold"
+                    style={{
+                      backgroundColor: colors.status.success,
+                      color: '#ffffff',
+                      border: 'none',
+                      cursor: 'pointer',
+                    }}
+                  >
+                    Save Validator
+                  </button>
+                </div>
+              </div>
+            )}
+
+            {/* Saved Validators */}
+            {savedValidators.length > 0 && (
+              <div>
+                <h3 className="text-sm font-semibold mb-3" style={{ color: colors.text.primary }}>
+                  Configured Validators ({savedValidators.length})
+                </h3>
+                <div className="space-y-2">
+                  {savedValidators.map((validator, idx) => (
+                    <div
+                      key={idx}
+                      className="p-3 rounded-lg"
+                      style={{
+                        border: `1px solid ${colors.border}`,
+                        backgroundColor: colors.bg.primary,
+                      }}
+                    >
+                      <div className="flex items-start justify-between">
+                        <div className="flex items-start gap-2">
+                          <div>
+                            <div className="font-semibold text-sm" style={{ color: colors.text.primary }}>
+                              {validator.name}
+                            </div>
+                            <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
+                              Threshold: {validator.config?.threshold || 0.8} • {validator.config?.enabled ? 'Enabled' : 'Disabled'}
+                            </div>
+                          </div>
+                        </div>
+                        <button
+                          onClick={() => onRemoveValidator && onRemoveValidator(idx)}
+                          className="text-xs"
+                          style={{
+                            color: colors.status.error,
+                            background: 'none',
+                            border: 'none',
+                            cursor: 'pointer',
+                          }}
+                        >
+                          Remove
+                        </button>
+                      </div>
+                    </div>
+                  ))}
+                </div>
+              </div>
+            )}
+          </div>
+
+          {/* Back Button */}
+          <div
+            className="p-4 border-t"
+            style={{ borderColor: colors.border }}
+          >
+            <button
+              onClick={() => {
+                if (onExitGuardrailsMode) {
+                  onExitGuardrailsMode();
+                  setValidatorConfig({});
+                }
+              }}
+              className="w-full px-4 py-2 rounded-md text-sm font-semibold"
+              style={{
+                backgroundColor: colors.bg.primary,
+                color: colors.text.primary,
+                border: `1px solid ${colors.border}`,
+                cursor: 'pointer',
+                transition: 'all 0.15s ease',
+              }}
+              onMouseEnter={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+              onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.primary}
+            >
+              ← Back to Main Config
+            </button>
+          </div>
+        </div>
+      )}
     </div>
   );
 }
diff --git a/app/components/prompt-editor/ValidatorListPane.tsx b/app/components/prompt-editor/ValidatorListPane.tsx
new file mode 100644
index 0000000..cbe916b
--- /dev/null
+++ b/app/components/prompt-editor/ValidatorListPane.tsx
@@ -0,0 +1,123 @@
+import React from 'react';
+import { colors } from '@/app/lib/colors';
+
+export interface Validator {
+  id: string;
+  name: string;
+  description: string;
+  tags: string[];
+  config?: {
+    threshold?: number;
+    enabled?: boolean;
+    [key: string]: any;
+  };
+}
+
+export const AVAILABLE_VALIDATORS: Validator[] = [
+  {
+    id: 'ban-list',
+    name: 'Ban List',
+    description: 'Validates that the output does not contain banned words, using fuzzy search.',
+    tags: ['STRING', 'BRAND RISK'],
+  },
+  {
+    id: 'bias-check',
+    name: 'Bias Check',
+    description: 'Validates that the text is free from biases related to age, gender, sex, ethnicity,...',
+    tags: ['STRING', 'BRAND RISK'],
+  },
+  {
+    id: 'detect-pii',
+    name: 'Detect PII',
+    description: 'Detects personally identifiable information (PII) in text, using Microsoft Presidio.',
+    tags: ['STRING', 'DATA LEAKAGE'],
+  },
+  {
+    id: 'extractive-summary',
+    name: 'Extractive Summary',
+    description: 'Uses fuzzy matching to detect if some text is a summary of a document.',
+    tags: ['STRING', 'FACTUALITY'],
+  },
+];
+
+interface ValidatorListPaneProps {
+  selectedValidator: string | null;
+  onSelectValidator: (validatorId: string) => void;
+}
+
+export default function ValidatorListPane({
+  selectedValidator,
+  onSelectValidator,
+}: ValidatorListPaneProps) {
+  return (
+    <div
+      className="flex-1 flex flex-col overflow-hidden border-r"
+      style={{
+        backgroundColor: colors.bg.primary,
+        borderColor: colors.border,
+      }}
+    >
+      {/* Header */}
+      <div
+        className="border-b px-4 py-3"
+        style={{ borderColor: colors.border }}
+      >
+        <h3 className="text-sm font-semibold" style={{ color: colors.text.primary }}>
+          Available Validators
+        </h3>
+      </div>
+
+      {/* Validator List */}
+      <div className="flex-1 overflow-auto p-4">
+        <div className="space-y-2">
+          {AVAILABLE_VALIDATORS.map((validator) => (
+            <button
+              key={validator.id}
+              onClick={() => onSelectValidator(validator.id)}
+              className="w-full text-left p-3 rounded-lg transition-colors"
+              style={{
+                backgroundColor: selectedValidator === validator.id ? colors.bg.secondary : colors.bg.primary,
+                border: `1px solid ${colors.border}`,
+              }}
+              onMouseEnter={(e) => {
+                if (selectedValidator !== validator.id) {
+                  e.currentTarget.style.backgroundColor = colors.bg.secondary;
+                }
+              }}
+              onMouseLeave={(e) => {
+                if (selectedValidator !== validator.id) {
+                  e.currentTarget.style.backgroundColor = colors.bg.primary;
+                }
+              }}
+            >
+              <div className="flex items-start gap-2">
+                <div className="flex-1">
+                  <div className="font-semibold text-sm" style={{ color: colors.text.primary }}>
+                    {validator.name}
+                  </div>
+                  <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
+                    {validator.description}
+                  </div>
+                  <div className="flex gap-1 mt-2">
+                    {validator.tags.map((tag) => (
+                      <span
+                        key={tag}
+                        className="text-xs px-2 py-0.5 rounded"
+                        style={{
+                          backgroundColor: colors.bg.secondary,
+                          color: colors.text.secondary,
+                        }}
+                      >
+                        {tag}
+                      </span>
+                    ))}
+                  </div>
+                </div>
+              </div>
+            </button>
+          ))}
+        </div>
+      </div>
+    </div>
+  );
+}
diff --git a/app/configurations/prompt-editor/page.tsx b/app/configurations/prompt-editor/page.tsx
index 7428474..141aafd 100644
--- a/app/configurations/prompt-editor/page.tsx
+++ b/app/configurations/prompt-editor/page.tsx
@@ -23,6 +23,7 @@ import HistorySidebar from '@/app/components/prompt-editor/HistorySidebar';
 import PromptEditorPane from '@/app/components/prompt-editor/PromptEditorPane';
 import ConfigEditorPane from '@/app/components/prompt-editor/ConfigEditorPane';
 import DiffView from '@/app/components/prompt-editor/DiffView';
+import ValidatorListPane, { Validator } from '@/app/components/prompt-editor/ValidatorListPane';
 import { useToast } from '@/app/components/Toast';
 import Loader from '@/app/components/Loader';
 import { useConfigs, invalidateConfigCache, SavedConfig } from '@/app/lib/useConfigs';
@@ -83,6 +84,11 @@ function PromptEditorContent() {
   const [selectedVersion, setSelectedVersion] = useState<SavedConfig | null>(null);
   const [compareWith, setCompareWith] = useState<SavedConfig | null>(null);
 
+  // Guardrails state
+  const [isGuardrailsMode, setIsGuardrailsMode] = useState<boolean>(false);
+  const [selectedValidator, setSelectedValidator] = useState<string | null>(null);
+  const [savedValidators, setSavedValidators] = useState<Validator[]>([]);
+
   // Get API key from localStorage
   const getApiKey = (): string | null => {
     try {
@@ -359,6 +365,30 @@ function PromptEditorContent() {
     setTools(config.tools || []);
   };
 
+  // Guardrails handlers
+  const handleEnterGuardrailsMode = () => {
+    setIsGuardrailsMode(true);
+    setSelectedValidator(null);
+  };
+
+  const handleExitGuardrailsMode = () => {
+    setIsGuardrailsMode(false);
+    setSelectedValidator(null);
+  };
+
+  const handleSelectValidator = (validatorId: string) => {
+    setSelectedValidator(validatorId);
+  };
+
+  const handleSaveValidator = (validator: Validator) => {
+    setSavedValidators([...savedValidators, validator]);
+    setSelectedValidator(null);
+  };
+
+  const handleRemoveValidator = (index: number) => {
+    setSavedValidators(savedValidators.filter((_, i) => i !== index));
+  };
+
 
   return (
     <div className="w-full h-screen flex flex-col" style={{ backgroundColor: colors.bg.secondary }}>
@@ -414,8 +444,9 @@ function PromptEditorContent() {
               />
             ) : (
               <div className="flex-1 flex flex-col overflow-hidden">
-                {/* Split View: Prompt (left) + Config (right) */}
+                {/* Split View: Prompt (left) + Config (right) OR Validators (left) + Config (right) */}
                 <div className="flex flex-1 overflow-hidden">
+                  {/* Left Panel - Conditionally render Prompt Editor or Validator List */}
                   <div
                     className="flex"
                     style={{
@@ -423,12 +454,20 @@ function PromptEditorContent() {
                       transition: 'flex 0.2s ease-in-out',
                     }}
                   >
-                    <PromptEditorPane
-                      currentContent={currentContent}
-                      onContentChange={setCurrentContent}
-                      currentBranch={currentConfigName || 'Unsaved'}
-                    />
+                    {isGuardrailsMode ? (
+                      <ValidatorListPane
+                        selectedValidator={selectedValidator}
+                        onSelectValidator={handleSelectValidator}
+                      />
+                    ) : (
+                      <PromptEditorPane
+                        currentContent={currentContent}
+                        onContentChange={setCurrentContent}
+                        currentBranch={currentConfigName || 'Unsaved'}
+                      />
+                    )}
                   </div>
+                  {/* Right Panel - Config Editor */}
                   <ConfigEditorPane
                     configBlob={currentConfigBlob}
                     onConfigChange={setCurrentConfigBlob}
@@ -443,6 +482,13 @@ function PromptEditorContent() {
                     isSaving={isSaving}
                     collapsed={!showConfigPane}
                     onToggle={() => setShowConfigPane(!showConfigPane)}
+                    isGuardrailsMode={isGuardrailsMode}
+                    onEnterGuardrailsMode={handleEnterGuardrailsMode}
+                    onExitGuardrailsMode={handleExitGuardrailsMode}
+                    selectedValidator={selectedValidator}
+                    savedValidators={savedValidators}
+                    onSaveValidator={handleSaveValidator}
+                    onRemoveValidator={handleRemoveValidator}
                   />
                 </div>
               </div>

From 2455ed6941f0b112247ffd636be97227fb2ee138 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Sun, 15 Mar 2026 22:04:25 +0530
Subject: [PATCH 08/13] second commit: made guardrail page better

---
 app/api/apikeys/verify/route.ts               |   44 +
 .../ban_lists/[ban_list_id]/route.ts          |  157 +++
 app/api/guardrails/ban_lists/route.ts         |  104 ++
 .../validators/configs/[config_id]/route.ts   |  104 ++
 .../guardrails/validators/configs/route.ts    |   70 +
 app/components/ConfigCard.tsx                 |   30 +
 .../prompt-editor/ConfigEditorPane.tsx        | 1227 +++++++++++++++--
 .../prompt-editor/ValidatorListPane.tsx       |   22 +-
 app/configurations/prompt-editor/page.tsx     |  417 +++++-
 app/keystore/page.tsx                         |   78 +-
 app/lib/useConfigs.ts                         |   11 +
 11 files changed, 2152 insertions(+), 112 deletions(-)
 create mode 100644 app/api/apikeys/verify/route.ts
 create mode 100644 app/api/guardrails/ban_lists/[ban_list_id]/route.ts
 create mode 100644 app/api/guardrails/ban_lists/route.ts

diff --git a/app/api/apikeys/verify/route.ts b/app/api/apikeys/verify/route.ts
new file mode 100644
index 0000000..4d4806a
--- /dev/null
+++ b/app/api/apikeys/verify/route.ts
@@ -0,0 +1,44 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8000';
+
+export async function GET(request: NextRequest) {
+  try {
+    // Get the API key from request headers
+    const apiKey = request.headers.get('X-API-KEY');
+    if (!apiKey) {
+      return NextResponse.json(
+        { error: 'Missing X-API-KEY header' },
+        { status: 401 }
+      );
+    }
+
+    // Forward the request to the actual backend
+    const url = `${backendUrl}/api/v1/apikeys/verify`;
+
+    const response = await fetch(url, {
+      method: 'GET',
+      headers: {
+        'X-API-KEY': apiKey,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : {};
+
+    // Return the response with the same status code
+    if (!response.ok) {
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
diff --git a/app/api/guardrails/ban_lists/[ban_list_id]/route.ts b/app/api/guardrails/ban_lists/[ban_list_id]/route.ts
new file mode 100644
index 0000000..eb9ad4b
--- /dev/null
+++ b/app/api/guardrails/ban_lists/[ban_list_id]/route.ts
@@ -0,0 +1,157 @@
+import { NextResponse } from 'next/server';
+
+const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
+
+export async function GET(
+  request: Request,
+  { params }: { params: Promise<{ ban_list_id: string }> }
+) {
+  const { ban_list_id } = await params;
+  const apiKey = request.headers.get('X-API-KEY');
+
+  if (!apiKey) {
+    return NextResponse.json(
+      { error: 'Missing X-API-KEY header' },
+      { status: 401 }
+    );
+  }
+
+  try {
+    const url = `${backendUrl}/api/v1/guardrails/ban_lists/${ban_list_id}`;
+
+    console.log('[GET /api/guardrails/ban_lists/[ban_list_id]] Forwarding to:', url);
+
+    const response = await fetch(url, {
+      headers: {
+        'X-API-KEY': apiKey,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    console.log('[GET /api/guardrails/ban_list/[ban_list_id]] Backend response status:', response.status, response.statusText);
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : {};
+
+    console.log('[GET /api/guardrails/ban_list/[ban_list_id]] Backend response data:', JSON.stringify(data, null, 2));
+
+    if (!response.ok) {
+      console.error('[GET /api/guardrails/ban_list/[ban_list_id]] Backend error:', response.status, data);
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
+
+export async function PUT(
+  request: Request,
+  { params }: { params: Promise<{ ban_list_id: string }> }
+) {
+  const { ban_list_id } = await params;
+  const apiKey = request.headers.get('X-API-KEY');
+
+  if (!apiKey) {
+    return NextResponse.json(
+      { error: 'Missing X-API-KEY header' },
+      { status: 401 }
+    );
+  }
+
+  try {
+    // Get the JSON body from the request
+    const body = await request.json();
+
+    const url = `${backendUrl}/api/v1/guardrails/ban_lists/${ban_list_id}`;
+
+    console.log('[PUT /api/guardrails/ban_list/[ban_list_id]] Forwarding to:', url);
+    console.log('[PUT /api/guardrails/ban_list/[ban_list_id]] Body:', JSON.stringify(body, null, 2));
+
+    const response = await fetch(url, {
+      method: 'PUT',
+      body: JSON.stringify(body),
+      headers: {
+        'X-API-KEY': apiKey,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    console.log('[PUT /api/guardrails/ban_list/[ban_list_id]] Backend response status:', response.status, response.statusText);
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : { success: true };
+
+    console.log('[PUT /api/guardrails/ban_list/[ban_list_id]] Backend response data:', JSON.stringify(data, null, 2));
+
+    if (!response.ok) {
+      console.error('[PUT /api/guardrails/ban_list/[ban_list_id]] Backend error:', response.status, data);
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
+
+export async function DELETE(
+  request: Request,
+  { params }: { params: Promise<{ ban_list_id: string }> }
+) {
+  const { ban_list_id } = await params;
+  const apiKey = request.headers.get('X-API-KEY');
+
+  if (!apiKey) {
+    return NextResponse.json(
+      { error: 'Missing X-API-KEY header' },
+      { status: 401 }
+    );
+  }
+
+  try {
+    const url = `${backendUrl}/api/v1/guardrails/ban_lists/${ban_list_id}`;
+
+    console.log('[DELETE /api/guardrails/ban_lists/[ban_list_id]] Forwarding to:', url);
+
+    const response = await fetch(url, {
+      method: 'DELETE',
+      headers: {
+        'X-API-KEY': apiKey,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    console.log('[DELETE /api/guardrails/ban_list/[ban_list_id]] Backend response status:', response.status, response.statusText);
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : { success: true };
+
+    console.log('[DELETE /api/guardrails/ban_list/[ban_list_id]] Backend response data:', JSON.stringify(data, null, 2));
+
+    if (!response.ok) {
+      console.error('[DELETE /api/guardrails/ban_list/[ban_list_id]] Backend error:', response.status, data);
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
diff --git a/app/api/guardrails/ban_lists/route.ts b/app/api/guardrails/ban_lists/route.ts
new file mode 100644
index 0000000..da84f34
--- /dev/null
+++ b/app/api/guardrails/ban_lists/route.ts
@@ -0,0 +1,104 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
+
+export async function GET(request: NextRequest) {
+  try {
+    // Get the Kaapi API key from request headers
+    const apiKey = request.headers.get('X-API-KEY');
+    if (!apiKey) {
+      return NextResponse.json(
+        { error: 'Missing X-API-KEY header' },
+        { status: 401 }
+      );
+    }
+
+    const url = `${backendUrl}/api/v1/guardrails/ban_lists`;
+
+    console.log('[GET /api/guardrails/ban_list] Forwarding to:', url);
+
+    // Forward the request to the actual backend
+    const response = await fetch(url, {
+      method: 'GET',
+      headers: {
+        'X-API-KEY': apiKey,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    console.log('[GET /api/guardrails/ban_list] Backend response status:', response.status, response.statusText);
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : { data: [] };
+
+    console.log('[GET /api/guardrails/ban_list] Backend response data:', JSON.stringify(data, null, 2));
+
+    // Return the response with the same status code
+    if (!response.ok) {
+      console.error('[GET /api/guardrails/ban_list] Backend error:', response.status, data);
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
+
+export async function POST(request: NextRequest) {
+  try {
+    // Get the Kaapi API key from request headers
+    const apiKey = request.headers.get('X-API-KEY');
+    if (!apiKey) {
+      return NextResponse.json(
+        { error: 'Missing X-API-KEY header' },
+        { status: 401 }
+      );
+    }
+
+    // Get the JSON body from the request
+    const body = await request.json();
+
+    const url = `${backendUrl}/api/v1/guardrails/ban_lists`;
+
+    console.log('[POST /api/guardrails/ban_list] Forwarding to:', url);
+    console.log('[POST /api/guardrails/ban_list] Body:', JSON.stringify(body, null, 2));
+
+    // Forward the request to the actual backend
+    const response = await fetch(url, {
+      method: 'POST',
+      body: JSON.stringify(body),
+      headers: {
+        'X-API-KEY': apiKey,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    console.log('[POST /api/guardrails/ban_list] Backend response status:', response.status, response.statusText);
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : { success: true };
+
+    console.log('[POST /api/guardrails/ban_list] Backend response data:', JSON.stringify(data, null, 2));
+
+    // Return the response with the same status code
+    if (!response.ok) {
+      console.error('[POST /api/guardrails/ban_list] Backend error:', response.status, data);
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
diff --git a/app/api/guardrails/validators/configs/[config_id]/route.ts b/app/api/guardrails/validators/configs/[config_id]/route.ts
index e69de29..e087b55 100644
--- a/app/api/guardrails/validators/configs/[config_id]/route.ts
+++ b/app/api/guardrails/validators/configs/[config_id]/route.ts
@@ -0,0 +1,104 @@
+import { NextResponse } from 'next/server';
+
+const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
+
+export async function GET(
+  request: Request,
+  { params }: { params: Promise<{ config_id: string }> }
+) {
+  const { config_id } = await params;
+  const authHeader = request.headers.get('Authorization');
+
+  if (!authHeader) {
+    return NextResponse.json(
+      { error: 'Missing Authorization header' },
+      { status: 401 }
+    );
+  }
+
+  try {
+    // Get query parameters
+    const { searchParams } = new URL(request.url);
+    const organizationId = searchParams.get('organization_id');
+    const projectId = searchParams.get('project_id');
+
+    // Build query string
+    const queryParams = new URLSearchParams();
+    if (organizationId) queryParams.append('organization_id', organizationId);
+    if (projectId) queryParams.append('project_id', projectId);
+
+    const queryString = queryParams.toString();
+    const url = `${backendUrl}/api/v1/guardrails/validators/configs/${config_id}${queryString ? `?${queryString}` : ''}`;
+
+    const response = await fetch(url, {
+      headers: {
+        'Authorization': authHeader,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : {};
+
+    if (!response.ok) {
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
+
+
+export async function DELETE(
+  request: Request,
+  { params }: { params: Promise<{ config_id: string }> }
+) {
+  const { config_id } = await params;
+  const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
+  const authHeader = request.headers.get('Authorization');
+
+  if (!authHeader) {
+    return NextResponse.json(
+      { error: 'Missing Authorization header' },
+      { status: 401 }
+    );
+  }
+
+  try {
+      // Get query parameters
+    const { searchParams } = new URL(request.url);
+    const organizationId = searchParams.get('organization_id');
+    const projectId = searchParams.get('project_id');
+
+    // Build query string
+    const queryParams = new URLSearchParams();
+    if (organizationId) queryParams.append('organization_id', organizationId);
+    if (projectId) queryParams.append('project_id', projectId);
+
+    const queryString = queryParams.toString();
+    const url = `${backendUrl}/api/v1/guardrails/validators/configs/${config_id}${queryString ? `?${queryString}` : ''}`;
+
+    const response = await fetch(url, {
+      method: 'DELETE',
+      headers: {
+        'Authorization': authHeader,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    const data = await response.json();
+    return NextResponse.json(data, { status: response.status });
+  } catch (error) {
+    return NextResponse.json(
+      { success: false, error: 'Failed to delete config', data: null },
+      { status: 500 }
+    );
+  }
+}
diff --git a/app/api/guardrails/validators/configs/route.ts b/app/api/guardrails/validators/configs/route.ts
index e69de29..0fa50a7 100644
--- a/app/api/guardrails/validators/configs/route.ts
+++ b/app/api/guardrails/validators/configs/route.ts
@@ -0,0 +1,70 @@
+import { NextRequest, NextResponse } from 'next/server';
+
+
+
+const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
+
+export async function POST(request: NextRequest) {
+  try {
+    // Get the API key from request headers
+    const authHeader = request.headers.get('Authorization');
+    if (!authHeader) {
+    return NextResponse.json(
+      { error: 'Missing Authorization header' },
+      { status: 401 }
+    );
+  }
+
+
+    // Get the JSON body from the request
+    const body = await request.json();
+
+    // Get query parameters
+    const { searchParams } = new URL(request.url);
+    const organizationId = searchParams.get('organization_id');
+    const projectId = searchParams.get('project_id');
+
+    // Build query string
+    const queryParams = new URLSearchParams();
+    if (organizationId) queryParams.append('organization_id', organizationId);
+    if (projectId) queryParams.append('project_id', projectId);
+
+    const queryString = queryParams.toString();
+    const url = `${backendUrl}/api/v1/guardrails/validators/configs${queryString ? `?${queryString}` : ''}`;
+
+    console.log('[POST /api/guardrails/validators/configs] Forwarding to:', url);
+    console.log('[POST /api/guardrails/validators/configs] Body:', JSON.stringify(body, null, 2));
+
+    // Forward the request to the actual backend
+    const response = await fetch(url, {
+      method: 'POST',
+      body: JSON.stringify(body),
+      headers: {
+        'Authorization': authHeader,
+        'Content-Type': 'application/json',
+      },
+    });
+
+    console.log('[POST /api/guardrails/validators/configs] Backend response status:', response.status, response.statusText);
+
+    // Handle empty responses (204 No Content, etc.)
+    const text = await response.text();
+    const data = text ? JSON.parse(text) : { success: true };
+
+    console.log('[POST /api/guardrails/validators/configs] Backend response data:', JSON.stringify(data, null, 2));
+
+    // Return the response with the same status code
+    if (!response.ok) {
+      console.error('[POST /api/guardrails/validators/configs] Backend error:', response.status, data);
+      return NextResponse.json(data, { status: response.status });
+    }
+
+    return NextResponse.json(data, { status: response.status });
+  } catch (error: any) {
+    console.error('Proxy error:', error);
+    return NextResponse.json(
+      { error: 'Failed to forward request to backend', details: error.message },
+      { status: 500 }
+    );
+  }
+}
\ No newline at end of file
diff --git a/app/components/ConfigCard.tsx b/app/components/ConfigCard.tsx
index 248844a..221b110 100644
--- a/app/components/ConfigCard.tsx
+++ b/app/components/ConfigCard.tsx
@@ -112,6 +112,36 @@ export default function ConfigCard({
             <span style={{ color: colors.text.secondary }}>Temp: </span>
             <span style={{ color: colors.text.primary, fontWeight: 500 }}>{latestVersion.temperature.toFixed(2)}</span>
           </div>
+          {(() => {
+            console.log('[DEBUG ConfigCard] Config:', configGroup.name, 'hasGuardrails:', latestVersion.hasGuardrails, 'count:', latestVersion.guardrailsCount);
+            return latestVersion.hasGuardrails && (
+              <div
+                className="px-2.5 py-1 rounded-md text-xs flex items-center gap-1"
+                style={{
+                  backgroundColor: '#f0fdf4',
+                  border: '1px solid #86efac',
+                }}
+              >
+                <svg
+                  className="w-3 h-3"
+                  fill="none"
+                  viewBox="0 0 24 24"
+                  stroke="currentColor"
+                  style={{ color: '#16a34a' }}
+                >
+                  <path
+                    strokeLinecap="round"
+                    strokeLinejoin="round"
+                    strokeWidth={2}
+                    d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
+                  />
+                </svg>
+                <span style={{ color: '#16a34a', fontWeight: 500 }}>
+                  Guardrails Configured
+                </span>
+              </div>
+            );
+          })()}
         </div>
 
         {/* Tools Dropdown */}
diff --git a/app/components/prompt-editor/ConfigEditorPane.tsx b/app/components/prompt-editor/ConfigEditorPane.tsx
index 8140029..fe1fc4f 100644
--- a/app/components/prompt-editor/ConfigEditorPane.tsx
+++ b/app/components/prompt-editor/ConfigEditorPane.tsx
@@ -3,6 +3,7 @@ import { colors } from '@/app/lib/colors';
 import { ConfigBlob, Tool } from '@/app/configurations/prompt-editor/types';
 import { SavedConfig, formatRelativeTime } from '@/app/lib/useConfigs';
 import { Validator, AVAILABLE_VALIDATORS } from './ValidatorListPane';
+import { useToast } from '@/app/components/Toast';
 
 interface ConfigEditorPaneProps {
   configBlob: ConfigBlob;
@@ -84,11 +85,133 @@ export default function ConfigEditorPane({
   const [isDropdownOpen, setIsDropdownOpen] = useState(false);
   const [showTooltip, setShowTooltip] = useState<number | null>(null);
   const [validatorConfig, setValidatorConfig] = useState<any>({});
+  const [showExitModal, setShowExitModal] = useState(false);
+  const [isEditMode, setIsEditMode] = useState(false);
+  const [showVersionWarningModal, setShowVersionWarningModal] = useState(false);
+  const [editingValidatorIndex, setEditingValidatorIndex] = useState<number | null>(null);
+  const [editingValidatorId, setEditingValidatorId] = useState<string | null>(null);
+  const [initialValidators, setInitialValidators] = useState<Validator[]>([]);
+  const [banLists, setBanLists] = useState<any[]>([]);
+  const [showCreateBanListModal, setShowCreateBanListModal] = useState(false);
+  const [newBanList, setNewBanList] = useState({ name: '', description:'', banned_words: '', domain: '', is_public: false });
+  const toast = useToast();
 
   const provider = configBlob.completion.provider;
   const params = configBlob.completion.params;
   const tools = (params.tools || []) as Tool[];
 
+  // Capture initial validators state when entering guardrails mode
+  React.useEffect(() => {
+    if (isGuardrailsMode) {
+      // Take a deep copy of validators when entering guardrails mode
+      setInitialValidators(JSON.parse(JSON.stringify(savedValidators)));
+    }
+  }, [isGuardrailsMode]);
+
+  // Fetch ban lists when ban-list validator is selected
+  React.useEffect(() => {
+    if ((selectedValidator === 'ban-list' || editingValidatorId === 'ban-list') && isGuardrailsMode) {
+      fetchBanLists();
+    }
+  }, [selectedValidator, editingValidatorId, isGuardrailsMode]);
+
+  const fetchBanLists = async () => {
+    try {
+      const stored = localStorage.getItem('kaapi_api_keys');
+      if (!stored) return;
+
+      const keys = JSON.parse(stored);
+      if (keys.length === 0 || !keys[0].key) return;
+
+      const apiKey = keys[0].key;
+
+      // Fetch ban lists
+      const response = await fetch('/api/guardrails/ban_lists', {
+        headers: {
+          'X-API-KEY': apiKey,
+          'Content-Type': 'application/json',
+        },
+      });
+
+      if (response.ok) {
+        const data = await response.json();
+        setBanLists(data.data || []);
+      }
+    } catch (error) {
+      console.error('Error fetching ban lists:', error);
+    }
+  };
+
+  const handleCreateBanList = async () => {
+    try {
+      const stored = localStorage.getItem('kaapi_api_keys');
+      if (!stored) {
+        toast.error('No API key found. Please add an API key first.');
+        return;
+      }
+
+      const keys = JSON.parse(stored);
+      if (keys.length === 0 || !keys[0].key) {
+        toast.error('No API key found. Please add an API key first.');
+        return;
+      }
+
+      const apiKey = keys[0].key;
+
+      // Parse banned words from textarea (split by newlines or commas)
+      const bannedWordsArray = newBanList.banned_words
+        .split(/[\n,]+/)
+        .map(word => word.trim())
+        .filter(word => word.length > 0);
+
+      // Create ban list payload
+      const payload = {
+        name: newBanList.name,
+        banned_words: bannedWordsArray,
+        domain: newBanList.domain,
+        is_public: newBanList.is_public,
+      };
+
+      // Create ban list
+      const response = await fetch('/api/guardrails/ban_lists', {
+        method: 'POST',
+        headers: {
+          'X-API-KEY': apiKey,
+          'Content-Type': 'application/json',
+        },
+        body: JSON.stringify(payload),
+      });
+
+      if (response.ok) {
+        const data = await response.json();
+        toast.success(`Ban list "${newBanList.name}" created successfully!`);
+        // Refresh ban lists
+        await fetchBanLists();
+        // Auto-select the newly created ban list
+        if (data.data && data.data.id) {
+          setValidatorConfig({ ...validatorConfig, ban_list_id: data.data.id });
+        }
+        // Reset form and close modal
+        setNewBanList({ name: '', description:'', banned_words: '', domain: '', is_public: false });
+        setShowCreateBanListModal(false);
+      } else {
+        const errorData = await response.json();
+        toast.error(`Failed to create ban list: ${errorData.error || 'Unknown error'}`);
+      }
+    } catch (error) {
+      console.error('Error creating ban list:', error);
+      toast.error('Failed to create ban list. Please try again.');
+    }
+  };
+
+  // Check if validators have changed
+  const validatorsChanged = () => {
+    if (initialValidators.length !== savedValidators.length) return true;
+
+    // Deep comparison of validator arrays
+    return JSON.stringify(initialValidators) !== JSON.stringify(savedValidators);
+  };
+
   // Group configs by config_id for nested dropdown
   const configGroups = useMemo(() => {
     const grouped = new Map<string, SavedConfig[]>();
@@ -744,22 +867,64 @@ export default function ConfigEditorPane({
             />
           </div>
 
-          {/* Add Guardrails Button */}
-          <button
-            onClick={onEnterGuardrailsMode}
-            className="w-full px-4 py-2 rounded-md text-sm font-semibold"
-            style={{
-              backgroundColor: colors.bg.primary,
-              color: colors.text.primary,
-              border: `1px solid ${colors.border}`,
-              cursor: 'pointer',
-              transition: 'all 0.15s ease',
-            }}
-            onMouseEnter={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
-            onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.primary}
-          >
-            Add Guardrails
-          </button>
+          {/* Guardrails Button */}
+          {savedValidators && savedValidators.length > 0 ? (
+            <div className="space-y-2">
+              <div
+                className="px-4 py-2 rounded-md text-sm"
+                style={{
+                  backgroundColor: colors.bg.secondary,
+                  border: `1px solid ${colors.border}`,
+                }}
+              >
+                <div className="flex items-center justify-between">
+                  <span className="font-semibold" style={{ color: colors.text.primary }}>
+                    Guardrails Configured
+                  </span>
+                  <span
+                    className="text-xs px-2 py-1 rounded"
+                    style={{
+                      backgroundColor: colors.status.success,
+                      color: '#ffffff',
+                    }}
+                  >
+                    {savedValidators.length} {savedValidators.length === 1 ? 'validator' : 'validators'}
+                  </span>
+                </div>
+              </div>
+              <button
+                onClick={onEnterGuardrailsMode}
+                className="w-full px-4 py-2 rounded-md text-sm font-semibold"
+                style={{
+                  backgroundColor: colors.bg.primary,
+                  color: colors.text.primary,
+                  border: `1px solid ${colors.border}`,
+                  cursor: 'pointer',
+                  transition: 'all 0.15s ease',
+                }}
+                onMouseEnter={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+                onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.primary}
+              >
+                Visit Guardrails Configuration
+              </button>
+            </div>
+          ) : (
+            <button
+              onClick={onEnterGuardrailsMode}
+              className="w-full px-4 py-2 rounded-md text-sm font-semibold"
+              style={{
+                backgroundColor: colors.bg.primary,
+                color: colors.text.primary,
+                border: `1px solid ${colors.border}`,
+                cursor: 'pointer',
+                transition: 'all 0.15s ease',
+              }}
+              onMouseEnter={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+              onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.primary}
+            >
+              Add Guardrails
+            </button>
+          )}
 
           {/* Save Button */}
           <button
@@ -785,10 +950,10 @@ export default function ConfigEditorPane({
         <div className="flex-1 flex flex-col overflow-hidden">
           <div className="flex-1 overflow-auto p-4">
             {/* Validator Configuration Form */}
-            {selectedValidator && (
+            {(selectedValidator || editingValidatorId) && (
               <div className="mb-6">
                 <h3 className="text-sm font-semibold mb-3" style={{ color: colors.text.primary }}>
-                  Configure {AVAILABLE_VALIDATORS.find(v => v.id === selectedValidator)?.name}
+                  {editingValidatorId ? 'Edit' : 'Configure'} {AVAILABLE_VALIDATORS.find(v => v.id === (editingValidatorId || selectedValidator))?.name}
                 </h3>
                 <div
                   className="p-4 rounded-lg space-y-3"
@@ -797,38 +962,463 @@ export default function ConfigEditorPane({
                     backgroundColor: colors.bg.secondary,
                   }}
                 >
-                  <div>
-                    <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
-                      <input
-                        type="checkbox"
-                        checked={validatorConfig.enabled || false}
-                        onChange={(e) => setValidatorConfig({ ...validatorConfig, enabled: e.target.checked })}
-                        style={{ accentColor: colors.accent.primary }}
-                      />
-                      Enabled
-                    </label>
-                  </div>
-                  <div>
-                    <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
-                      Threshold: {validatorConfig.threshold || 0.8}
-                    </label>
-                    <input
-                      type="range"
-                      min="0"
-                      max="1"
-                      step="0.1"
-                      value={validatorConfig.threshold || 0.8}
-                      onChange={(e) => setValidatorConfig({ ...validatorConfig, threshold: parseFloat(e.target.value) })}
-                      className="w-full"
-                      style={{ accentColor: colors.accent.primary }}
-                    />
-                  </div>
+                  {/* Detect PII Validator */}
+                  {(editingValidatorId || selectedValidator) === 'detect-pii' && (
+                    <>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Type
+                        </label>
+                        <input
+                          type="text"
+                          value={validatorConfig.type || 'pii_remover'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, type: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        />
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Stage
+                        </label>
+                        <select
+                          value={validatorConfig.stage || 'input'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, stage: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="input">Input</option>
+                          <option value="output">Output</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          On Fail Action
+                        </label>
+                        <select
+                          value={validatorConfig.on_fail_action || 'fix'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, on_fail_action: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="fix">Fix</option>
+                          <option value="exception">Exception</option>
+                          <option value="rephrase">Rephrase</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                          <input
+                            type="checkbox"
+                            checked={validatorConfig.is_enabled !== undefined ? validatorConfig.is_enabled : true}
+                            onChange={(e) => setValidatorConfig({ ...validatorConfig, is_enabled: e.target.checked })}
+                            style={{ accentColor: colors.accent.primary }}
+                          />
+                          Enabled
+                        </label>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Entity Types
+                        </label>
+                        <div className="space-y-2">
+                          {['PERSON', 'PHONE_NUMBER', 'IN_AADHAAR', 'EMAIL_ADDRESS', 'CREDIT_CARD', 'IP_ADDRESS'].map((entity) => (
+                            <label key={entity} className="flex items-center gap-2 text-xs" style={{ color: colors.text.primary }}>
+                              <input
+                                type="checkbox"
+                                checked={(validatorConfig.entity_types || ['PERSON', 'PHONE_NUMBER', 'IN_AADHAAR']).includes(entity)}
+                                onChange={(e) => {
+                                  const current = validatorConfig.entity_types || ['PERSON', 'PHONE_NUMBER', 'IN_AADHAAR'];
+                                  const updated = e.target.checked
+                                    ? [...current, entity]
+                                    : current.filter((t: string) => t !== entity);
+                                  setValidatorConfig({ ...validatorConfig, entity_types: updated });
+                                }}
+                                style={{ accentColor: colors.accent.primary }}
+                              />
+                              {entity}
+                            </label>
+                          ))}
+                        </div>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Threshold: {(validatorConfig.threshold !== undefined ? validatorConfig.threshold : 0.6).toFixed(1)}
+                        </label>
+                        <input
+                          type="range"
+                          min="0"
+                          max="1"
+                          step="0.1"
+                          value={validatorConfig.threshold !== undefined ? validatorConfig.threshold : 0.6}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, threshold: parseFloat(e.target.value) })}
+                          className="w-full"
+                          style={{ accentColor: colors.accent.primary }}
+                        />
+                      </div>
+                    </>
+                  )}
+
+                  {/* Lexical Slur Match Validator */}
+                  {(editingValidatorId || selectedValidator) === 'lexical-slur-match' && (
+                    <>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Stage
+                        </label>
+                        <select
+                          value={validatorConfig.stage || 'input'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, stage: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="input">Input</option>
+                          <option value="output">Output</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          On Fail Action
+                        </label>
+                        <input
+                          type="text"
+                          value={validatorConfig.on_fail || 'fix'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, on_fail: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        />
+                      </div>
+                      <div>
+                        <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                          <input
+                            type="checkbox"
+                            checked={validatorConfig.enabled !== undefined ? validatorConfig.enabled : true}
+                            onChange={(e) => setValidatorConfig({ ...validatorConfig, enabled: e.target.checked })}
+                            style={{ accentColor: colors.accent.primary }}
+                          />
+                          Enabled
+                        </label>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Languages
+                        </label>
+                        <div className="space-y-2">
+                          {['en', 'hi'].map((lang) => (
+                            <label key={lang} className="flex items-center gap-2 text-xs" style={{ color: colors.text.primary }}>
+                              <input
+                                type="checkbox"
+                                checked={(validatorConfig.languages || ['en', 'hi']).includes(lang)}
+                                onChange={(e) => {
+                                  const current = validatorConfig.languages || ['en', 'hi'];
+                                  const updated = e.target.checked
+                                    ? [...current, lang]
+                                    : current.filter((l: string) => l !== lang);
+                                  setValidatorConfig({ ...validatorConfig, languages: updated });
+                                }}
+                                style={{ accentColor: colors.accent.primary }}
+                              />
+                              {lang === 'en' ? 'English' : 'Hindi'}
+                            </label>
+                          ))}
+                        </div>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Severity
+                        </label>
+                        <input
+                          type="text"
+                          value={validatorConfig.severity || 'all'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, severity: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        />
+                      </div>
+                    </>
+                  )}
+
+                  {/* Gender Assumption Bias Validator */}
+                  {(editingValidatorId || selectedValidator) === 'gender-assumption-bias' && (
+                    <>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Stage
+                        </label>
+                        <select
+                          value={validatorConfig.stage || 'input'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, stage: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="input">Input</option>
+                          <option value="output">Output</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          On Fail Action
+                        </label>
+                        <select
+                          value={validatorConfig.on_fail_action || 'fix'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, on_fail_action: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="fix">Fix</option>
+                          <option value="exception">Exception</option>
+                          <option value="rephrase">Rephrase</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                          <input
+                            type="checkbox"
+                            checked={validatorConfig.enabled !== undefined ? validatorConfig.enabled : true}
+                            onChange={(e) => setValidatorConfig({ ...validatorConfig, enabled: e.target.checked })}
+                            style={{ accentColor: colors.accent.primary }}
+                          />
+                          Enabled
+                        </label>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Bias Category
+                        </label>
+                        <select
+                          value={validatorConfig.bias_category || 'all'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, bias_category: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="generic">Generic</option>
+                          <option value="healthcare">Healthcare</option>
+                          <option value="education">Education</option>
+                          <option value="all">All</option>
+                        </select>
+                      </div>
+                    </>
+                  )}
+
+                  {/* Ban List Validator */}
+                  {(editingValidatorId || selectedValidator) === 'ban-list' && (
+                    <>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Stage
+                        </label>
+                        <select
+                          value={validatorConfig.stage || 'input'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, stage: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="input">Input</option>
+                          <option value="output">Output</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                          <input
+                            type="checkbox"
+                            checked={validatorConfig.enabled !== undefined ? validatorConfig.enabled : true}
+                            onChange={(e) => setValidatorConfig({ ...validatorConfig, enabled: e.target.checked })}
+                            style={{ accentColor: colors.accent.primary }}
+                          />
+                          Enabled
+                        </label>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          On Fail Action
+                        </label>
+                        <select
+                          value={validatorConfig.on_fail_action || 'exception'}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, on_fail_action: e.target.value })}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="fix">Fix</option>
+                          <option value="exception">Exception</option>
+                          <option value="rephrase">Rephrase</option>
+                        </select>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Ban List
+                        </label>
+                        <select
+                          value={validatorConfig.ban_list_id || ''}
+                          onChange={(e) => {
+                            if (e.target.value === 'create-new') {
+                              setShowCreateBanListModal(true);
+                            } else {
+                              setValidatorConfig({ ...validatorConfig, ban_list_id: e.target.value });
+                            }
+                          }}
+                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                          style={{
+                            border: `1px solid ${colors.border}`,
+                            backgroundColor: colors.bg.primary,
+                            color: colors.text.primary,
+                          }}
+                        >
+                          <option value="">Select a ban list...</option>
+                          <option value="create-new" style={{ fontWeight: 600 }}>+ Create New Ban List</option>
+                          {banLists.map((list) => (
+                            <option key={list.id} value={list.id}>
+                              {list.name} ({list.banned_words?.length || 0} words)
+                            </option>
+                          ))}
+                        </select>
+                      </div>
+                    </>
+                  )}
+
+                  {/* Generic Validator Configuration */}
+                  {(editingValidatorId || selectedValidator) !== 'detect-pii' && (editingValidatorId || selectedValidator) !== 'lexical-slur-match' && (editingValidatorId || selectedValidator) !== 'gender-assumption-bias' && (editingValidatorId || selectedValidator) !== 'ban-list' && (
+                    <>
+                      <div>
+                        <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                          <input
+                            type="checkbox"
+                            checked={validatorConfig.enabled || false}
+                            onChange={(e) => setValidatorConfig({ ...validatorConfig, enabled: e.target.checked })}
+                            style={{ accentColor: colors.accent.primary }}
+                          />
+                          Enabled
+                        </label>
+                      </div>
+                      <div>
+                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
+                          Threshold: {validatorConfig.threshold || 0.8}
+                        </label>
+                        <input
+                          type="range"
+                          min="0"
+                          max="1"
+                          step="0.1"
+                          value={validatorConfig.threshold || 0.8}
+                          onChange={(e) => setValidatorConfig({ ...validatorConfig, threshold: parseFloat(e.target.value) })}
+                          className="w-full"
+                          style={{ accentColor: colors.accent.primary }}
+                        />
+                      </div>
+                    </>
+                  )}
+
                   <button
                     onClick={() => {
-                      const validator = AVAILABLE_VALIDATORS.find(v => v.id === selectedValidator);
+                      const currentValidatorId = editingValidatorId || selectedValidator;
+                      const validator = AVAILABLE_VALIDATORS.find(v => v.id === currentValidatorId);
                       if (validator && onSaveValidator) {
-                        onSaveValidator({ ...validator, config: validatorConfig });
+                        // Merge default values with user-provided values
+                        let finalConfig = { ...validatorConfig };
+
+                        if (currentValidatorId === 'detect-pii') {
+                          finalConfig = {
+                            type: validatorConfig.type || 'pii_remover',
+                            stage: validatorConfig.stage || 'input',
+                            on_fail_action: validatorConfig.on_fail_action || 'fix',
+                            is_enabled: validatorConfig.is_enabled !== undefined ? validatorConfig.is_enabled : true,
+                            entity_types: validatorConfig.entity_types || ['PERSON', 'PHONE_NUMBER', 'IN_AADHAAR'],
+                            threshold: validatorConfig.threshold !== undefined ? validatorConfig.threshold : 0.6,
+                          };
+                        } else if (currentValidatorId === 'lexical-slur-match') {
+                          finalConfig = {
+                            type: validatorConfig.type || 'uli_slur_match',
+                            stage: validatorConfig.stage || 'input',
+                            on_fail: validatorConfig.on_fail || 'fix',
+                            enabled: validatorConfig.enabled !== undefined ? validatorConfig.enabled : true,
+                            languages: validatorConfig.languages || ['en', 'hi'],
+                            severity: validatorConfig.severity || 'all',
+                          };
+                        } else if (currentValidatorId === 'gender-assumption-bias') {
+                          finalConfig = {
+                            type: validatorConfig.type || 'gender_assumption_bias',
+                            stage: validatorConfig.stage || 'input',
+                            on_fail_action: validatorConfig.on_fail_action || 'fix',
+                            enabled: validatorConfig.enabled !== undefined ? validatorConfig.enabled : true,
+                            bias_category: validatorConfig.bias_category || 'all',
+                          };
+                        } else if (currentValidatorId === 'ban-list') {
+                          finalConfig = {
+                            type: validatorConfig.type || 'ban_list',
+                            stage: validatorConfig.stage || 'input',
+                            enabled: validatorConfig.enabled !== undefined ? validatorConfig.enabled : true,
+                            on_fail_action: validatorConfig.on_fail_action || 'exception',
+                            ban_list_id: validatorConfig.ban_list_id || '',
+                          };
+                        } else {
+                          finalConfig = {
+                            type: validatorConfig.type || 'topic_relevance',
+                            enabled: validatorConfig.enabled || false,
+                            threshold: validatorConfig.threshold || 0.8,
+                          };
+                        }
+
+                        // If editing, remove the old validator first, then add updated one
+                        if (editingValidatorIndex !== null && onRemoveValidator) {
+                          onRemoveValidator(editingValidatorIndex);
+                        }
+
+                        // Save the validator (create new or update)
+                        onSaveValidator({
+                          id: validator.id,
+                          name: validator.name,
+                          description: validator.description,
+                          tags: validator.tags,
+                          config: finalConfig
+                        });
+
+                        // Reset state
                         setValidatorConfig({});
+                        setEditingValidatorIndex(null);
+                        setEditingValidatorId(null);
                       }
                     }}
                     className="w-full px-4 py-2 rounded-md text-sm font-semibold"
@@ -839,55 +1429,204 @@ export default function ConfigEditorPane({
                       cursor: 'pointer',
                     }}
                   >
-                    Save Validator
+                    {editingValidatorId ? 'Update Validator' : 'Save Validator'}
                   </button>
                 </div>
               </div>
             )}
 
+            {/* No Validator Selected - Empty State */}
+            {!selectedValidator && savedValidators.length === 0 && (
+              <div className="flex flex-col items-center justify-center py-12 px-4">
+                <svg
+                  className="w-16 h-16 mb-4"
+                  fill="none"
+                  viewBox="0 0 24 24"
+                  stroke="currentColor"
+                  style={{ color: colors.text.secondary, opacity: 0.5 }}
+                >
+                  <path
+                    strokeLinecap="round"
+                    strokeLinejoin="round"
+                    strokeWidth={1.5}
+                    d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
+                  />
+                </svg>
+                <p
+                  className="text-sm font-medium text-center"
+                  style={{ color: colors.text.secondary }}
+                >
+                  Select any validator from the list
+                </p>
+                <p
+                  className="text-xs text-center mt-2"
+                  style={{ color: colors.text.secondary, opacity: 0.7 }}
+                >
+                  Choose a validator to configure its settings
+                </p>
+              </div>
+            )}
+
             {/* Saved Validators */}
             {savedValidators.length > 0 && (
               <div>
-                <h3 className="text-sm font-semibold mb-3" style={{ color: colors.text.primary }}>
-                  Configured Validators ({savedValidators.length})
-                </h3>
-                <div className="space-y-2">
-                  {savedValidators.map((validator, idx) => (
-                    <div
-                      key={idx}
-                      className="p-3 rounded-lg"
+                <div className="flex items-center justify-between mb-3">
+                  <h3 className="text-sm font-semibold" style={{ color: colors.text.primary }}>
+                    Configured Validators ({savedValidators.length})
+                  </h3>
+                  {!isEditMode && (
+                    <button
+                      onClick={() => setShowVersionWarningModal(true)}
+                      className="px-3 py-1.5 rounded-md text-xs font-medium flex items-center gap-1.5"
                       style={{
-                        border: `1px solid ${colors.border}`,
                         backgroundColor: colors.bg.primary,
+                        color: colors.text.primary,
+                        border: `1px solid ${colors.border}`,
+                        cursor: 'pointer',
+                        transition: 'all 0.15s ease',
                       }}
+                      onMouseEnter={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+                      onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.primary}
                     >
-                      <div className="flex items-start justify-between">
-                        <div className="flex items-start gap-2">
-                          <div>
-                            <div className="font-semibold text-sm" style={{ color: colors.text.primary }}>
-                              {validator.name}
+                      <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" />
+                      </svg>
+                      Edit
+                    </button>
+                  )}
+                </div>
+
+                {/* Input Validators */}
+                {(() => {
+                  const inputValidators = savedValidators.filter(v => (v.config?.stage || 'input') === 'input');
+                  return inputValidators.length > 0 && (
+                    <div className="mb-4">
+                      <h4 className="text-xs font-semibold mb-2" style={{ color: colors.text.secondary }}>
+                        Input Validators
+                      </h4>
+                      <div className="space-y-2">
+                        {inputValidators.map((validator) => {
+                          const originalIdx = savedValidators.indexOf(validator);
+                          const isSelected = editingValidatorIndex === originalIdx;
+                          return (
+                            <div
+                              key={originalIdx}
+                              className="p-3 rounded-lg"
+                              style={{
+                                border: `1px solid ${isSelected ? colors.accent.primary : colors.border}`,
+                                backgroundColor: isSelected ? colors.bg.secondary : colors.bg.primary,
+                                transition: 'all 0.15s ease',
+                              }}
+                            >
+                              <div className="flex items-start justify-between">
+                                <div className="flex items-start gap-2">
+                                  <div>
+                                    <div className="font-semibold text-sm" style={{ color: colors.text.primary }}>
+                                      {validator.name}
+                                    </div>
+                                    <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
+                                      {(() => {
+                                        const isEnabled = validator.config?.is_enabled ?? validator.config?.enabled ?? true;
+                                        return isEnabled ? 'Enabled' : 'Disabled';
+                                      })()}
+                                    </div>
+                                  </div>
+                                </div>
+                                {isEditMode && (
+                                  <div className="flex items-center gap-2">
+                                    {/* Remove Button */}
+                                    <button
+                                      onClick={() => onRemoveValidator && onRemoveValidator(originalIdx)}
+                                      className="p-1.5 rounded-md transition-colors"
+                                      style={{
+                                        backgroundColor: colors.bg.secondary,
+                                        border: 'none',
+                                        cursor: 'pointer',
+                                      }}
+                                      onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#fee'}
+                                      onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+                                      title="Remove validator"
+                                    >
+                                      <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: colors.status.error }}>
+                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
+                                      </svg>
+                                    </button>
+                                  </div>
+                                )}
+                              </div>
                             </div>
-                            <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
-                              Threshold: {validator.config?.threshold || 0.8} • {validator.config?.enabled ? 'Enabled' : 'Disabled'}
+                          );
+                        })}
+                      </div>
+                    </div>
+                  );
+                })()}
+
+                {/* Output Validators */}
+                {(() => {
+                  const outputValidators = savedValidators.filter(v => v.config?.stage === 'output');
+                  return outputValidators.length > 0 && (
+                    <div>
+                      <h4 className="text-xs font-semibold mb-2" style={{ color: colors.text.secondary }}>
+                        Output Validators
+                      </h4>
+                      <div className="space-y-2">
+                        {outputValidators.map((validator) => {
+                          const originalIdx = savedValidators.indexOf(validator);
+                          const isSelected = editingValidatorIndex === originalIdx;
+                          return (
+                            <div
+                              key={originalIdx}
+                              className="p-3 rounded-lg"
+                              style={{
+                                border: `1px solid ${isSelected ? colors.accent.primary : colors.border}`,
+                                backgroundColor: isSelected ? colors.bg.secondary : colors.bg.primary,
+                                transition: 'all 0.15s ease',
+                              }}
+                            >
+                              <div className="flex items-start justify-between">
+                                <div className="flex items-start gap-2">
+                                  <div>
+                                    <div className="font-semibold text-sm" style={{ color: colors.text.primary }}>
+                                      {validator.name}
+                                    </div>
+                                    <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
+                                      {(() => {
+                                        const isEnabled = validator.config?.is_enabled ?? validator.config?.enabled ?? true;
+                                        return isEnabled ? 'Enabled' : 'Disabled';
+                                      })()}
+                                    </div>
+                                  </div>
+                                </div>
+                                {isEditMode && (
+                                  <div className="flex items-center gap-2">
+                                    {/* Remove Button */}
+                                    <button
+                                      onClick={() => onRemoveValidator && onRemoveValidator(originalIdx)}
+                                      className="p-1.5 rounded-md transition-colors"
+                                      style={{
+                                        backgroundColor: colors.bg.secondary,
+                                        border: 'none',
+                                        cursor: 'pointer',
+                                      }}
+                                      onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#fee'}
+                                      onMouseLeave={(e) => e.currentTarget.style.backgroundColor = colors.bg.secondary}
+                                      title="Remove validator"
+                                    >
+                                      <svg className="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" style={{ color: colors.status.error }}>
+                                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
+                                      </svg>
+                                    </button>
+                                  </div>
+                                )}
+                              </div>
                             </div>
-                          </div>
-                        </div>
-                        <button
-                          onClick={() => onRemoveValidator && onRemoveValidator(idx)}
-                          className="text-xs"
-                          style={{
-                            color: colors.status.error,
-                            background: 'none',
-                            border: 'none',
-                            cursor: 'pointer',
-                          }}
-                        >
-                          Remove
-                        </button>
+                          );
+                        })}
                       </div>
                     </div>
-                  ))}
-                </div>
+                  );
+                })()}
               </div>
             )}
           </div>
@@ -899,9 +1638,16 @@ export default function ConfigEditorPane({
           >
             <button
               onClick={() => {
-                if (onExitGuardrailsMode) {
-                  onExitGuardrailsMode();
-                  setValidatorConfig({});
+                // Only show modal if validators have changed
+                if (validatorsChanged()) {
+                  setShowExitModal(true);
+                } else {
+                  // No changes, exit directly
+                  if (onExitGuardrailsMode) {
+                    onExitGuardrailsMode();
+                    setValidatorConfig({});
+                    setIsEditMode(false);
+                  }
                 }
               }}
               className="w-full px-4 py-2 rounded-md text-sm font-semibold"
@@ -920,6 +1666,323 @@ export default function ConfigEditorPane({
           </div>
         </div>
       )}
+
+      {/* Exit Confirmation Modal */}
+      {showExitModal && (
+        <>
+          {/* Backdrop */}
+          <div
+            className="fixed inset-0 z-50"
+            style={{
+              backgroundColor: 'rgba(0, 0, 0, 0.5)',
+            }}
+            onClick={() => setShowExitModal(false)}
+          />
+
+          {/* Modal */}
+          <div
+            className="fixed top-1/2 left-1/2 z-50 w-full max-w-md rounded-lg shadow-lg p-6"
+            style={{
+              transform: 'translate(-50%, -50%)',
+              backgroundColor: colors.bg.primary,
+              border: `1px solid ${colors.border}`,
+            }}
+          >
+            <div className="flex items-start gap-4">
+              <svg
+                className="w-6 h-6 flex-shrink-0 mt-0.5"
+                fill="none"
+                viewBox="0 0 24 24"
+                stroke="currentColor"
+                style={{ color: colors.accent.primary }}
+              >
+                <path
+                  strokeLinecap="round"
+                  strokeLinejoin="round"
+                  strokeWidth={2}
+                  d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
+                />
+              </svg>
+              <div className="flex-1">
+                <h3
+                  className="text-lg font-semibold mb-2"
+                  style={{ color: colors.text.primary }}
+                >
+                  Confirm Guardrails Configuration
+                </h3>
+                <p className="text-sm mb-6" style={{ color: colors.text.secondary }}>
+                  Do you want to go ahead with using the validators you have configured?
+                </p>
+                <div className="flex gap-3 justify-end">
+                  <button
+                    onClick={() => setShowExitModal(false)}
+                    className="px-4 py-2 rounded-md text-sm font-medium"
+                    style={{
+                      backgroundColor: colors.bg.secondary,
+                      color: colors.text.primary,
+                      border: `1px solid ${colors.border}`,
+                      cursor: 'pointer',
+                    }}
+                  >
+                    Cancel
+                  </button>
+                  <button
+                    onClick={() => {
+                      setShowExitModal(false);
+                      if (onExitGuardrailsMode) {
+                        onExitGuardrailsMode();
+                        setValidatorConfig({});
+                        setIsEditMode(false);
+                      }
+                    }}
+                    className="px-4 py-2 rounded-md text-sm font-semibold"
+                    style={{
+                      backgroundColor: colors.status.success,
+                      color: '#ffffff',
+                      border: 'none',
+                      cursor: 'pointer',
+                    }}
+                  >
+                    Done
+                  </button>
+                </div>
+              </div>
+            </div>
+          </div>
+        </>
+      )}
+
+      {/* Version Warning Modal */}
+      {showVersionWarningModal && (
+        <>
+          {/* Backdrop */}
+          <div
+            className="fixed inset-0 z-50"
+            style={{
+              backgroundColor: 'rgba(0, 0, 0, 0.5)',
+            }}
+            onClick={() => setShowVersionWarningModal(false)}
+          />
+
+          {/* Modal */}
+          <div
+            className="fixed top-1/2 left-1/2 z-50 w-full max-w-md rounded-lg shadow-lg p-6"
+            style={{
+              transform: 'translate(-50%, -50%)',
+              backgroundColor: colors.bg.primary,
+              border: `1px solid ${colors.border}`,
+            }}
+          >
+            <div className="flex items-start gap-4">
+              <div className="flex-1">
+                <h3
+                  className="text-lg font-semibold mb-2"
+                  style={{ color: colors.text.primary }}
+                >
+                  Edit Guardrails Configuration
+                </h3>
+                <p className="text-sm mb-6" style={{ color: colors.text.secondary }}>
+                  If you edit these validators, a whole new version of the configuration will be created when you save. Do you want to continue?
+                </p>
+                <div className="flex gap-3 justify-end">
+                  <button
+                    onClick={() => setShowVersionWarningModal(false)}
+                    className="px-4 py-2 rounded-md text-sm font-medium"
+                    style={{
+                      backgroundColor: colors.bg.secondary,
+                      color: colors.text.primary,
+                      border: `1px solid ${colors.border}`,
+                      cursor: 'pointer',
+                    }}
+                  >
+                    Cancel
+                  </button>
+                  <button
+                    onClick={() => {
+                      setShowVersionWarningModal(false);
+                      setIsEditMode(true);
+                    }}
+                    className="px-4 py-2 rounded-md text-sm font-semibold"
+                    style={{
+                      backgroundColor: colors.accent.primary,
+                      color: '#ffffff',
+                      border: 'none',
+                      cursor: 'pointer',
+                    }}
+                  >
+                    Okay, Continue
+                  </button>
+                </div>
+              </div>
+            </div>
+          </div>
+        </>
+      )}
+
+      {/* Create Ban List Modal */}
+      {showCreateBanListModal && (
+        <>
+          {/* Backdrop */}
+          <div
+            className="fixed inset-0 z-50"
+            style={{
+              backgroundColor: 'rgba(0, 0, 0, 0.5)',
+            }}
+            onClick={() => {
+              setShowCreateBanListModal(false);
+              setNewBanList({ name: '', description:'', banned_words: '', domain: '', is_public: false });
+            }}
+          />
+
+          {/* Modal */}
+          <div
+            className="fixed top-1/2 left-1/2 z-50 w-full max-w-lg rounded-lg shadow-lg p-6"
+            style={{
+              transform: 'translate(-50%, -50%)',
+              backgroundColor: colors.bg.primary,
+              border: `1px solid ${colors.border}`,
+            }}
+          >
+            <h3
+              className="text-lg font-semibold mb-4"
+              style={{ color: colors.text.primary }}
+            >
+              Create New Ban List
+            </h3>
+
+            <div className="space-y-4">
+              {/* Name */}
+              <div>
+                <label className="block text-sm font-semibold mb-2" style={{ color: colors.text.primary }}>
+                  Name *
+                </label>
+                <input
+                  type="text"
+                  value={newBanList.name}
+                  onChange={(e) => setNewBanList({ ...newBanList, name: e.target.value })}
+                  placeholder="e.g., profanity-filter"
+                  className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                  style={{
+                    border: `1px solid ${colors.border}`,
+                    backgroundColor: colors.bg.primary,
+                    color: colors.text.primary,
+                  }}
+                />
+              </div>
+
+              <div>
+                <label className="block text-sm font-semibold mb-2" style={{ color: colors.text.primary }}>
+                  Description *
+                </label>
+                <input
+                  type="text"
+                  value={newBanList.description}
+                  onChange={(e) => setNewBanList({ ...newBanList, description: e.target.value })}
+                  placeholder="e.g., profanity-filter"
+                  className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                  style={{
+                    border: `1px solid ${colors.border}`,
+                    backgroundColor: colors.bg.primary,
+                    color: colors.text.primary,
+                  }}
+                />
+              </div>
+
+              {/* Banned Words */}
+              <div>
+                <label className="block text-sm font-semibold mb-2" style={{ color: colors.text.primary }}>
+                  Banned Words *
+                </label>
+                <textarea
+                  value={newBanList.banned_words}
+                  onChange={(e) => setNewBanList({ ...newBanList, banned_words: e.target.value })}
+                  placeholder="Enter words separated by commas or new lines&#10;e.g., word1, word2&#10;word3"
+                  rows={5}
+                  className="w-full px-3 py-2 rounded-md text-sm focus:outline-none resize-none"
+                  style={{
+                    border: `1px solid ${colors.border}`,
+                    backgroundColor: colors.bg.primary,
+                    color: colors.text.primary,
+                  }}
+                />
+                <p className="text-xs mt-1" style={{ color: colors.text.secondary }}>
+                  Separate words with commas or new lines
+                </p>
+              </div>
+
+              {/* Domain */}
+              <div>
+                <label className="block text-sm font-semibold mb-2" style={{ color: colors.text.primary }}>
+                  Domain
+                </label>
+                <input
+                  type="text"
+                  value={newBanList.domain}
+                  onChange={(e) => setNewBanList({ ...newBanList, domain: e.target.value })}
+                  placeholder="e.g., general, healthcare"
+                  className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
+                  style={{
+                    border: `1px solid ${colors.border}`,
+                    backgroundColor: colors.bg.primary,
+                    color: colors.text.primary,
+                  }}
+                />
+              </div>
+
+              {/* Is Public */}
+              <div>
+                <label className="flex items-center gap-2 text-sm" style={{ color: colors.text.primary }}>
+                  <input
+                    type="checkbox"
+                    checked={newBanList.is_public}
+                    onChange={(e) => setNewBanList({ ...newBanList, is_public: e.target.checked })}
+                    style={{ accentColor: colors.accent.primary }}
+                  />
+                  Make this ban list public
+                </label>
+              </div>
+            </div>
+
+            {/* Actions */}
+            <div className="flex gap-3 justify-end mt-6">
+              <button
+                onClick={() => {
+                  setShowCreateBanListModal(false);
+                  setNewBanList({ name: '', banned_words: '', domain: '', is_public: false });
+                }}
+                className="px-4 py-2 rounded-md text-sm font-medium"
+                style={{
+                  backgroundColor: colors.bg.secondary,
+                  color: colors.text.primary,
+                  border: `1px solid ${colors.border}`,
+                  cursor: 'pointer',
+                }}
+              >
+                Cancel
+              </button>
+              <button
+                onClick={handleCreateBanList}
+                disabled={!newBanList.name.trim() || !newBanList.banned_words.trim()}
+                className="px-4 py-2 rounded-md text-sm font-semibold"
+                style={{
+                  backgroundColor: !newBanList.name.trim() || !newBanList.banned_words.trim()
+                    ? colors.bg.secondary
+                    : colors.status.success,
+                  color: !newBanList.name.trim() || !newBanList.banned_words.trim()
+                    ? colors.text.secondary
+                    : '#ffffff',
+                  border: 'none',
+                  cursor: !newBanList.name.trim() || !newBanList.banned_words.trim()
+                    ? 'not-allowed'
+                    : 'pointer',
+                }}
+              >
+                Create Ban List
+              </button>
+            </div>
+          </div>
+        </>
+      )}
     </div>
   );
 }
diff --git a/app/components/prompt-editor/ValidatorListPane.tsx b/app/components/prompt-editor/ValidatorListPane.tsx
index cbe916b..b411d35 100644
--- a/app/components/prompt-editor/ValidatorListPane.tsx
+++ b/app/components/prompt-editor/ValidatorListPane.tsx
@@ -6,9 +6,11 @@ export interface Validator {
   name: string;
   description: string;
   tags: string[];
+  validator_config_id?: string; // ID returned from backend after saving
   config?: {
     threshold?: number;
     enabled?: boolean;
+    stage?: string;
     [key: string]: any;
   };
 }
@@ -20,12 +22,6 @@ export const AVAILABLE_VALIDATORS: Validator[] = [
     description: 'Validates that the output does not contain banned words, using fuzzy search.',
     tags: ['STRING', 'BRAND RISK'],
   },
-  {
-    id: 'bias-check',
-    name: 'Bias Check',
-    description: 'Validates that the text is free from biases related to age, gender, sex, ethnicity,...',
-    tags: ['STRING', 'BRAND RISK'],
-  },
   {
     id: 'detect-pii',
     name: 'Detect PII',
@@ -33,10 +29,16 @@ export const AVAILABLE_VALIDATORS: Validator[] = [
     tags: ['STRING', 'DATA LEAKAGE'],
   },
   {
-    id: 'extractive-summary',
-    name: 'Extractive Summary',
-    description: 'Uses fuzzy matching to detect if some text is a summary of a document.',
-    tags: ['STRING', 'FACTUALITY'],
+    id: 'lexical-slur-match',
+    name: 'Lexical Slur Match',
+    description: 'Detects and filters offensive slurs in multiple languages using lexical matching.',
+    tags: ['STRING', 'BRAND RISK'],
+  },
+  {
+    id: 'gender-assumption-bias',
+    name: 'Gender Assumption Bias',
+    description: 'Detects gender assumption biases across different domains like healthcare and education.',
+    tags: ['STRING', 'BRAND RISK'],
   },
 ];
 
diff --git a/app/configurations/prompt-editor/page.tsx b/app/configurations/prompt-editor/page.tsx
index 141aafd..9776248 100644
--- a/app/configurations/prompt-editor/page.tsx
+++ b/app/configurations/prompt-editor/page.tsx
@@ -23,7 +23,7 @@ import HistorySidebar from '@/app/components/prompt-editor/HistorySidebar';
 import PromptEditorPane from '@/app/components/prompt-editor/PromptEditorPane';
 import ConfigEditorPane from '@/app/components/prompt-editor/ConfigEditorPane';
 import DiffView from '@/app/components/prompt-editor/DiffView';
-import ValidatorListPane, { Validator } from '@/app/components/prompt-editor/ValidatorListPane';
+import ValidatorListPane, { Validator, AVAILABLE_VALIDATORS } from '@/app/components/prompt-editor/ValidatorListPane';
 import { useToast } from '@/app/components/Toast';
 import Loader from '@/app/components/Loader';
 import { useConfigs, invalidateConfigCache, SavedConfig } from '@/app/lib/useConfigs';
@@ -89,6 +89,15 @@ function PromptEditorContent() {
   const [selectedValidator, setSelectedValidator] = useState<string | null>(null);
   const [savedValidators, setSavedValidators] = useState<Validator[]>([]);
 
+  // Mapping from backend validator type to frontend validator id
+  const VALIDATOR_TYPE_TO_ID: Record<string, string> = {
+    'pii_remover': 'detect-pii',
+    'uli_slur_match': 'lexical-slur-match',
+    'gender_assumption_bias': 'gender-assumption-bias',
+    'ban_list': 'ban-list',
+    'topic_relevance': 'topic-relevance',
+  };
+
   // Get API key from localStorage
   const getApiKey = (): string | null => {
     try {
@@ -163,6 +172,25 @@ function PromptEditorContent() {
         setCurrentConfigVersion(targetConfig.version);
         setTools(targetConfig.tools || []);
 
+        // Load guardrails if this config has them
+        if (targetConfig.hasGuardrails) {
+          const apiKey = getApiKey();
+          if (apiKey) {
+            fetch(`/api/configs/${targetConfig.config_id}/versions/${targetConfig.version}`, {
+              headers: { 'X-API-KEY': apiKey },
+            })
+              .then(res => res.json())
+              .then(data => {
+                if (data.success && data.data && data.data.config_blob) {
+                  loadGuardrailsFromConfig(data.data.config_blob);
+                }
+              })
+              .catch(error => console.error('Failed to load guardrails:', error));
+          }
+        } else {
+          setSavedValidators([]);
+        }
+
         // If history is requested, show the history sidebar with this version selected
         if (showHistory) {
           setSelectedVersion(targetConfig);
@@ -235,7 +263,21 @@ function PromptEditorContent() {
         }
       });
 
-      const configBlob: ConfigBlob = {
+      // Build guardrails arrays from saved validators
+      console.log('[DEBUG] Saved validators:', savedValidators);
+
+      const inputGuardrails = savedValidators
+        .filter(v => (v.config?.stage || 'input') === 'input' && v.validator_config_id)
+        .map(v => ({ validator_config_id: v.validator_config_id! }));
+
+      const outputGuardrails = savedValidators
+        .filter(v => v.config?.stage === 'output' && v.validator_config_id)
+        .map(v => ({ validator_config_id: v.validator_config_id! }));
+
+      console.log('[DEBUG] Input guardrails:', inputGuardrails);
+      console.log('[DEBUG] Output guardrails:', outputGuardrails);
+
+      const configBlob: any = {
         completion: {
           provider: currentConfigBlob.completion.provider,
           type: currentConfigBlob.completion.type || 'text', // Default to 'text'
@@ -250,6 +292,9 @@ function PromptEditorContent() {
             }),
           },
         },
+        // Include guardrails if any validators are configured
+        ...(inputGuardrails.length > 0 && { input_guardrails: inputGuardrails }),
+        ...(outputGuardrails.length > 0 && { output_guardrails: outputGuardrails }),
       };
 
       console.log('[DEBUG] Config blob being sent:', JSON.stringify(configBlob, null, 2));
@@ -325,7 +370,7 @@ function PromptEditorContent() {
   };
 
   // Load a saved configuration by ID
-  const handleLoadConfigById = (configId: string) => {
+  const handleLoadConfigById = async (configId: string) => {
     if (!configId) {
       // Reset to new config
       setCurrentContent('');
@@ -337,6 +382,7 @@ function PromptEditorContent() {
       setCurrentConfigParentId('');
       setCurrentConfigVersion(0);
       setTools([]);
+      setSavedValidators([]);
       return;
     }
 
@@ -363,6 +409,31 @@ function PromptEditorContent() {
     setCurrentConfigParentId(config.config_id);
     setCurrentConfigVersion(config.version);
     setTools(config.tools || []);
+
+    // Always fetch config blob to check for guardrails
+    const apiKey = getApiKey();
+    if (apiKey) {
+      try {
+        // Fetch full config version to get config_blob
+        const response = await fetch(
+          `/api/configs/${config.config_id}/versions/${config.version}`,
+          {
+            headers: { 'X-API-KEY': apiKey },
+          }
+        );
+        const data = await response.json();
+        if (data.success && data.data && data.data.config_blob) {
+          await loadGuardrailsFromConfig(data.data.config_blob);
+        } else {
+          setSavedValidators([]);
+        }
+      } catch (error) {
+        console.error('Failed to load guardrails:', error);
+        setSavedValidators([]);
+      }
+    } else {
+      setSavedValidators([]);
+    }
   };
 
   // Guardrails handlers
@@ -380,13 +451,337 @@ function PromptEditorContent() {
     setSelectedValidator(validatorId);
   };
 
-  const handleSaveValidator = (validator: Validator) => {
-    setSavedValidators([...savedValidators, validator]);
-    setSelectedValidator(null);
+  const handleSaveValidator = async (validator: Validator) => {
+    // Get API key from localStorage
+    const apiKey = getApiKey();
+    if (!apiKey) {
+      toast.error('No API key found. Please add an API key in the Keystore.');
+      return;
+    }
+
+    // Get guardrails token from localStorage
+    const getGuardrailsToken = (): string | null => {
+      try {
+        const stored = localStorage.getItem('kaapi_api_keys');
+        if (stored) {
+          const keys = JSON.parse(stored);
+          if (keys.length > 0 && keys[0].guardrails_token) {
+            return keys[0].guardrails_token;
+          }
+        }
+      } catch (e) {
+        console.error('Failed to get guardrails token:', e);
+      }
+      return null;
+    };
+
+    const guardrailsToken = getGuardrailsToken();
+    if (!guardrailsToken) {
+      toast.error('No guardrails token found. Please add a guardrails token in the Keystore.');
+      return;
+    }
+
+    try {
+      // Get actual organization_id and project_id from API key verification
+      const verifyResponse = await fetch('/api/apikeys/verify', {
+        method: 'GET',
+        headers: {
+          'X-API-KEY': apiKey,
+        },
+      });
+
+      const verifyData = await verifyResponse.json();
+
+      if (!verifyResponse.ok || !verifyData.success) {
+        toast.error('Failed to verify API key. Please check your credentials.');
+        return;
+      }
+
+      const { organization_id, project_id } = verifyData.data;
+
+      // Make API call to save validator configuration
+      console.log('[DEBUG] Saving validator config:', JSON.stringify(validator.config, null, 2));
+      console.log('[DEBUG] Request URL:', `/api/guardrails/validators/configs?organization_id=${organization_id}&project_id=${project_id}`);
+
+      const response = await fetch(
+        `/api/guardrails/validators/configs?organization_id=${organization_id}&project_id=${project_id}`,
+        {
+          method: 'POST',
+          headers: {
+            'Authorization': `Bearer ${guardrailsToken}`,
+            'Content-Type': 'application/json',
+          },
+          body: JSON.stringify(validator.config),
+        }
+      );
+
+      console.log('[DEBUG] Response status:', response.status, response.statusText);
+
+      // Try to parse response as JSON, fallback to text if it fails
+      let data: any = {};
+      const contentType = response.headers.get('content-type');
+      try {
+        if (contentType && contentType.includes('application/json')) {
+          data = await response.json();
+        } else {
+          const text = await response.text();
+          console.log('[DEBUG] Response text (non-JSON):', text);
+          data = { error: text || 'Empty response' };
+        }
+      } catch (parseError) {
+        console.error('[DEBUG] Failed to parse response:', parseError);
+        const text = await response.text();
+        console.log('[DEBUG] Raw response text:', text);
+        data = { error: 'Failed to parse response' };
+      }
+
+      console.log('[DEBUG] Validator save response:', JSON.stringify(data, null, 2));
+
+      if (!response.ok) {
+        console.error('[DEBUG] Validator save failed with status:', response.status);
+        console.error('[DEBUG] Response data:', data);
+        toast.error(`Failed to save validator (${response.status}): ${data.error || data.detail || 'Unknown error'}`);
+        return;
+      }
+
+      // Extract validator_config_id from response
+      // Try multiple possible response structures
+      const configId = data.id || data.validator_config_id || data.config_id || data.data?.id || data.data?.validator_config_id;
+
+      console.log('[DEBUG] Extracted config ID:', configId);
+
+      if (!configId) {
+        console.error('[DEBUG] No config ID found in response. Full response:', data);
+        toast.error('Validator saved but no ID returned from backend');
+        return;
+      }
+
+      // Extract validator_config_id from response and add to validator
+      const validatorWithId: Validator = {
+        ...validator,
+        validator_config_id: configId
+      };
+
+      console.log('[DEBUG] Validator with ID:', validatorWithId);
+
+      // Add to local state on success
+      setSavedValidators([...savedValidators, validatorWithId]);
+      setSelectedValidator(null);
+      toast.success(`Validator "${validator.name}" configured successfully!`);
+    } catch (error) {
+      console.error('Error saving validator:', error);
+      toast.error('Failed to save validator configuration. Please try again.');
+    }
   };
 
-  const handleRemoveValidator = (index: number) => {
-    setSavedValidators(savedValidators.filter((_, i) => i !== index));
+  const handleRemoveValidator = async (index: number) => {
+    const validator = savedValidators[index];
+    if (!validator || !validator.validator_config_id) {
+      // No config ID, just remove from local state
+      setSavedValidators(savedValidators.filter((_, i) => i !== index));
+      return;
+    }
+
+    // Get API key and guardrails token
+    const apiKey = getApiKey();
+    if (!apiKey) {
+      toast.error('No API key found. Please add an API key in the Keystore.');
+      return;
+    }
+
+    const getGuardrailsToken = (): string | null => {
+      try {
+        const stored = localStorage.getItem('kaapi_api_keys');
+        if (stored) {
+          const keys = JSON.parse(stored);
+          if (keys.length > 0 && keys[0].guardrails_token) {
+            return keys[0].guardrails_token;
+          }
+        }
+      } catch (e) {
+        console.error('Failed to get guardrails token:', e);
+      }
+      return null;
+    };
+
+    const guardrailsToken = getGuardrailsToken();
+    if (!guardrailsToken) {
+      toast.error('No guardrails token found. Please add a guardrails token in the Keystore.');
+      return;
+    }
+
+    try {
+      // Get organization and project IDs
+      const verifyResponse = await fetch('/api/apikeys/verify', {
+        method: 'GET',
+        headers: {
+          'X-API-KEY': apiKey,
+        },
+      });
+
+      const verifyData = await verifyResponse.json();
+      if (!verifyResponse.ok || !verifyData.success) {
+        toast.error('Failed to verify API key.');
+        return;
+      }
+
+      const { organization_id, project_id } = verifyData.data;
+
+      // Call DELETE API
+      const response = await fetch(
+        `/api/guardrails/validators/configs/${validator.validator_config_id}?organization_id=${organization_id}&project_id=${project_id}`,
+        {
+          method: 'DELETE',
+          headers: {
+            'Authorization': `Bearer ${guardrailsToken}`,
+            'Content-Type': 'application/json',
+          },
+        }
+      );
+
+      if (!response.ok) {
+        const data = await response.json();
+        toast.error(`Failed to delete validator: ${data.error || 'Unknown error'}`);
+        return;
+      }
+
+      // Remove from local state on success
+      setSavedValidators(savedValidators.filter((_, i) => i !== index));
+      toast.success(`Validator "${validator.name}" deleted successfully!`);
+    } catch (error) {
+      console.error('Error deleting validator:', error);
+      toast.error('Failed to delete validator. Please try again.');
+    }
+  };
+
+  // Load guardrails from config blob
+  const loadGuardrailsFromConfig = async (configBlob: any) => {
+    console.log('[DEBUG loadGuardrailsFromConfig] Config blob:', configBlob);
+    const inputGuardrails = configBlob.input_guardrails || [];
+    const outputGuardrails = configBlob.output_guardrails || [];
+
+    console.log('[DEBUG loadGuardrailsFromConfig] Input guardrails:', inputGuardrails);
+    console.log('[DEBUG loadGuardrailsFromConfig] Output guardrails:', outputGuardrails);
+
+    const allGuardrailIds = [
+      ...inputGuardrails.map((g: any) => ({ id: g.validator_config_id, stage: 'input' })),
+      ...outputGuardrails.map((g: any) => ({ id: g.validator_config_id, stage: 'output' }))
+    ];
+
+    console.log('[DEBUG loadGuardrailsFromConfig] All guardrail IDs:', allGuardrailIds);
+
+    if (allGuardrailIds.length === 0) {
+      console.log('[DEBUG loadGuardrailsFromConfig] No guardrails found, clearing validators');
+      setSavedValidators([]);
+      return;
+    }
+
+    // Get API key and guardrails token
+    const apiKey = getApiKey();
+    if (!apiKey) return;
+
+    const getGuardrailsToken = (): string | null => {
+      try {
+        const stored = localStorage.getItem('kaapi_api_keys');
+        if (stored) {
+          const keys = JSON.parse(stored);
+          if (keys.length > 0 && keys[0].guardrails_token) {
+            return keys[0].guardrails_token;
+          }
+        }
+      } catch (e) {
+        console.error('Failed to get guardrails token:', e);
+      }
+      return null;
+    };
+
+    const guardrailsToken = getGuardrailsToken();
+    if (!guardrailsToken) {
+      console.warn('No guardrails token found, cannot load validator details');
+      return;
+    }
+
+    // Get organization and project IDs
+    try {
+      const verifyResponse = await fetch('/api/apikeys/verify', {
+        method: 'GET',
+        headers: {
+          'X-API-KEY': apiKey,
+        },
+      });
+
+      const verifyData = await verifyResponse.json();
+      if (!verifyResponse.ok || !verifyData.success) {
+        console.error('Failed to verify API key');
+        return;
+      }
+
+      const { organization_id, project_id } = verifyData.data;
+
+      // Fetch all validator configs
+      const validators: Validator[] = [];
+
+      for (const { id: configId, stage } of allGuardrailIds) {
+        try {
+          console.log(`[DEBUG loadGuardrailsFromConfig] Fetching validator config ${configId} for stage ${stage}`);
+          const response = await fetch(
+            `/api/guardrails/validators/configs/${configId}?organization_id=${organization_id}&project_id=${project_id}`,
+            {
+              method: 'GET',
+              headers: {
+                'Authorization': `Bearer ${guardrailsToken}`,
+                'Content-Type': 'application/json',
+              },
+            }
+          );
+
+          const data = await response.json();
+          console.log(`[DEBUG loadGuardrailsFromConfig] Response for ${configId}:`, response.ok, data);
+
+          if (response.ok && data && data.data) {
+            const validatorData = data.data;
+
+            // Map backend type to frontend validator id
+            const backendType = validatorData.type || '';
+            const validatorId = VALIDATOR_TYPE_TO_ID[backendType] || backendType;
+
+            console.log(`[DEBUG loadGuardrailsFromConfig] Backend type: ${backendType}, Frontend ID: ${validatorId}`);
+
+            // Find validator metadata from AVAILABLE_VALIDATORS
+            const validatorMeta = AVAILABLE_VALIDATORS.find(v => v.id === validatorId);
+
+            console.log(`[DEBUG loadGuardrailsFromConfig] Validator meta:`, validatorMeta);
+
+            if (validatorMeta) {
+              validators.push({
+                id: validatorId,
+                name: validatorMeta.name,
+                description: validatorMeta.description,
+                tags: validatorMeta.tags,
+                validator_config_id: configId,
+                config: {
+                  ...validatorData,
+                  stage: stage, // Ensure stage is set correctly
+                }
+              });
+              console.log(`[DEBUG loadGuardrailsFromConfig] Added validator:`, validatorMeta.name);
+            } else {
+              console.warn(`[DEBUG loadGuardrailsFromConfig] No metadata found for validator ID: ${validatorId}`);
+            }
+          } else {
+            // Validator config not found (likely deleted) - skip silently
+            console.log(`[DEBUG loadGuardrailsFromConfig] Validator config ${configId} not found (may have been deleted), skipping`);
+          }
+        } catch (error) {
+          console.error(`Failed to load validator config ${configId}:`, error);
+        }
+      }
+
+      console.log('[DEBUG loadGuardrailsFromConfig] Loaded validators:', validators);
+      setSavedValidators(validators);
+    } catch (error) {
+      console.error('Error loading guardrails:', error);
+    }
   };
 
 
@@ -421,6 +816,9 @@ function PromptEditorContent() {
               }}
               onLoadVersion={(version) => {
                 handleLoadConfigById(version.id);
+                // Exit guardrails mode when loading a version
+                setIsGuardrailsMode(false);
+                setSelectedValidator(null);
               }}
               onBackToEditor={() => {
                 setSelectedVersion(null);
@@ -440,6 +838,9 @@ function PromptEditorContent() {
                   handleLoadConfigById(versionId);
                   setSelectedVersion(null);
                   setCompareWith(null);
+                  // Exit guardrails mode when loading a version
+                  setIsGuardrailsMode(false);
+                  setSelectedValidator(null);
                 }}
               />
             ) : (
diff --git a/app/keystore/page.tsx b/app/keystore/page.tsx
index 88c62f4..9abf9f9 100644
--- a/app/keystore/page.tsx
+++ b/app/keystore/page.tsx
@@ -14,6 +14,7 @@ export interface APIKey {
   label: string;
   key: string;
   provider: string;
+  guardrails_token?: string;
   createdAt?: string;
 }
 
@@ -27,6 +28,7 @@ export default function KaapiKeystore() {
   const [newKeyLabel, setNewKeyLabel] = useState('');
   const [newKeyValue, setNewKeyValue] = useState('');
   const [newKeyProvider, setNewKeyProvider] = useState('Kaapi');
+  const [newGuardrailsToken, setNewGuardrailsToken] = useState('');
   const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());
 
   // Load API keys from localStorage on mount
@@ -63,6 +65,7 @@ export default function KaapiKeystore() {
       label: newKeyLabel,
       key: newKeyValue,
       provider: newKeyProvider,
+      guardrails_token: newGuardrailsToken.trim() || undefined,
       createdAt: new Date().toISOString(),
     };
 
@@ -70,6 +73,7 @@ export default function KaapiKeystore() {
     setNewKeyLabel('');
     setNewKeyValue('');
     setNewKeyProvider('Kaapi');
+    setNewGuardrailsToken('');
 
     // Close modal after adding
     setIsModalOpen(false);
@@ -176,10 +180,12 @@ export default function KaapiKeystore() {
           newKeyLabel={newKeyLabel}
           newKeyValue={newKeyValue}
           newKeyProvider={newKeyProvider}
+          newGuardrailsToken={newGuardrailsToken}
           providers={providers}
           onLabelChange={setNewKeyLabel}
           onValueChange={setNewKeyValue}
           onProviderChange={setNewKeyProvider}
+          onGuardrailsTokenChange={setNewGuardrailsToken}
           onAddKey={handleAddKey}
           onClose={() => setIsModalOpen(false)}
         />
@@ -299,18 +305,41 @@ function StoredKeysTab({
                         {apiKey.label}
                       </h3>
                     </div>
-                    <div className="flex items-center gap-2">
-                      <code
-                        className="text-sm px-3 py-1 rounded font-mono"
-                        style={{
-                          backgroundColor: 'hsl(0, 0%, 100%)',
-                          color: 'hsl(330, 3%, 19%)'
-                        }}
-                      >
-                        {visibleKeys.has(apiKey.id)
-                          ? apiKey.key
-                          : '•'.repeat(32)}
-                      </code>
+                    <div className="space-y-2">
+                      <div>
+                        <p className="text-xs font-medium mb-1" style={{ color: 'hsl(330, 3%, 49%)' }}>
+                          Kaapi API Key
+                        </p>
+                        <code
+                          className="text-sm px-3 py-1 rounded font-mono inline-block"
+                          style={{
+                            backgroundColor: 'hsl(0, 0%, 100%)',
+                            color: 'hsl(330, 3%, 19%)'
+                          }}
+                        >
+                          {visibleKeys.has(apiKey.id)
+                            ? apiKey.key
+                            : '•'.repeat(32)}
+                        </code>
+                      </div>
+                      {apiKey.guardrails_token && (
+                        <div>
+                          <p className="text-xs font-medium mb-1" style={{ color: 'hsl(330, 3%, 49%)' }}>
+                            Guardrails Token
+                          </p>
+                          <code
+                            className="text-sm px-3 py-1 rounded font-mono inline-block"
+                            style={{
+                              backgroundColor: 'hsl(0, 0%, 100%)',
+                              color: 'hsl(330, 3%, 19%)'
+                            }}
+                          >
+                            {visibleKeys.has(apiKey.id)
+                              ? apiKey.guardrails_token
+                              : '•'.repeat(32)}
+                          </code>
+                        </div>
+                      )}
                     </div>
                     <p className="text-xs mt-2" style={{ color: 'hsl(330, 3%, 49%)' }}>
                       Added {new Date(apiKey.createdAt).toLocaleDateString()}
@@ -409,10 +438,12 @@ interface AddKeyModalProps {
   newKeyLabel: string;
   newKeyValue: string;
   newKeyProvider: string;
+  newGuardrailsToken: string;
   providers: string[];
   onLabelChange: (value: string) => void;
   onValueChange: (value: string) => void;
   onProviderChange: (value: string) => void;
+  onGuardrailsTokenChange: (value: string) => void;
   onAddKey: () => void;
   onClose: () => void;
 }
@@ -421,10 +452,12 @@ function AddKeyModal({
   newKeyLabel,
   newKeyValue,
   newKeyProvider,
+  newGuardrailsToken,
   providers,
   onLabelChange,
   onValueChange,
   onProviderChange,
+  onGuardrailsTokenChange,
   onAddKey,
   onClose,
 }: AddKeyModalProps) {
@@ -535,6 +568,27 @@ function AddKeyModal({
                 }}
               />
             </div>
+
+            <div>
+              <label className="block text-sm font-medium mb-2" style={{ color: 'hsl(330, 3%, 19%)' }}>
+                Guardrails Token (Optional)
+              </label>
+              <input
+                type="password"
+                value={newGuardrailsToken}
+                onChange={(e) => onGuardrailsTokenChange(e.target.value)}
+                placeholder="Paste your guardrails token here"
+                className="w-full px-4 py-2 rounded-md border focus:outline-none focus:ring-2 font-mono text-sm"
+                style={{
+                  borderColor: 'hsl(0, 0%, 85%)',
+                  backgroundColor: 'hsl(0, 0%, 100%)',
+                  color: 'hsl(330, 3%, 19%)'
+                }}
+              />
+              <p className="text-xs mt-1.5" style={{ color: 'hsl(330, 3%, 49%)' }}>
+                Used for guardrails validator configuration
+              </p>
+            </div>
           </div>
 
           {/* Info Card */}
diff --git a/app/lib/useConfigs.ts b/app/lib/useConfigs.ts
index 6ec6a9b..2d9c854 100644
--- a/app/lib/useConfigs.ts
+++ b/app/lib/useConfigs.ts
@@ -37,6 +37,8 @@ export interface SavedConfig {
   vectorStoreIds: string;
   tools?: Tool[];
   commit_message?: string | null;
+  hasGuardrails?: boolean; // Whether this config has input or output guardrails configured
+  guardrailsCount?: number; // Total count of guardrails (input + output)
 }
 
 // Config grouped by name with all its versions
@@ -110,6 +112,13 @@ const flattenConfigVersion = (
     });
   }
 
+  // Check for guardrails
+  const inputGuardrails = (blob as any).input_guardrails || [];
+  const outputGuardrails = (blob as any).output_guardrails || [];
+  const guardrailsCount = inputGuardrails.length + outputGuardrails.length;
+
+  console.log('[DEBUG flattenConfigVersion] Config:', config.name, 'Input guardrails:', inputGuardrails.length, 'Output guardrails:', outputGuardrails.length, 'Total:', guardrailsCount);
+
   return {
     id: version.id,
     config_id: config.id,
@@ -126,6 +135,8 @@ const flattenConfigVersion = (
     vectorStoreIds: tools[0]?.knowledge_base_ids?.[0] || '',
     tools: tools,
     commit_message: version.commit_message,
+    hasGuardrails: guardrailsCount > 0,
+    guardrailsCount: guardrailsCount,
   };
 };
 

From 9690443a77ac99a998a537c80378d07062a341ce Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Mon, 16 Mar 2026 13:45:13 +0530
Subject: [PATCH 09/13] third commit including ban list creation

---
 .../prompt-editor/ConfigEditorPane.tsx        | 126 +++---------------
 .../prompt-editor/ValidatorListPane.tsx       |   2 +-
 2 files changed, 20 insertions(+), 108 deletions(-)

diff --git a/app/components/prompt-editor/ConfigEditorPane.tsx b/app/components/prompt-editor/ConfigEditorPane.tsx
index fe1fc4f..e30ed85 100644
--- a/app/components/prompt-editor/ConfigEditorPane.tsx
+++ b/app/components/prompt-editor/ConfigEditorPane.tsx
@@ -87,7 +87,6 @@ export default function ConfigEditorPane({
   const [validatorConfig, setValidatorConfig] = useState<any>({});
   const [showExitModal, setShowExitModal] = useState(false);
   const [isEditMode, setIsEditMode] = useState(false);
-  const [showVersionWarningModal, setShowVersionWarningModal] = useState(false);
   const [editingValidatorIndex, setEditingValidatorIndex] = useState<number | null>(null);
   const [editingValidatorId, setEditingValidatorId] = useState<string | null>(null);
   const [initialValidators, setInitialValidators] = useState<Validator[]>([]);
@@ -167,6 +166,7 @@ export default function ConfigEditorPane({
       // Create ban list payload
       const payload = {
         name: newBanList.name,
+        description: newBanList.description,
         banned_words: bannedWordsArray,
         domain: newBanList.domain,
         is_public: newBanList.is_public,
@@ -965,22 +965,6 @@ export default function ConfigEditorPane({
                   {/* Detect PII Validator */}
                   {(editingValidatorId || selectedValidator) === 'detect-pii' && (
                     <>
-                      <div>
-                        <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
-                          Type
-                        </label>
-                        <input
-                          type="text"
-                          value={validatorConfig.type || 'pii_remover'}
-                          onChange={(e) => setValidatorConfig({ ...validatorConfig, type: e.target.value })}
-                          className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
-                          style={{
-                            border: `1px solid ${colors.border}`,
-                            backgroundColor: colors.bg.primary,
-                            color: colors.text.primary,
-                          }}
-                        />
-                      </div>
                       <div>
                         <label className="block text-xs font-semibold mb-2" style={{ color: colors.text.primary }}>
                           Stage
@@ -1098,7 +1082,7 @@ export default function ConfigEditorPane({
                         </label>
                         <input
                           type="text"
-                          value={validatorConfig.on_fail || 'fix'}
+                          value={validatorConfig.on_fail || 'Fix'}
                           onChange={(e) => setValidatorConfig({ ...validatorConfig, on_fail: e.target.value })}
                           className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
                           style={{
@@ -1358,45 +1342,45 @@ export default function ConfigEditorPane({
                       if (validator && onSaveValidator) {
                         // Merge default values with user-provided values
                         let finalConfig = { ...validatorConfig };
+                        let enabled = true;
 
                         if (currentValidatorId === 'detect-pii') {
+                          enabled = validatorConfig.is_enabled !== undefined ? validatorConfig.is_enabled : true;
                           finalConfig = {
                             type: validatorConfig.type || 'pii_remover',
                             stage: validatorConfig.stage || 'input',
                             on_fail_action: validatorConfig.on_fail_action || 'fix',
-                            is_enabled: validatorConfig.is_enabled !== undefined ? validatorConfig.is_enabled : true,
                             entity_types: validatorConfig.entity_types || ['PERSON', 'PHONE_NUMBER', 'IN_AADHAAR'],
                             threshold: validatorConfig.threshold !== undefined ? validatorConfig.threshold : 0.6,
                           };
                         } else if (currentValidatorId === 'lexical-slur-match') {
+                          enabled = validatorConfig.enabled !== undefined ? validatorConfig.enabled : true;
                           finalConfig = {
                             type: validatorConfig.type || 'uli_slur_match',
                             stage: validatorConfig.stage || 'input',
-                            on_fail: validatorConfig.on_fail || 'fix',
-                            enabled: validatorConfig.enabled !== undefined ? validatorConfig.enabled : true,
                             languages: validatorConfig.languages || ['en', 'hi'],
                             severity: validatorConfig.severity || 'all',
                           };
                         } else if (currentValidatorId === 'gender-assumption-bias') {
+                          enabled = validatorConfig.enabled !== undefined ? validatorConfig.enabled : true;
                           finalConfig = {
                             type: validatorConfig.type || 'gender_assumption_bias',
                             stage: validatorConfig.stage || 'input',
                             on_fail_action: validatorConfig.on_fail_action || 'fix',
-                            enabled: validatorConfig.enabled !== undefined ? validatorConfig.enabled : true,
-                            bias_category: validatorConfig.bias_category || 'all',
+                            categories: validatorConfig.bias_category || 'all',
                           };
                         } else if (currentValidatorId === 'ban-list') {
+                          enabled = validatorConfig.enabled !== undefined ? validatorConfig.enabled : true;
                           finalConfig = {
                             type: validatorConfig.type || 'ban_list',
                             stage: validatorConfig.stage || 'input',
-                            enabled: validatorConfig.enabled !== undefined ? validatorConfig.enabled : true,
                             on_fail_action: validatorConfig.on_fail_action || 'exception',
                             ban_list_id: validatorConfig.ban_list_id || '',
                           };
                         } else {
+                          enabled = validatorConfig.enabled || false;
                           finalConfig = {
                             type: validatorConfig.type || 'topic_relevance',
-                            enabled: validatorConfig.enabled || false,
                             threshold: validatorConfig.threshold || 0.8,
                           };
                         }
@@ -1412,6 +1396,7 @@ export default function ConfigEditorPane({
                           name: validator.name,
                           description: validator.description,
                           tags: validator.tags,
+                          enabled: enabled,
                           config: finalConfig
                         });
 
@@ -1476,7 +1461,7 @@ export default function ConfigEditorPane({
                   </h3>
                   {!isEditMode && (
                     <button
-                      onClick={() => setShowVersionWarningModal(true)}
+                      onClick={() => setIsEditMode(true)}
                       className="px-3 py-1.5 rounded-md text-xs font-medium flex items-center gap-1.5"
                       style={{
                         backgroundColor: colors.bg.primary,
@@ -1525,10 +1510,7 @@ export default function ConfigEditorPane({
                                       {validator.name}
                                     </div>
                                     <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
-                                      {(() => {
-                                        const isEnabled = validator.config?.is_enabled ?? validator.config?.enabled ?? true;
-                                        return isEnabled ? 'Enabled' : 'Disabled';
-                                      })()}
+                                      {validator.enabled !== undefined ? (validator.enabled ? 'Enabled' : 'Disabled') : 'Enabled'}
                                     </div>
                                   </div>
                                 </div>
@@ -1591,10 +1573,7 @@ export default function ConfigEditorPane({
                                       {validator.name}
                                     </div>
                                     <div className="text-xs mt-1" style={{ color: colors.text.secondary }}>
-                                      {(() => {
-                                        const isEnabled = validator.config?.is_enabled ?? validator.config?.enabled ?? true;
-                                        return isEnabled ? 'Enabled' : 'Disabled';
-                                      })()}
+                                      {validator.enabled !== undefined ? (validator.enabled ? 'Enabled' : 'Disabled') : 'Enabled'}
                                     </div>
                                   </div>
                                 </div>
@@ -1752,73 +1731,6 @@ export default function ConfigEditorPane({
         </>
       )}
 
-      {/* Version Warning Modal */}
-      {showVersionWarningModal && (
-        <>
-          {/* Backdrop */}
-          <div
-            className="fixed inset-0 z-50"
-            style={{
-              backgroundColor: 'rgba(0, 0, 0, 0.5)',
-            }}
-            onClick={() => setShowVersionWarningModal(false)}
-          />
-
-          {/* Modal */}
-          <div
-            className="fixed top-1/2 left-1/2 z-50 w-full max-w-md rounded-lg shadow-lg p-6"
-            style={{
-              transform: 'translate(-50%, -50%)',
-              backgroundColor: colors.bg.primary,
-              border: `1px solid ${colors.border}`,
-            }}
-          >
-            <div className="flex items-start gap-4">
-              <div className="flex-1">
-                <h3
-                  className="text-lg font-semibold mb-2"
-                  style={{ color: colors.text.primary }}
-                >
-                  Edit Guardrails Configuration
-                </h3>
-                <p className="text-sm mb-6" style={{ color: colors.text.secondary }}>
-                  If you edit these validators, a whole new version of the configuration will be created when you save. Do you want to continue?
-                </p>
-                <div className="flex gap-3 justify-end">
-                  <button
-                    onClick={() => setShowVersionWarningModal(false)}
-                    className="px-4 py-2 rounded-md text-sm font-medium"
-                    style={{
-                      backgroundColor: colors.bg.secondary,
-                      color: colors.text.primary,
-                      border: `1px solid ${colors.border}`,
-                      cursor: 'pointer',
-                    }}
-                  >
-                    Cancel
-                  </button>
-                  <button
-                    onClick={() => {
-                      setShowVersionWarningModal(false);
-                      setIsEditMode(true);
-                    }}
-                    className="px-4 py-2 rounded-md text-sm font-semibold"
-                    style={{
-                      backgroundColor: colors.accent.primary,
-                      color: '#ffffff',
-                      border: 'none',
-                      cursor: 'pointer',
-                    }}
-                  >
-                    Okay, Continue
-                  </button>
-                </div>
-              </div>
-            </div>
-          </div>
-        </>
-      )}
-
       {/* Create Ban List Modal */}
       {showCreateBanListModal && (
         <>
@@ -1878,7 +1790,7 @@ export default function ConfigEditorPane({
                   type="text"
                   value={newBanList.description}
                   onChange={(e) => setNewBanList({ ...newBanList, description: e.target.value })}
-                  placeholder="e.g., profanity-filter"
+                  placeholder="e.g., Filter for offensive and inappropriate language"
                   className="w-full px-3 py-2 rounded-md text-sm focus:outline-none"
                   style={{
                     border: `1px solid ${colors.border}`,
@@ -1948,7 +1860,7 @@ export default function ConfigEditorPane({
               <button
                 onClick={() => {
                   setShowCreateBanListModal(false);
-                  setNewBanList({ name: '', banned_words: '', domain: '', is_public: false });
+                  setNewBanList({ name: '',description:'', banned_words: '', domain: '', is_public: false });
                 }}
                 className="px-4 py-2 rounded-md text-sm font-medium"
                 style={{
@@ -1962,17 +1874,17 @@ export default function ConfigEditorPane({
               </button>
               <button
                 onClick={handleCreateBanList}
-                disabled={!newBanList.name.trim() || !newBanList.banned_words.trim()}
+                disabled={!newBanList.name.trim() || !newBanList.description.trim() || !newBanList.banned_words.trim()}
                 className="px-4 py-2 rounded-md text-sm font-semibold"
                 style={{
-                  backgroundColor: !newBanList.name.trim() || !newBanList.banned_words.trim()
+                  backgroundColor: !newBanList.name.trim() || !newBanList.description.trim() || !newBanList.banned_words.trim()
                     ? colors.bg.secondary
                     : colors.status.success,
-                  color: !newBanList.name.trim() || !newBanList.banned_words.trim()
+                  color: !newBanList.name.trim() || !newBanList.description.trim() || !newBanList.banned_words.trim()
                     ? colors.text.secondary
                     : '#ffffff',
                   border: 'none',
-                  cursor: !newBanList.name.trim() || !newBanList.banned_words.trim()
+                  cursor: !newBanList.name.trim() || !newBanList.description.trim() || !newBanList.banned_words.trim()
                     ? 'not-allowed'
                     : 'pointer',
                 }}
diff --git a/app/components/prompt-editor/ValidatorListPane.tsx b/app/components/prompt-editor/ValidatorListPane.tsx
index b411d35..a645fe3 100644
--- a/app/components/prompt-editor/ValidatorListPane.tsx
+++ b/app/components/prompt-editor/ValidatorListPane.tsx
@@ -6,10 +6,10 @@ export interface Validator {
   name: string;
   description: string;
   tags: string[];
+  enabled?: boolean;
   validator_config_id?: string; // ID returned from backend after saving
   config?: {
     threshold?: number;
-    enabled?: boolean;
     stage?: string;
     [key: string]: any;
   };

From b0b35723a0f30e4df1cc5d7dae975415bf1109c0 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Tue, 17 Mar 2026 13:55:51 +0530
Subject: [PATCH 10/13] remove guardrail token from keystore, add to env

---
 .../validators/configs/[config_id]/route.ts   | 22 +++++----
 .../guardrails/validators/configs/route.ts    | 17 +++----
 app/keystore/page.tsx                         | 48 -------------------
 3 files changed, 23 insertions(+), 64 deletions(-)

diff --git a/app/api/guardrails/validators/configs/[config_id]/route.ts b/app/api/guardrails/validators/configs/[config_id]/route.ts
index e087b55..f403d30 100644
--- a/app/api/guardrails/validators/configs/[config_id]/route.ts
+++ b/app/api/guardrails/validators/configs/[config_id]/route.ts
@@ -7,15 +7,18 @@ export async function GET(
   { params }: { params: Promise<{ config_id: string }> }
 ) {
   const { config_id } = await params;
-  const authHeader = request.headers.get('Authorization');
 
-  if (!authHeader) {
+  // Get the guardrails token from environment variable
+  const guardrailsToken = process.env.GUARDRAILS_TOKEN;
+  if (!guardrailsToken) {
     return NextResponse.json(
-      { error: 'Missing Authorization header' },
-      { status: 401 }
+      { error: 'Missing GUARDRAILS_TOKEN environment variable' },
+      { status: 500 }
     );
   }
 
+  const authHeader = `Bearer ${guardrailsToken}`;
+
   try {
     // Get query parameters
     const { searchParams } = new URL(request.url);
@@ -62,15 +65,18 @@ export async function DELETE(
 ) {
   const { config_id } = await params;
   const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
-  const authHeader = request.headers.get('Authorization');
 
-  if (!authHeader) {
+  // Get the guardrails token from environment variable
+  const guardrailsToken = process.env.GUARDRAILS_TOKEN;
+  if (!guardrailsToken) {
     return NextResponse.json(
-      { error: 'Missing Authorization header' },
-      { status: 401 }
+      { error: 'Missing GUARDRAILS_TOKEN environment variable' },
+      { status: 500 }
     );
   }
 
+  const authHeader = `Bearer ${guardrailsToken}`;
+
   try {
       // Get query parameters
     const { searchParams } = new URL(request.url);
diff --git a/app/api/guardrails/validators/configs/route.ts b/app/api/guardrails/validators/configs/route.ts
index 0fa50a7..d09cd38 100644
--- a/app/api/guardrails/validators/configs/route.ts
+++ b/app/api/guardrails/validators/configs/route.ts
@@ -6,15 +6,16 @@ const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001
 
 export async function POST(request: NextRequest) {
   try {
-    // Get the API key from request headers
-    const authHeader = request.headers.get('Authorization');
-    if (!authHeader) {
-    return NextResponse.json(
-      { error: 'Missing Authorization header' },
-      { status: 401 }
-    );
-  }
+    // Get the guardrails token from environment variable
+    const guardrailsToken = process.env.GUARDRAILS_TOKEN;
+    if (!guardrailsToken) {
+      return NextResponse.json(
+        { error: 'Missing GUARDRAILS_TOKEN environment variable' },
+        { status: 500 }
+      );
+    }
 
+    const authHeader = `Bearer ${guardrailsToken}`;
 
     // Get the JSON body from the request
     const body = await request.json();
diff --git a/app/keystore/page.tsx b/app/keystore/page.tsx
index 9abf9f9..335289c 100644
--- a/app/keystore/page.tsx
+++ b/app/keystore/page.tsx
@@ -14,7 +14,6 @@ export interface APIKey {
   label: string;
   key: string;
   provider: string;
-  guardrails_token?: string;
   createdAt?: string;
 }
 
@@ -28,7 +27,6 @@ export default function KaapiKeystore() {
   const [newKeyLabel, setNewKeyLabel] = useState('');
   const [newKeyValue, setNewKeyValue] = useState('');
   const [newKeyProvider, setNewKeyProvider] = useState('Kaapi');
-  const [newGuardrailsToken, setNewGuardrailsToken] = useState('');
   const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());
 
   // Load API keys from localStorage on mount
@@ -65,7 +63,6 @@ export default function KaapiKeystore() {
       label: newKeyLabel,
       key: newKeyValue,
       provider: newKeyProvider,
-      guardrails_token: newGuardrailsToken.trim() || undefined,
       createdAt: new Date().toISOString(),
     };
 
@@ -73,7 +70,6 @@ export default function KaapiKeystore() {
     setNewKeyLabel('');
     setNewKeyValue('');
     setNewKeyProvider('Kaapi');
-    setNewGuardrailsToken('');
 
     // Close modal after adding
     setIsModalOpen(false);
@@ -180,12 +176,10 @@ export default function KaapiKeystore() {
           newKeyLabel={newKeyLabel}
           newKeyValue={newKeyValue}
           newKeyProvider={newKeyProvider}
-          newGuardrailsToken={newGuardrailsToken}
           providers={providers}
           onLabelChange={setNewKeyLabel}
           onValueChange={setNewKeyValue}
           onProviderChange={setNewKeyProvider}
-          onGuardrailsTokenChange={setNewGuardrailsToken}
           onAddKey={handleAddKey}
           onClose={() => setIsModalOpen(false)}
         />
@@ -322,24 +316,6 @@ function StoredKeysTab({
                             : '•'.repeat(32)}
                         </code>
                       </div>
-                      {apiKey.guardrails_token && (
-                        <div>
-                          <p className="text-xs font-medium mb-1" style={{ color: 'hsl(330, 3%, 49%)' }}>
-                            Guardrails Token
-                          </p>
-                          <code
-                            className="text-sm px-3 py-1 rounded font-mono inline-block"
-                            style={{
-                              backgroundColor: 'hsl(0, 0%, 100%)',
-                              color: 'hsl(330, 3%, 19%)'
-                            }}
-                          >
-                            {visibleKeys.has(apiKey.id)
-                              ? apiKey.guardrails_token
-                              : '•'.repeat(32)}
-                          </code>
-                        </div>
-                      )}
                     </div>
                     <p className="text-xs mt-2" style={{ color: 'hsl(330, 3%, 49%)' }}>
                       Added {new Date(apiKey.createdAt).toLocaleDateString()}
@@ -438,12 +414,10 @@ interface AddKeyModalProps {
   newKeyLabel: string;
   newKeyValue: string;
   newKeyProvider: string;
-  newGuardrailsToken: string;
   providers: string[];
   onLabelChange: (value: string) => void;
   onValueChange: (value: string) => void;
   onProviderChange: (value: string) => void;
-  onGuardrailsTokenChange: (value: string) => void;
   onAddKey: () => void;
   onClose: () => void;
 }
@@ -452,12 +426,10 @@ function AddKeyModal({
   newKeyLabel,
   newKeyValue,
   newKeyProvider,
-  newGuardrailsToken,
   providers,
   onLabelChange,
   onValueChange,
   onProviderChange,
-  onGuardrailsTokenChange,
   onAddKey,
   onClose,
 }: AddKeyModalProps) {
@@ -569,26 +541,6 @@ function AddKeyModal({
               />
             </div>
 
-            <div>
-              <label className="block text-sm font-medium mb-2" style={{ color: 'hsl(330, 3%, 19%)' }}>
-                Guardrails Token (Optional)
-              </label>
-              <input
-                type="password"
-                value={newGuardrailsToken}
-                onChange={(e) => onGuardrailsTokenChange(e.target.value)}
-                placeholder="Paste your guardrails token here"
-                className="w-full px-4 py-2 rounded-md border focus:outline-none focus:ring-2 font-mono text-sm"
-                style={{
-                  borderColor: 'hsl(0, 0%, 85%)',
-                  backgroundColor: 'hsl(0, 0%, 100%)',
-                  color: 'hsl(330, 3%, 19%)'
-                }}
-              />
-              <p className="text-xs mt-1.5" style={{ color: 'hsl(330, 3%, 49%)' }}>
-                Used for guardrails validator configuration
-              </p>
-            </div>
           </div>
 
           {/* Info Card */}

From 6a8493cf14aed897c636f6efcbbcfa3c1da83e07 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Tue, 17 Mar 2026 13:57:58 +0530
Subject: [PATCH 11/13] remove guardrail token from keystore, add to env

---
 .env.example | 3 +++
 1 file changed, 3 insertions(+)
 create mode 100644 .env.example

diff --git a/.env.example b/.env.example
new file mode 100644
index 0000000..fcdd331
--- /dev/null
+++ b/.env.example
@@ -0,0 +1,3 @@
+NEXT_PUBLIC_BACKEND_URL=
+
+GUARDRAIL_TOKEN=
\ No newline at end of file

From 4871f2a1f4f6fc4597853cf0f5047e5f32f0a009 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Tue, 17 Mar 2026 14:00:57 +0530
Subject: [PATCH 12/13] remove guardrail token from keystore

---
 app/api/guardrails/validators/configs/[config_id]/route.ts | 1 +
 app/api/guardrails/validators/configs/route.ts             | 1 -
 app/keystore/page.tsx                                      | 1 +
 3 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/app/api/guardrails/validators/configs/[config_id]/route.ts b/app/api/guardrails/validators/configs/[config_id]/route.ts
index f403d30..38ffb31 100644
--- a/app/api/guardrails/validators/configs/[config_id]/route.ts
+++ b/app/api/guardrails/validators/configs/[config_id]/route.ts
@@ -1,5 +1,6 @@
 import { NextResponse } from 'next/server';
 
+
 const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
 
 export async function GET(
diff --git a/app/api/guardrails/validators/configs/route.ts b/app/api/guardrails/validators/configs/route.ts
index d09cd38..2bcca02 100644
--- a/app/api/guardrails/validators/configs/route.ts
+++ b/app/api/guardrails/validators/configs/route.ts
@@ -1,7 +1,6 @@
 import { NextRequest, NextResponse } from 'next/server';
 
 
-
 const backendUrl = process.env.NEXT_PUBLIC_BACKEND_URL || 'http://localhost:8001';
 
 export async function POST(request: NextRequest) {
diff --git a/app/keystore/page.tsx b/app/keystore/page.tsx
index 335289c..39b5164 100644
--- a/app/keystore/page.tsx
+++ b/app/keystore/page.tsx
@@ -4,6 +4,7 @@
  * Allows users to securely store and manage API keys for various LLM providers
  */
 
+
 "use client"
 import { useState, useEffect } from 'react';
 import { useRouter } from 'next/navigation'

From 9ee79ac065c9489c38e87fe9535c8c488f789434 Mon Sep 17 00:00:00 2001
From: nishika26 <nishikayadav26@gmail.com>
Date: Tue, 17 Mar 2026 14:04:23 +0530
Subject: [PATCH 13/13] remove guardrail token from keystore

---
 app/keystore/page.tsx | 33 +++++++++++++--------------------
 1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/app/keystore/page.tsx b/app/keystore/page.tsx
index 39b5164..b17dc7c 100644
--- a/app/keystore/page.tsx
+++ b/app/keystore/page.tsx
@@ -4,7 +4,6 @@
  * Allows users to securely store and manage API keys for various LLM providers
  */
 
-
 "use client"
 import { useState, useEffect } from 'react';
 import { useRouter } from 'next/navigation'
@@ -300,23 +299,18 @@ function StoredKeysTab({
                         {apiKey.label}
                       </h3>
                     </div>
-                    <div className="space-y-2">
-                      <div>
-                        <p className="text-xs font-medium mb-1" style={{ color: 'hsl(330, 3%, 49%)' }}>
-                          Kaapi API Key
-                        </p>
-                        <code
-                          className="text-sm px-3 py-1 rounded font-mono inline-block"
-                          style={{
-                            backgroundColor: 'hsl(0, 0%, 100%)',
-                            color: 'hsl(330, 3%, 19%)'
-                          }}
-                        >
-                          {visibleKeys.has(apiKey.id)
-                            ? apiKey.key
-                            : '•'.repeat(32)}
-                        </code>
-                      </div>
+                    <div className="flex items-center gap-2">
+                      <code
+                        className="text-sm px-3 py-1 rounded font-mono"
+                        style={{
+                          backgroundColor: 'hsl(0, 0%, 100%)',
+                          color: 'hsl(330, 3%, 19%)'
+                        }}
+                      >
+                        {visibleKeys.has(apiKey.id)
+                          ? apiKey.key
+                          : '•'.repeat(32)}
+                      </code>
                     </div>
                     <p className="text-xs mt-2" style={{ color: 'hsl(330, 3%, 49%)' }}>
                       Added {new Date(apiKey.createdAt).toLocaleDateString()}
@@ -541,7 +535,6 @@ function AddKeyModal({
                 }}
               />
             </div>
-
           </div>
 
           {/* Info Card */}
@@ -589,4 +582,4 @@ function AddKeyModal({
       </div>
     </div>
   );
-}
+}
\ No newline at end of file
