refactor: Archive experimental LLM features for MVP stability (Phase 1.1)

Moved experimental LLM integration code to optimization_engine/future/:
- llm_optimization_runner.py - Runtime LLM API runner
- llm_workflow_analyzer.py - Workflow analysis
- inline_code_generator.py - Auto-generate calculations
- hook_generator.py - Auto-generate hooks
- report_generator.py - LLM report generation
- extractor_orchestrator.py - Extractor orchestration

Added comprehensive optimization_engine/future/README.md explaining:
- MVP LLM strategy (Claude Code skills, not runtime LLM)
- Why files were archived
- When to revisit post-MVP
- Production architecture reference

Production runner confirmed: optimization_engine/runner.py is sole active runner.

This establishes clear separation between:
- Production code (stable, no runtime LLM dependencies)
- Experimental code (archived for post-MVP exploration)

Part of Phase 1: Core Stabilization & Organization for MVP

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-24 09:12:36 -05:00
parent 46515475cb
commit d228ccec66
377 changed files with 1195 additions and 16789 deletions

View File

@@ -3,33 +3,53 @@ import {
LineChart, Line, ScatterChart, Scatter,
XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, Cell
} from 'recharts';
import { useWebSocket } from '../hooks/useWebSocket';
import { Card } from '../components/Card';
import { MetricCard } from '../components/MetricCard';
import { StudyCard } from '../components/StudyCard';
import { useOptimizationWebSocket } from '../hooks/useWebSocket';
import { apiClient } from '../api/client';
import { Card } from '../components/common/Card';
import { MetricCard } from '../components/dashboard/MetricCard';
import { StudyCard } from '../components/dashboard/StudyCard';
import { OptimizerPanel } from '../components/OptimizerPanel';
import { ParetoPlot } from '../components/ParetoPlot';
import { ParallelCoordinatesPlot } from '../components/ParallelCoordinatesPlot';
import type { Study, Trial, ConvergenceDataPoint, ParameterSpaceDataPoint } from '../types';
interface DashboardProps {
studies: Study[];
selectedStudyId: string | null;
onStudySelect: (studyId: string) => void;
}
export default function Dashboard({ studies, selectedStudyId, onStudySelect }: DashboardProps) {
const [trials, setTrials] = useState<Trial[]>([]);
export default function Dashboard() {
const [studies, setStudies] = useState<Study[]>([]);
const [selectedStudyId, setSelectedStudyId] = useState<string | null>(null);
const [allTrials, setAllTrials] = useState<Trial[]>([]);
const [displayedTrials, setDisplayedTrials] = useState<Trial[]>([]);
const [bestValue, setBestValue] = useState<number>(Infinity);
const [prunedCount, setPrunedCount] = useState<number>(0);
const [alerts, setAlerts] = useState<Array<{ id: number; type: 'success' | 'warning'; message: string }>>([]);
const [alertIdCounter, setAlertIdCounter] = useState(0);
const [expandedTrials, setExpandedTrials] = useState<Set<number>>(new Set());
const [sortBy, setSortBy] = useState<'performance' | 'chronological'>('performance');
// Protocol 13: New state for metadata and Pareto front
const [studyMetadata, setStudyMetadata] = useState<any>(null);
const [paretoFront, setParetoFront] = useState<any[]>([]);
// Load studies on mount
useEffect(() => {
apiClient.getStudies()
.then(data => {
setStudies(data.studies);
if (data.studies.length > 0) {
// Check LocalStorage for last selected study
const savedStudyId = localStorage.getItem('lastSelectedStudyId');
const studyExists = data.studies.find(s => s.id === savedStudyId);
if (savedStudyId && studyExists) {
setSelectedStudyId(savedStudyId);
} else {
const running = data.studies.find(s => s.status === 'running');
setSelectedStudyId(running?.id || data.studies[0].id);
}
}
})
.catch(console.error);
}, []);
const showAlert = (type: 'success' | 'warning', message: string) => {
const id = alertIdCounter;
setAlertIdCounter(prev => prev + 1);
@@ -40,54 +60,50 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
};
// WebSocket connection
const { isConnected } = useWebSocket({
const { connectionStatus } = useOptimizationWebSocket({
studyId: selectedStudyId,
onTrialCompleted: (trial) => {
setTrials(prev => [trial, ...prev].slice(0, 20));
setAllTrials(prev => [...prev, trial]);
if (trial.objective < bestValue) {
setBestValue(trial.objective);
showAlert('success', `New best: ${trial.objective.toFixed(4)} (Trial #${trial.trial_number})`);
onMessage: (msg) => {
if (msg.type === 'trial_completed') {
const trial = msg.data as Trial;
setAllTrials(prev => [...prev, trial]);
if (trial.objective !== null && trial.objective !== undefined && trial.objective < bestValue) {
setBestValue(trial.objective);
showAlert('success', `New best: ${trial.objective.toFixed(4)} (Trial #${trial.trial_number})`);
}
} else if (msg.type === 'trial_pruned') {
setPrunedCount(prev => prev + 1);
showAlert('warning', `Trial pruned: ${msg.data.pruning_cause}`);
}
},
onNewBest: (trial) => {
console.log('New best trial:', trial);
},
onTrialPruned: (pruned) => {
setPrunedCount(prev => prev + 1);
showAlert('warning', `Trial #${pruned.trial_number} pruned: ${pruned.pruning_cause}`);
},
}
});
// Load initial trial history when study changes
useEffect(() => {
if (selectedStudyId) {
setTrials([]);
setAllTrials([]);
setBestValue(Infinity);
setPrunedCount(0);
setExpandedTrials(new Set());
// Fetch full history
fetch(`/api/optimization/studies/${selectedStudyId}/history`)
.then(res => res.json())
// Save to LocalStorage
localStorage.setItem('lastSelectedStudyId', selectedStudyId);
apiClient.getStudyHistory(selectedStudyId)
.then(data => {
const sortedTrials = data.trials.sort((a: Trial, b: Trial) => a.trial_number - b.trial_number);
setAllTrials(sortedTrials);
setTrials(sortedTrials.slice(-20).reverse());
if (sortedTrials.length > 0) {
const minObj = Math.min(...sortedTrials.map((t: Trial) => t.objective));
const validTrials = data.trials.filter(t => t.objective !== null && t.objective !== undefined);
setAllTrials(validTrials);
if (validTrials.length > 0) {
const minObj = Math.min(...validTrials.map(t => t.objective));
setBestValue(minObj);
}
})
.catch(err => console.error('Failed to load history:', err));
.catch(console.error);
// Fetch pruning count
fetch(`/api/optimization/studies/${selectedStudyId}/pruning`)
.then(res => res.json())
apiClient.getStudyPruning(selectedStudyId)
.then(data => {
setPrunedCount(data.pruned_trials?.length || 0);
})
.catch(err => console.error('Failed to load pruning data:', err));
.catch(console.error);
// Protocol 13: Fetch metadata
fetch(`/api/optimization/studies/${selectedStudyId}/metadata`)
@@ -97,12 +113,12 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
})
.catch(err => console.error('Failed to load metadata:', err));
// Protocol 13: Fetch Pareto front
// Protocol 13: Fetch Pareto front (raw format for Protocol 13 components)
fetch(`/api/optimization/studies/${selectedStudyId}/pareto-front`)
.then(res => res.json())
.then(data => {
if (data.is_multi_objective) {
setParetoFront(data.pareto_front);
.then(paretoData => {
if (paretoData.is_multi_objective && paretoData.pareto_front) {
setParetoFront(paretoData.pareto_front);
} else {
setParetoFront([]);
}
@@ -111,42 +127,92 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
}
}, [selectedStudyId]);
// Prepare chart data
const convergenceData: ConvergenceDataPoint[] = allTrials.map((trial, idx) => ({
trial_number: trial.trial_number,
objective: trial.objective,
best_so_far: Math.min(...allTrials.slice(0, idx + 1).map(t => t.objective)),
}));
// Sort trials based on selected sort order
useEffect(() => {
let sorted = [...allTrials];
if (sortBy === 'performance') {
// Sort by objective (best first)
sorted.sort((a, b) => {
const aObj = a.objective ?? Infinity;
const bObj = b.objective ?? Infinity;
return aObj - bObj;
});
} else {
// Chronological (newest first)
sorted.sort((a, b) => b.trial_number - a.trial_number);
}
setDisplayedTrials(sorted);
}, [allTrials, sortBy]);
const parameterSpaceData: ParameterSpaceDataPoint[] = allTrials.map(trial => {
const params = Object.values(trial.design_variables);
return {
trial_number: trial.trial_number,
x: params[0] || 0,
y: params[1] || 0,
objective: trial.objective,
isBest: trial.objective === bestValue,
};
});
// Auto-refresh polling (every 3 seconds) for trial history
useEffect(() => {
if (!selectedStudyId) return;
const refreshInterval = setInterval(() => {
apiClient.getStudyHistory(selectedStudyId)
.then(data => {
const validTrials = data.trials.filter(t => t.objective !== null && t.objective !== undefined);
setAllTrials(validTrials);
if (validTrials.length > 0) {
const minObj = Math.min(...validTrials.map(t => t.objective));
setBestValue(minObj);
}
})
.catch(err => console.error('Auto-refresh failed:', err));
}, 3000); // Poll every 3 seconds
return () => clearInterval(refreshInterval);
}, [selectedStudyId]);
// Prepare chart data with proper null/undefined handling
const convergenceData: ConvergenceDataPoint[] = allTrials
.filter(t => t.objective !== null && t.objective !== undefined)
.sort((a, b) => a.trial_number - b.trial_number)
.map((trial, idx, arr) => {
const previousTrials = arr.slice(0, idx + 1);
const validObjectives = previousTrials.map(t => t.objective).filter(o => o !== null && o !== undefined);
return {
trial_number: trial.trial_number,
objective: trial.objective,
best_so_far: validObjectives.length > 0 ? Math.min(...validObjectives) : trial.objective,
};
});
const parameterSpaceData: ParameterSpaceDataPoint[] = allTrials
.filter(t => t.objective !== null && t.objective !== undefined && t.design_variables)
.map(trial => {
const params = Object.values(trial.design_variables);
return {
trial_number: trial.trial_number,
x: params[0] || 0,
y: params[1] || 0,
objective: trial.objective,
isBest: trial.objective === bestValue,
};
});
// Calculate average objective
const avgObjective = allTrials.length > 0
? allTrials.reduce((sum, t) => sum + t.objective, 0) / allTrials.length
const validObjectives = allTrials.filter(t => t.objective !== null && t.objective !== undefined).map(t => t.objective);
const avgObjective = validObjectives.length > 0
? validObjectives.reduce((sum, obj) => sum + obj, 0) / validObjectives.length
: 0;
// Get parameter names
const paramNames = allTrials.length > 0 ? Object.keys(allTrials[0].design_variables) : [];
const paramNames = allTrials.length > 0 && allTrials[0].design_variables
? Object.keys(allTrials[0].design_variables)
: [];
// Helper: Format parameter label with unit from metadata
const getParamLabel = (paramName: string, index: number): string => {
if (!studyMetadata?.design_variables) {
return paramName || `Parameter ${index + 1}`;
}
const dv = studyMetadata.design_variables.find((v: any) => v.name === paramName);
if (dv && dv.unit) {
return `${paramName} (${dv.unit})`;
}
return paramName || `Parameter ${index + 1}`;
// Toggle trial expansion
const toggleTrialExpansion = (trialNumber: number) => {
setExpandedTrials(prev => {
const newSet = new Set(prev);
if (newSet.has(trialNumber)) {
newSet.delete(trialNumber);
} else {
newSet.add(trialNumber);
}
return newSet;
});
};
// Export functions
@@ -169,7 +235,7 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
const rows = allTrials.map(t => [
t.trial_number,
t.objective,
...paramNames.map(k => t.design_variables[k])
...paramNames.map(k => t.design_variables?.[k] ?? '')
].join(','));
const csv = [headers, ...rows].join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
@@ -183,7 +249,7 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
};
return (
<div className="container mx-auto p-6">
<div className="container mx-auto">
{/* Alerts */}
<div className="fixed top-4 right-4 z-50 space-y-2">
{alerts.map(alert => (
@@ -201,12 +267,24 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
</div>
{/* Header */}
<header className="mb-8 flex items-center justify-between border-b border-dark-500 pb-4">
<header className="mb-8 flex items-center justify-between border-b border-dark-600 pb-4">
<div>
<h1 className="text-3xl font-bold text-primary-400">Atomizer Dashboard</h1>
<p className="text-dark-200 mt-2">Real-time optimization monitoring</p>
<h1 className="text-3xl font-bold text-primary-400">Live Dashboard</h1>
<p className="text-dark-300 mt-1">Real-time optimization monitoring</p>
</div>
<div className="flex gap-2">
<button
onClick={() => {
if (selectedStudyId) {
window.open(`http://localhost:8080?study=${selectedStudyId}`, '_blank');
}
}}
className="btn-secondary"
disabled={!selectedStudyId}
title="Open Optuna Dashboard (make sure it's running on port 8080)"
>
Optuna Dashboard
</button>
<button onClick={exportJSON} className="btn-secondary" disabled={allTrials.length === 0}>
Export JSON
</button>
@@ -226,7 +304,7 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
key={study.id}
study={study}
isActive={study.id === selectedStudyId}
onClick={() => onStudySelect(study.id)}
onClick={() => setSelectedStudyId(study.id)}
/>
))}
</div>
@@ -248,14 +326,6 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
value={avgObjective > 0 ? avgObjective.toFixed(4) : '-'}
valueColor="text-blue-400"
/>
<MetricCard
label="Connection"
value={isConnected ? 'Connected' : 'Disconnected'}
valueColor={isConnected ? 'text-green-400' : 'text-red-400'}
/>
</div>
<div className="grid grid-cols-4 gap-4 mb-6">
<MetricCard
label="Pruned"
value={prunedCount}
@@ -264,25 +334,38 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
</div>
{/* Protocol 13: Intelligent Optimizer & Pareto Front */}
{selectedStudyId && (
{selectedStudyId && paretoFront.length > 0 && studyMetadata && studyMetadata.objectives && (
<div className="grid grid-cols-2 gap-6 mb-6">
<OptimizerPanel studyId={selectedStudyId} />
{paretoFront.length > 0 && studyMetadata && (
<ParetoPlot
paretoData={paretoFront}
objectives={studyMetadata.objectives || []}
/>
)}
<Card title="Optimizer Strategy">
<div className="space-y-2">
<div className="text-sm text-dark-300">
<span className="font-semibold text-dark-100">Algorithm:</span> {studyMetadata.sampler || 'NSGA-II'}
</div>
<div className="text-sm text-dark-300">
<span className="font-semibold text-dark-100">Type:</span> Multi-objective
</div>
<div className="text-sm text-dark-300">
<span className="font-semibold text-dark-100">Objectives:</span> {studyMetadata.objectives?.length || 2}
</div>
<div className="text-sm text-dark-300">
<span className="font-semibold text-dark-100">Design Variables:</span> {studyMetadata.design_variables?.length || 0}
</div>
</div>
</Card>
<ParetoPlot
paretoData={paretoFront}
objectives={studyMetadata.objectives}
/>
</div>
)}
{/* Parallel Coordinates (full width for multi-objective) */}
{paretoFront.length > 0 && studyMetadata && (
{paretoFront.length > 0 && studyMetadata && studyMetadata.objectives && studyMetadata.design_variables && (
<div className="mb-6">
<ParallelCoordinatesPlot
paretoData={paretoFront}
objectives={studyMetadata.objectives || []}
designVariables={studyMetadata.design_variables || []}
objectives={studyMetadata.objectives}
designVariables={studyMetadata.design_variables}
/>
</div>
)}
@@ -344,14 +427,14 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
dataKey="x"
stroke="#94a3b8"
name={paramNames[0] || 'X'}
label={{ value: getParamLabel(paramNames[0], 0), position: 'insideBottom', offset: -5, fill: '#94a3b8' }}
label={{ value: paramNames[0] || 'Parameter 1', position: 'insideBottom', offset: -5, fill: '#94a3b8' }}
/>
<YAxis
type="number"
dataKey="y"
stroke="#94a3b8"
name={paramNames[1] || 'Y'}
label={{ value: getParamLabel(paramNames[1], 1), angle: -90, position: 'insideLeft', fill: '#94a3b8' }}
label={{ value: paramNames[1] || 'Parameter 2', angle: -90, position: 'insideLeft', fill: '#94a3b8' }}
/>
<Tooltip
cursor={{ strokeDasharray: '3 3' }}
@@ -381,38 +464,149 @@ export default function Dashboard({ studies, selectedStudyId, onStudySelect }: D
</Card>
</div>
{/* Trial Feed */}
<Card title="Recent Trials">
<div className="space-y-2 max-h-96 overflow-y-auto">
{trials.length > 0 ? (
trials.map(trial => (
<div
key={trial.trial_number}
className={`p-3 rounded-lg transition-all duration-200 ${
trial.objective === bestValue
? 'bg-green-900 border-l-4 border-green-400'
: 'bg-dark-500 hover:bg-dark-400'
{/* Trial History with Sort Controls */}
<Card
title={
<div className="flex items-center justify-between w-full">
<span>Trial History ({displayedTrials.length} trials)</span>
<div className="flex gap-2">
<button
onClick={() => setSortBy('performance')}
className={`px-3 py-1 rounded text-sm ${
sortBy === 'performance'
? 'bg-primary-500 text-white'
: 'bg-dark-500 text-dark-200 hover:bg-dark-400'
}`}
>
<div className="flex justify-between items-center mb-1">
<span className="font-semibold text-primary-400">
Trial #{trial.trial_number}
</span>
<span className={`font-mono text-lg ${
trial.objective === bestValue ? 'text-green-400 font-bold' : 'text-dark-100'
}`}>
{trial.objective.toFixed(4)}
</span>
Best First
</button>
<button
onClick={() => setSortBy('chronological')}
className={`px-3 py-1 rounded text-sm ${
sortBy === 'chronological'
? 'bg-primary-500 text-white'
: 'bg-dark-500 text-dark-200 hover:bg-dark-400'
}`}
>
Newest First
</button>
</div>
</div>
}
>
<div className="space-y-2 max-h-[600px] overflow-y-auto">
{displayedTrials.length > 0 ? (
displayedTrials.map(trial => {
const isExpanded = expandedTrials.has(trial.trial_number);
const isBest = trial.objective === bestValue;
return (
<div
key={trial.trial_number}
className={`rounded-lg transition-all duration-200 cursor-pointer ${
isBest
? 'bg-green-900 border-l-4 border-green-400'
: 'bg-dark-500 hover:bg-dark-400'
}`}
onClick={() => toggleTrialExpansion(trial.trial_number)}
>
{/* Collapsed View */}
<div className="p-3">
<div className="flex justify-between items-center">
<span className="font-semibold text-primary-400">
Trial #{trial.trial_number}
{isBest && <span className="ml-2 text-xs bg-green-700 text-green-100 px-2 py-1 rounded">BEST</span>}
</span>
<div className="flex items-center gap-3">
<span className={`font-mono text-lg ${
isBest ? 'text-green-400 font-bold' : 'text-dark-100'
}`}>
{trial.objective !== null && trial.objective !== undefined
? trial.objective.toFixed(4)
: 'N/A'}
</span>
<span className="text-dark-400 text-sm">
{isExpanded ? '▼' : '▶'}
</span>
</div>
</div>
{/* Quick Preview */}
{!isExpanded && trial.results && Object.keys(trial.results).length > 0 && (
<div className="text-xs text-primary-300 flex flex-wrap gap-3 mt-2">
{trial.results.mass && (
<span>Mass: {trial.results.mass.toFixed(2)}g</span>
)}
{trial.results.frequency && (
<span>Freq: {trial.results.frequency.toFixed(2)}Hz</span>
)}
</div>
)}
</div>
{/* Expanded View */}
{isExpanded && (
<div className="px-3 pb-3 space-y-3">
{/* Design Variables */}
{trial.design_variables && Object.keys(trial.design_variables).length > 0 && (
<div className="border-t border-dark-400 pt-3">
<h4 className="text-sm font-semibold text-dark-200 mb-2">Design Variables</h4>
<div className="grid grid-cols-2 gap-2 text-xs">
{Object.entries(trial.design_variables).map(([key, val]) => (
<div key={key} className="flex justify-between bg-dark-600 px-2 py-1 rounded">
<span className="text-dark-300">{key}:</span>
<span className="text-dark-100 font-mono">{val.toFixed(4)}</span>
</div>
))}
</div>
</div>
)}
{/* Results */}
{trial.results && Object.keys(trial.results).length > 0 && (
<div className="border-t border-dark-400 pt-3">
<h4 className="text-sm font-semibold text-dark-200 mb-2">Extracted Results</h4>
<div className="grid grid-cols-2 gap-2 text-xs">
{Object.entries(trial.results).map(([key, val]) => (
<div key={key} className="flex justify-between bg-dark-600 px-2 py-1 rounded">
<span className="text-dark-300">{key}:</span>
<span className="text-primary-300 font-mono">
{typeof val === 'number' ? val.toFixed(4) : String(val)}
</span>
</div>
))}
</div>
</div>
)}
{/* All User Attributes */}
{trial.user_attrs && Object.keys(trial.user_attrs).length > 0 && (
<div className="border-t border-dark-400 pt-3">
<h4 className="text-sm font-semibold text-dark-200 mb-2">All Attributes</h4>
<div className="max-h-48 overflow-y-auto">
<pre className="text-xs text-dark-300 bg-dark-700 p-2 rounded">
{JSON.stringify(trial.user_attrs, null, 2)}
</pre>
</div>
</div>
)}
{/* Timestamps */}
{trial.start_time && trial.end_time && (
<div className="border-t border-dark-400 pt-3 text-xs text-dark-400">
<div className="flex justify-between">
<span>Duration:</span>
<span>
{((new Date(trial.end_time).getTime() - new Date(trial.start_time).getTime()) / 1000).toFixed(1)}s
</span>
</div>
</div>
)}
</div>
)}
</div>
<div className="text-xs text-dark-200 flex flex-wrap gap-3">
{Object.entries(trial.design_variables).map(([key, val]) => (
<span key={key}>
<span className="text-dark-400">{key}:</span> {val.toFixed(3)}
</span>
))}
</div>
</div>
))
);
})
) : (
<div className="text-center py-8 text-dark-300">
No trials yet. Waiting for optimization to start...