/** * Recommendation Card (Feature 17 — Story 17.15) * * Displays an individual optimization recommendation. */ import React, { useState } from 'react'; import type { EnhancedRecommendation, OptimizationCategory, ImplementationDifficulty, } from '@agentkitai/agentlens-core'; import { request } from '../../api/core'; const CATEGORY_META: Record = { model_downgrade: { label: 'Model Downgrade', icon: '⬇️' }, prompt_optimization: { label: 'Prompt Optimization', icon: '✂️' }, caching: { label: 'Caching', icon: '💾' }, tool_reduction: { label: 'Tool Reduction', icon: '🔧' }, }; const CONFIDENCE_STYLES: Record = { high: 'bg-green-100 text-green-800', medium: 'bg-yellow-100 text-yellow-800', low: 'bg-gray-100 text-gray-600', }; const DIFFICULTY_LABELS: Record = { auto: 'Automatic', config_change: 'Config Change', code_change: 'Code Change', }; function formatCost(usd: number): string { if (usd < 0.01) return `$${usd.toFixed(4)}`; if (usd < 1) return `$${usd.toFixed(3)}`; return `$${usd.toFixed(2)}`; } interface RecommendationCardProps { recommendation: EnhancedRecommendation; onApplied?: () => void; } export function RecommendationCard({ recommendation: rec, onApplied, }: RecommendationCardProps): React.ReactElement { const [applying, setApplying] = useState(false); const [applied, setApplied] = useState(false); const meta = CATEGORY_META[rec.category]; const canApply = rec.difficulty === 'auto' || rec.difficulty === 'config_change'; const handleApply = async () => { setApplying(true); try { await request(`/api/optimize/recommendations/${encodeURIComponent(rec.id)}/apply`, { method: 'POST', }); setApplied(true); onApplied?.(); } catch { // Apply endpoint may not exist yet (Story 17.12) } finally { setApplying(false); } }; return (
{/* Header */}
{meta.icon}
{meta.label} {rec.agentId && ( Agent: {rec.agentId} )}
{formatCost(rec.estimatedMonthlySavings)}
/month
{/* Badges */}
{rec.confidence} confidence {DIFFICULTY_LABELS[rec.difficulty]} {rec.evidence.callsAnalyzed.toLocaleString()} calls analyzed
{/* Model downgrade detail */} {rec.modelDowngrade && (
{rec.modelDowngrade.currentModel} {rec.modelDowngrade.recommendedModel} ({rec.modelDowngrade.callVolume.toLocaleString()} calls,{' '} {rec.modelDowngrade.complexityTier} tier)
)} {/* Actionable steps */} {rec.actionableSteps.length > 0 && (
    {rec.actionableSteps.map((step, i) => (
  • {step}
  • ))}
)} {/* Apply button */}
{applied ? ( ✓ Applied ) : canApply ? ( ) : ( Requires code change )}
); }