import React, { useEffect, useState } from "react"; export default function SettingsModal({ onClose }) { const [settings, setSettings] = useState(null); const [models, setModels] = useState([]); const [modelsError, setModelsError] = useState(null); const [loadingModels, setLoadingModels] = useState(false); const [testResult, setTestResult] = useState(null); // { ok: bool, message: string } const [testing, setTesting] = useState(false); const loadSettings = async () => { const res = await fetch("/api/settings"); const data = await res.json(); setSettings(data); }; useEffect(() => { loadSettings(); }, []); const changeProvider = async (provider) => { const res = await fetch("/api/settings/provider", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ provider }), }); const data = await res.json(); setSettings(data); // Reset models state when provider changes setModels([]); setModelsError(null); }; const loadModels = async () => { if (!settings) return; setLoadingModels(true); setModelsError(null); try { const res = await fetch( `/api/settings/models?provider=${settings.provider}` ); const data = await res.json(); if (data.error) { setModelsError(data.error); setModels([]); } else { setModels(data.models || []); } } catch (err) { console.error(err); setModelsError("Failed to load models"); setModels([]); } finally { setLoadingModels(false); } }; const currentModelForActiveProvider = () => { if (!settings) return ""; const p = settings.provider; if (p === "openai") return settings.openai?.model || ""; if (p === "claude") return settings.claude?.model || ""; if (p === "watsonx") return settings.watsonx?.model_id || ""; if (p === "ollama") return settings.ollama?.model || ""; return ""; }; const changeModel = async (model) => { if (!settings) return; const provider = settings.provider; let payload = {}; if (provider === "openai") { payload = { openai: { ...settings.openai, model, }, }; } else if (provider === "claude") { payload = { claude: { ...settings.claude, model, }, }; } else if (provider === "watsonx") { payload = { watsonx: { ...settings.watsonx, model_id: model, }, }; } else if (provider === "ollama") { payload = { ollama: { ...settings.ollama, model, }, }; } const res = await fetch("/api/settings/llm", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const data = await res.json(); setSettings(data); }; const testConnection = async () => { if (!settings) return; setTesting(true); setTestResult(null); try { const res = await fetch(`/api/settings/test?provider=${settings.provider}`); const data = await res.json(); if (!res.ok || data.error) { setTestResult({ ok: false, message: data.error || data.detail || "Connection failed" }); } else { setTestResult({ ok: true, message: data.message || "Connection successful" }); } } catch (err) { setTestResult({ ok: false, message: err.message || "Connection test failed" }); } finally { setTesting(false); } }; const toggleLiteMode = async () => { if (!settings) return; const newValue = !settings.lite_mode; try { const res = await fetch("/api/settings/lite-mode", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ lite_mode: newValue }), }); if (res.ok) { setSettings((prev) => ({ ...prev, lite_mode: newValue })); } } catch (err) { console.error("Failed to toggle lite mode:", err); } }; if (!settings) return null; const activeModel = currentModelForActiveProvider(); return (
e.stopPropagation()}>
Settings
Select which LLM provider GitPilot should use for planning and chat.
{settings.providers.map((p) => (
{p}
))}
{/* Models section */}
Active provider: {settings.provider}
{activeModel && ( Current model: {activeModel} )}
{modelsError && (
{modelsError}
)} {testResult && (
{testResult.ok ? "✓ " : "✗ "}{testResult.message}
)} {models.length > 0 && (
)}
{/* Lite Mode section */}
Lite Mode
Optimized for small models (under 7B parameters). Uses simplified prompts and single-agent execution instead of multi-agent pipelines. Recommended for: qwen2.5:1.5b, phi-3-mini, gemma-2b, tinyllama, etc.
); }