import { useState, useEffect, useRef } from "react"; interface LlmSettingsProps { settings: Record; onSave: (key: string, value: any) => Promise; saveError: string | null; } const DEFAULT_MODEL = "openai/gpt-oss-120b:free"; const DEFAULT_TEMPERATURE = 0.7; const DEFAULT_MAX_DEBATE_ROUNDS = 3; const AVAILABLE_MODELS = [ "openai/gpt-oss-120b:free", "openrouter/free", "deepseek/deepseek-chat:free", "meta/llama-3.3-70b-instruct:free", ]; export default function LlmSettings({ settings, onSave, saveError }: LlmSettingsProps) { const [model, setModel] = useState(settings["llm.model"] ?? DEFAULT_MODEL); const [temperature, setTemperature] = useState(settings["llm.temperature"] ?? DEFAULT_TEMPERATURE); const [maxDebateRounds, setMaxDebateRounds] = useState(settings["llm.maxDebateRounds"] ?? DEFAULT_MAX_DEBATE_ROUNDS); const tempTimerRef = useRef | null>(null); useEffect(() => { setModel(settings["llm.model"] ?? DEFAULT_MODEL); setTemperature(settings["llm.temperature"] ?? DEFAULT_TEMPERATURE); setMaxDebateRounds(settings["llm.maxDebateRounds"] ?? DEFAULT_MAX_DEBATE_ROUNDS); return () => { if (tempTimerRef.current) clearTimeout(tempTimerRef.current); }; }, [settings]); const saveModel = async (value: string) => { setModel(value); await onSave("llm.model", value); }; const saveTemperature = async (value: number) => { setTemperature(value); if (tempTimerRef.current) clearTimeout(tempTimerRef.current); tempTimerRef.current = setTimeout(() => { onSave("llm.temperature", value).catch((e) => console.error("Failed to save temperature:", e)); }, 300); }; const saveMaxDebateRounds = async (value: number) => { const clamped = Math.min(10, Math.max(1, value)); setMaxDebateRounds(clamped); await onSave("llm.maxDebateRounds", clamped); }; return (

LLM & Agents

Configure the language model and agent behavior for trading analysis.

{saveError && (
{saveError}
)}
saveTemperature(parseFloat(e.target.value))} className="w-full" />
0.0 (deterministic) 2.0 (creative)
saveMaxDebateRounds(Math.max(1, parseInt(e.target.value) || 1))} className="w-32 border border-gray-300 rounded-lg px-4 py-2.5 text-gray-900 focus:ring-2 focus:ring-blue-500" />
); }