import { useState, useRef } from 'react' import { Play, Terminal, Activity } from 'lucide-react' import { llmRunStream } from '../lib/api.js' import { RewardBreakdown } from '../components/RewardBreakdown.jsx' import { TurnCard } from '../components/TurnCard.jsx' import { KpiCard } from '../components/KpiCard.jsx' const PRESET_ENDPOINTS = [ { label: 'Ollama (localhost:11434)', url: 'http://localhost:11434/v1' }, { label: 'Hugging Face Router', url: 'https://router.huggingface.co/v1' }, { label: 'OpenAI', url: 'https://api.openai.com/v1' }, { label: 'Custom', url: '' }, ] const MODELS = [ 'qwen2.5:3b', 'qwen2.5:7b', 'qwen2.5:1.5b', 'Qwen/Qwen2.5-7B-Instruct', 'Qwen/Qwen2.5-3B-Instruct', 'meta-llama/Llama-3.2-3B-Instruct', 'gpt-4o-mini', ] export function RunWithLlm() { const [endpoint, setEndpoint] = useState(PRESET_ENDPOINTS[0].label) const [customUrl, setCustomUrl] = useState('') const [apiKey, setApiKey] = useState('') const [model, setModel] = useState(MODELS[0]) const [tier, setTier] = useState('T0') const [seed, setSeed] = useState(42) const [temperature, setTemperature] = useState(0.7) const [maxTurns, setMaxTurns] = useState(10) const [running, setRunning] = useState(false) const [turns, setTurns] = useState([]) const [header, setHeader] = useState(null) const [done, setDone] = useState(null) const stopRef = useRef(null) function run() { setTurns([]); setHeader(null); setDone(null); setRunning(true) const preset = PRESET_ENDPOINTS.find(p => p.label === endpoint) const base_url = (customUrl || preset.url).replace(/\/$/, '') if (stopRef.current) stopRef.current() stopRef.current = llmRunStream( { base_url, api_key: apiKey, model, tier, seed, temperature, max_turns: maxTurns, }, (ev) => { if (ev.kind === 'header') { setHeader(ev) } else if (ev.kind === 'turn') { // SSE event uses `kind` for event type and `kind_of` for action kind; // TurnCard expects `kind` = action kind, so rename here. setTurns(prev => [...prev, { ...ev, kind: ev.kind_of }]) } else if (ev.kind === 'done') { setDone(ev) setRunning(false) } else if (ev.kind === 'error') { setHeader(h => ({ ...(h || {}), error: ev.message })) setRunning(false) } }, ) } return (
{/* ─── MAIN PANE ─── */}

Transcript

{!header && !turns.length && (

Configure the LLM on the right and hit Run episode. Each turn streams here as the model plays.

)} {header && (
Model {header.model}  via  {header.base_url}
Landscape: {header.landscape}
Dim: {header.dim} · Initial budget:{' '} {header.budget}
{header.error && (
{header.error}
)}
)}
{turns.map((t, i) => )}
{done && }
{/* ─── SIDEBAR ─── */}
) } function RangeRow({ label, min, max, step, value, onChange }) { return (
onChange(Number(e.target.value))} className="w-full accent-accent" />
) } function EpisodeDone({ done }) { const reward = done.reward const speedup = done.speedup_vs_adam const myProg = done.my_progress const adamProg = done.adam_progress const rewardTone = reward >= 0.5 ? 'good' : reward >= 0 ? 'warn' : 'bad' // --- Speedup display --- // "Speedup" only makes sense when both optimizers descended. Handle the // degenerate cases cleanly rather than showing "-0.44×" (mathematically // correct, semantically nonsense). let speedupDisplay, speedupTone, speedupSub if (myProg < 0) { // Our optimizer went uphill speedupDisplay = 'diverged' speedupTone = 'bad' speedupSub = `f moved +${Math.abs(myProg).toFixed(2)} (wrong direction)` } else if (adamProg <= 0) { // Adam itself couldn't descend — unfair denominator speedupDisplay = myProg > 0 ? '∞' : '—' speedupTone = myProg > 0 ? 'good' : 'warn' speedupSub = 'Adam made no progress on this landscape' } else { const f = speedup < 100 ? speedup.toFixed(2) : Math.round(speedup).toString() speedupDisplay = `${f}×` speedupTone = speedup >= 1.0 ? 'good' : 'warn' speedupSub = `descent ${myProg.toFixed(2)} vs Adam ${adamProg.toFixed(2)}` } // --- Verdict --- let verdict, verdictTone, verdictSub if (myProg < 0) { verdict = 'Diverged' verdictTone = 'bad' verdictSub = 'optimizer moved away from the minimum' } else if (adamProg <= 0) { verdict = myProg > 0 ? 'Succeeds where Adam fails' : 'Tied · both stuck' verdictTone = myProg > 0 ? 'good' : 'warn' verdictSub = `you: ${myProg.toFixed(2)}, Adam: ${adamProg.toFixed(2)}` } else if (speedup >= 1.5) { verdict = 'Beats Adam' verdictTone = 'good' verdictSub = `${((speedup - 1) * 100).toFixed(0)}% further than Adam` } else if (speedup >= 1.1) { verdict = 'Edges Adam' verdictTone = 'good' verdictSub = `${((speedup - 1) * 100).toFixed(0)}% further than Adam` } else if (speedup >= 0.9) { verdict = 'Matches Adam' verdictTone = 'warn' verdictSub = 'within ±10% of Adam' } else { verdict = 'Behind Adam' verdictTone = 'bad' verdictSub = `covered ${(speedup * 100).toFixed(0)}% of Adam's descent` } return (
Episode complete ended by {done.reason}
= 0 ? '+' : ''} />
) }