'use client' import { useState, useMemo } from 'react' import type { UsageData } from '@/lib/parse-logs' import { analyzePersonality, type PersonalityProfile, type BigFiveProfile } from '@/lib/personality' import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select' import { Button } from '@/components/ui/button' import { Copy, Check, Brain, Target, Sparkles, ArrowRight } from 'lucide-react' const TASK_OPTIONS = [ { value: 'frontendDev', label: 'Frontend Development' }, { value: 'backendDev', label: 'Backend Development' }, { value: 'dataEngineering', label: 'Data Engineering' }, { value: 'devOps', label: 'DevOps' }, { value: 'debugging', label: 'Debugging' }, { value: 'refactoring', label: 'Refactoring' }, ] const MBTI_DESCRIPTIONS: Record = { ISTJ: 'The Inspector — Methodical, detail-oriented, follows established procedures', ISFJ: 'The Protector — Supportive, reliable, focused on preserving working code', INFJ: 'The Counselor — Insightful, sees patterns, anticipates architectural needs', INTJ: 'The Architect — Strategic, independent, designs for long-term quality', ISTP: 'The Craftsman — Practical, efficient, excels at targeted fixes', ISFP: 'The Composer — Adaptable, aesthetic sense, good at UI refinement', INFP: 'The Healer — Idealistic, explores creative solutions, values code clarity', INTP: 'The Thinker — Analytical, explores edge cases, values logical consistency', ESTP: 'The Dynamo — Action-oriented, quick iterations, bias toward execution', ESFP: 'The Performer — Energetic, responsive, generates many alternatives', ENFP: 'The Champion — Enthusiastic explorer, broad tool usage, creative approaches', ENTP: 'The Visionary — Innovative, questions assumptions, proposes novel solutions', ESTJ: 'The Supervisor — Organized, efficient, follows project conventions strictly', ESFJ: 'The Provider — Cooperative, communicative, adapts to user preferences', ENFJ: 'The Teacher — Explains reasoning, mentors through code, proactive guidance', ENTJ: 'The Commander — Decisive, takes charge, designs comprehensive solutions', } function TraitBar({ label, value, idealValue, color, leftLabel, rightLabel, }: { label: string value: number idealValue?: number color: string leftLabel?: string rightLabel?: string }) { return (
{label} {Math.round(value)}/100
{(leftLabel || rightLabel) && (
{leftLabel} {rightLabel}
)}
{idealValue !== undefined && (
)}
) } function MBTIDimension({ label, value, leftPole, rightPole, }: { label: string value: number leftPole: string rightPole: string }) { const normalized = (value + 100) / 2 // -100..+100 → 0..100 const isLeft = value < 0 return (
{leftPole} {label} {rightPole}
{isLeft ? (
) : (
)}
) } function FitScoreCard({ task, score, isSelected }: { task: string; score: number; isSelected: boolean }) { const taskNames: Record = { frontendDev: 'Frontend', backendDev: 'Backend', dataEngineering: 'Data Eng', devOps: 'DevOps', debugging: 'Debug', refactoring: 'Refactor', } const getColor = (s: number) => { if (s >= 80) return 'text-foreground' if (s >= 60) return 'text-foreground' if (s >= 40) return 'text-muted-foreground' return 'text-muted-foreground' } const getBg = (s: number) => { if (s >= 80) return 'bg-chart-2/10' if (s >= 60) return 'bg-chart-1/10' if (s >= 40) return 'bg-chart-3/10' return 'bg-muted/50' } return (
{taskNames[task]}
{score}%
) } export function PersonalityFit({ data }: { data: UsageData }) { const [targetTask, setTargetTask] = useState('backendDev') const targetTaskLabel = TASK_OPTIONS.find((t) => t.value === targetTask)?.label || targetTask const [copied, setCopied] = useState(false) const profile: PersonalityProfile = useMemo( () => analyzePersonality(data, targetTask), [data, targetTask] ) const handleCopyPrompt = async () => { await navigator.clipboard.writeText(profile.systemPrompt) setCopied(true) setTimeout(() => setCopied(false), 2000) } const bigFiveColors: Record = { openness: 'var(--chart-1)', conscientiousness: 'var(--chart-2)', extraversion: 'var(--chart-3)', agreeableness: 'var(--chart-4)', neuroticism: 'var(--chart-5)', } const idealProfile = { frontendDev: { openness: 80, conscientiousness: 60, extraversion: 70, agreeableness: 75, neuroticism: 20 }, backendDev: { openness: 50, conscientiousness: 90, extraversion: 40, agreeableness: 60, neuroticism: 15 }, dataEngineering: { openness: 45, conscientiousness: 95, extraversion: 35, agreeableness: 55, neuroticism: 10 }, devOps: { openness: 55, conscientiousness: 85, extraversion: 50, agreeableness: 65, neuroticism: 15 }, debugging: { openness: 70, conscientiousness: 80, extraversion: 55, agreeableness: 50, neuroticism: 25 }, refactoring: { openness: 65, conscientiousness: 90, extraversion: 45, agreeableness: 70, neuroticism: 15 }, }[targetTask] || { openness: 50, conscientiousness: 50, extraversion: 50, agreeableness: 50, neuroticism: 50 } return (
{/* MBTI type */}
Agent Personality Type
{profile.mbtiType}
{MBTI_DESCRIPTIONS[profile.mbtiType] || 'Unique personality profile'}
{/* Task Fit Scores */}
Task Fit Scores How well the agent's observed personality matches ideal profiles for each task type
Target Task
{Object.entries(profile.fitScores).map(([task, score]) => ( ))}
{/* Big Five and MBTI side by side */}
{/* Big Five */} Big Five (OCEAN) Profile Derived from behavioral signals. Vertical markers show ideal for selected task. {/* MBTI */} MBTI Dimensions Cognitive style inferred from interaction patterns
{/* Behavioral Signals */} Behavioral Signals Raw metrics extracted from conversation traces that drive personality inference
{[ { label: 'Tool Diversity', value: profile.signals.toolDiversity.toFixed(3) }, { label: 'Read-Before-Edit', value: profile.signals.readBeforeEditRatio.toFixed(2) }, { label: 'Output/Input Ratio', value: profile.signals.outputInputRatio.toFixed(2) }, { label: 'Avg Msg Length', value: `${Math.round(profile.signals.avgAssistantMsgLength)} tok` }, { label: 'Bash/Total Ratio', value: profile.signals.bashToTotalRatio.toFixed(3) }, { label: 'Edit/Read Ratio', value: profile.signals.editToReadRatio.toFixed(2) }, { label: 'Tool Entropy', value: profile.signals.toolTransitionEntropy.toFixed(2) }, { label: 'Duration CV', value: profile.signals.sessionDurationVariance.toFixed(2) }, { label: 'Tools/Message', value: profile.signals.avgToolCallsPerMessage.toFixed(2) }, { label: 'Overflow Rate', value: `${(profile.signals.contextOverflowRate * 100).toFixed(1)}%` }, ].map(({ label, value }) => (
{label}
{value}
))}
{/* Recommendations */} {profile.recommendations.length > 0 && (
Personality Tuning Recommendations Adjustments to better fit the {TASK_OPTIONS.find(t => t.value === targetTask)?.label} personality profile
{profile.recommendations.map((rec) => (
{rec.trait} {rec.current} {rec.ideal}

{rec.promptSnippet}

))}
)} {/* System Prompt */}
Generated System Prompt Add this to your AI assistant's system prompt to tune its personality for {TASK_OPTIONS.find(t => t.value === targetTask)?.label}
            {profile.systemPrompt}
          
) }