Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions dashboard/backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,83 @@ func configHandler(configPath string) http.HandlerFunc {
}
}

// updateConfigHandler updates the config.yaml file
func updateConfigHandler(configPath string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Only allow POST/PUT requests
if r.Method != http.MethodPost && r.Method != http.MethodPut {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

// Read the request body
var configData map[string]interface{}
if err := json.NewDecoder(r.Body).Decode(&configData); err != nil {
log.Printf("Error decoding request body: %v", err)
http.Error(w, fmt.Sprintf("Invalid request body: %v", err), http.StatusBadRequest)
return
}

// Convert to YAML
yamlData, err := yaml.Marshal(configData)
if err != nil {
log.Printf("Error marshaling config to YAML: %v", err)
http.Error(w, fmt.Sprintf("Failed to convert config to YAML: %v", err), http.StatusInternalServerError)
return
}

// Write to file
if err := os.WriteFile(configPath, yamlData, 0644); err != nil {
log.Printf("Error writing config file: %v", err)
http.Error(w, fmt.Sprintf("Failed to write config file: %v", err), http.StatusInternalServerError)
return
}

log.Printf("Configuration updated successfully")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{"status": "success", "message": "Configuration updated successfully"})
}
}

// toolsDBHandler reads and serves the tools_db.json file
func toolsDBHandler(configDir string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// Only allow GET requests
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}

// Construct the tools_db.json path
toolsDBPath := filepath.Join(configDir, "tools_db.json")

// Read the tools database file
data, err := os.ReadFile(toolsDBPath)
if err != nil {
log.Printf("Error reading tools_db.json: %v", err)
http.Error(w, fmt.Sprintf("Failed to read tools database: %v", err), http.StatusInternalServerError)
return
}

// Parse JSON to validate it
var tools interface{}
if err := json.Unmarshal(data, &tools); err != nil {
log.Printf("Error parsing tools_db.json: %v", err)
http.Error(w, fmt.Sprintf("Failed to parse tools database: %v", err), http.StatusInternalServerError)
return
}

// Send response
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(tools); err != nil {
log.Printf("Error encoding tools to JSON: %v", err)
http.Error(w, fmt.Sprintf("Failed to encode tools: %v", err), http.StatusInternalServerError)
return
}
}
}

// newReverseProxy creates a reverse proxy to targetBase and strips the given prefix from the incoming path
func newReverseProxy(targetBase, stripPrefix string, forwardAuth bool) (*httputil.ReverseProxy, error) {
targetURL, err := url.Parse(targetBase)
Expand Down Expand Up @@ -213,6 +290,15 @@ func main() {
mux.HandleFunc("/api/router/config/all", configHandler(absConfigPath))
log.Printf("Config API endpoint registered: /api/router/config/all")

// Config update endpoint - update the config.yaml file
mux.HandleFunc("/api/router/config/update", updateConfigHandler(absConfigPath))
log.Printf("Config update API endpoint registered: /api/router/config/update")

// Tools DB endpoint - serve the tools_db.json
configDir := filepath.Dir(absConfigPath)
mux.HandleFunc("/api/tools-db", toolsDBHandler(configDir))
log.Printf("Tools DB API endpoint registered: /api/tools-db")

// Router API proxy (forward Authorization) - MUST be registered before Grafana
var routerAPIProxy *httputil.ReverseProxy
if *routerAPI != "" {
Expand Down
27 changes: 17 additions & 10 deletions dashboard/frontend/src/components/ConfigNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type ConfigSection =
| 'intelligent-routing'
| 'tools-selection'
| 'observability'
| 'classification-api'

interface ConfigNavProps {
activeSection: ConfigSection
Expand All @@ -18,39 +19,45 @@ const ConfigNav: React.FC<ConfigNavProps> = ({ activeSection, onSectionChange })
const sections = [
{
id: 'models' as ConfigSection,
icon: '🔌',
title: 'Models & Endpoints',
description: 'Model configurations and backend endpoints'
icon: '🤖',
title: 'Models',
description: 'User defined models and endpoints'
},
{
id: 'prompt-guard' as ConfigSection,
icon: '🛡️',
title: 'Prompt Guard',
description: 'PII and jailbreak detection'
description: 'PII and jailbreak ModernBERT detection'
},
{
id: 'similarity-cache' as ConfigSection,
icon: '⚡',
title: 'Similarity Cache',
description: 'Semantic caching configuration'
description: 'Similarity BERT configuration'
},
{
id: 'intelligent-routing' as ConfigSection,
icon: '📊',
icon: '🧠',
title: 'Intelligent Routing',
description: 'Categories and reasoning configuration'
description: 'Classify BERT, categories & reasoning'
},
{
id: 'tools-selection' as ConfigSection,
icon: '🔧',
title: 'Tools Selection',
description: 'Tool auto-selection settings'
description: 'Tools configuration and database'
},
{
id: 'observability' as ConfigSection,
icon: '📈',
icon: '📊',
title: 'Observability',
description: 'Metrics and monitoring'
description: 'Tracing and metrics'
},
{
id: 'classification-api' as ConfigSection,
icon: '🔌',
title: 'Classification API',
description: 'Batch classification settings'
}
]

Expand Down
Loading
Loading