import React, { useState } from "react"; import { Plus, Pencil, Trash2, CheckCircle, XCircle, Zap } from "lucide-react"; import { Card, CardHeader, CardTitle, CardContent, Button, Input, Label, Badge, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, Separator, } from "@/components/ui"; import { useSettingsStore } from "@/stores/settingsStore"; import { testProviderConnectionCmd, type ProviderConfig } from "@/lib/tauriCommands"; const emptyProvider: ProviderConfig = { name: "", provider_type: "openai", api_url: "", api_key: "", model: "", max_tokens: 4096, temperature: 0.7, custom_endpoint_path: undefined, custom_auth_header: undefined, custom_auth_prefix: undefined, api_format: undefined, session_id: undefined, }; export default function AIProviders() { const { ai_providers, active_provider, addProvider, updateProvider, removeProvider, setActiveProvider, } = useSettingsStore(); const [editIndex, setEditIndex] = useState(null); const [isAdding, setIsAdding] = useState(false); const [form, setForm] = useState({ ...emptyProvider }); const [testResult, setTestResult] = useState<{ success: boolean; message: string } | null>(null); const [isTesting, setIsTesting] = useState(false); const startAdd = () => { setForm({ ...emptyProvider }); setEditIndex(null); setIsAdding(true); setTestResult(null); }; const startEdit = (index: number) => { setForm({ ...ai_providers[index] }); setEditIndex(index); setIsAdding(true); setTestResult(null); }; const handleSave = () => { if (!form.name || !form.api_url || !form.model) return; if (editIndex != null) { updateProvider(editIndex, form); } else { addProvider(form); } setIsAdding(false); setEditIndex(null); setForm({ ...emptyProvider }); }; const handleCancel = () => { setIsAdding(false); setEditIndex(null); setForm({ ...emptyProvider }); setTestResult(null); }; const handleTest = async () => { setIsTesting(true); setTestResult(null); try { const response = await testProviderConnectionCmd(form); setTestResult({ success: true, message: `OK: ${response.content.slice(0, 100)}` }); } catch (err) { setTestResult({ success: false, message: String(err) }); } finally { setIsTesting(false); } }; const maskApiKey = (key?: string) => { if (!key) return "Not set"; if (key.length <= 8) return "****"; return key.slice(0, 4) + "..." + key.slice(-4); }; return (

AI Providers

Configure AI model providers for triage and document generation.

{!isAdding && ( )}
{/* Provider list */} {ai_providers.length === 0 && !isAdding && (

No providers configured yet.

)} {ai_providers.map((provider, idx) => (
{provider.name} {provider.provider_type} {active_provider === provider.name && ( Active )}

{provider.api_url} | Model: {provider.model} | Key: {maskApiKey(provider.api_key)}

{active_provider !== provider.name && ( )}
))} {/* Add/Edit form */} {isAdding && ( {editIndex != null ? "Edit Provider" : "Add Provider"}
setForm({ ...form, name: e.target.value })} placeholder="My OpenAI" />
setForm({ ...form, api_url: e.target.value })} placeholder="https://api.openai.com/v1" />
setForm({ ...form, api_key: e.target.value })} placeholder="sk-..." />
setForm({ ...form, model: e.target.value })} placeholder="gpt-4o" />
setForm({ ...form, max_tokens: Number(e.target.value) })} />
setForm({ ...form, temperature: Number(e.target.value) })} />
{/* Custom provider format options */} {form.provider_type === "custom" && ( <>

Select the API format. MSI GenAI uses a different request/response structure.

setForm({ ...form, custom_endpoint_path: e.target.value }) } placeholder="/chat/completions" />

Path appended to API URL. Leave empty if URL includes full path.

setForm({ ...form, custom_auth_header: e.target.value }) } placeholder="Authorization" />

Header name for authentication (e.g., "Authorization" or "x-msi-genai-api-key")

setForm({ ...form, custom_auth_prefix: e.target.value })} placeholder="Bearer " />

Prefix added before API key (e.g., "Bearer " for OpenAI, empty for MSI GenAI)

)} {/* Test result */} {testResult && (
{testResult.success ? ( ) : ( )} {testResult.message}
)}
)}
); }