GOD AGENT OS
feat(v12): True Autonomous Agent Runtime with E2B sandbox execution
876b3cb
'use client'
import { useEffect, useRef } from 'react'
import { X, MonitorPlay, Brain, Globe, Code2, Terminal, GitBranch, Rocket, CheckCircle, XCircle, Loader, FileText, Search, PenTool, HardDrive } from 'lucide-react'
import { useAppStore, type ComputerUseStep } from '@/store/useAppStore'
const STEP_ICONS: Record<string, { icon: React.ElementType; color: string; bg: string }> = {
thinking: { icon: Brain, color: '#a78bfa', bg: 'rgba(124,58,237,0.12)' },
browsing: { icon: Globe, color: '#22d3ee', bg: 'rgba(34,211,238,0.12)' },
coding: { icon: Code2, color: '#34d399', bg: 'rgba(52,211,153,0.12)' },
terminal: { icon: Terminal, color: '#f59e0b', bg: 'rgba(245,158,11,0.12)' },
executing: { icon: Terminal, color: '#f59e0b', bg: 'rgba(245,158,11,0.12)' },
file: { icon: FileText, color: '#94a3b8', bg: 'rgba(148,163,184,0.1)' },
git: { icon: GitBranch, color: '#60a5fa', bg: 'rgba(96,165,250,0.12)' },
deploy: { icon: Rocket, color: '#f472b6', bg: 'rgba(244,114,182,0.12)' },
complete: { icon: CheckCircle, color: '#22c55e', bg: 'rgba(34,197,94,0.12)' },
error: { icon: XCircle, color: '#ef4444', bg: 'rgba(239,68,68,0.12)' },
reading: { icon: FileText, color: '#94a3b8', bg: 'rgba(148,163,184,0.1)' },
writing: { icon: PenTool, color: '#818cf8', bg: 'rgba(129,140,248,0.12)'},
searching: { icon: Search, color: '#fbbf24', bg: 'rgba(251,191,36,0.12)' },
sandbox: { icon: HardDrive, color: '#fb923c', bg: 'rgba(251,146,60,0.12)' },
}
function StepCard({ step }: { step: ComputerUseStep }) {
const def = STEP_ICONS[step.type] || STEP_ICONS.thinking
const Icon = def.icon
return (
<div
className="computer-use-step animate-fade-in"
style={{ borderBottom: '1px solid var(--border)' }}
>
<div className="computer-use-step-icon" style={{ background: def.bg }}>
{step.status === 'running' && step.type !== 'complete' && step.type !== 'error' && step.type !== 'done' ? (
<Loader size={14} style={{ color: def.color, animation: 'spin 1s linear infinite' }} />
) : (
<Icon size={14} style={{ color: def.color }} />
)}
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<span className="text-xs font-semibold capitalize" style={{ color: def.color }}>
{step.type}
</span>
<span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
{new Date(step.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
</span>
</div>
<div className="text-xs mt-0.5" style={{ color: 'var(--text-secondary)' }}>
{step.title}
</div>
{step.detail && (
<div className="text-[11px] mt-1 p-2 rounded-lg" style={{ background: 'var(--surface-3)', color: 'var(--text-muted)' }}>
{step.detail}
</div>
)}
{step.data && step.type === 'coding' && (() => {
const code = step.data['code'] as string | undefined
return code ? (
<pre className="text-[11px] mt-1 p-2 rounded-lg overflow-x-auto" style={{ background: 'var(--surface-3)', color: '#86efac', fontFamily: 'monospace' }}>
{code.slice(0, 200)}{code.length > 200 ? '...' : ''}
</pre>
) : null
})()}
</div>
</div>
)
}
export default function ComputerUsePanel() {
const { computerUseSteps, clearComputerUseSteps, setComputerUseOpen, locale } = useAppStore()
const bottomRef = useRef<HTMLDivElement>(null)
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: 'smooth' })
}, [computerUseSteps.length])
const runningSteps = computerUseSteps.filter(s => s.status === 'running').length
return (
<div className="computer-use-panel flex flex-col" style={{ borderLeft: '1px solid var(--border)', background: 'var(--surface-1)' }}>
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 shrink-0"
style={{ borderBottom: '1px solid var(--border)' }}>
<div className="flex items-center gap-2">
<div className="w-7 h-7 rounded-lg flex items-center justify-center"
style={{ background: 'rgba(124,58,237,0.12)', border: '1px solid rgba(124,58,237,0.2)' }}>
<MonitorPlay size={14} style={{ color: '#a78bfa' }} />
</div>
<div>
<div className="text-xs font-bold" style={{ color: 'var(--text-primary)' }}>
{locale === 'my' ? 'Computer ကြည့်ရန်' : 'Computer Use'}
</div>
<div className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
{locale === 'my' ? 'Agent လုပ်ဆောင်မှုများ' : 'Live agent activity'}
</div>
</div>
</div>
<div className="flex items-center gap-2">
{runningSteps > 0 && (
<div className="badge badge-purple text-[10px]">
<Loader size={8} style={{ animation: 'spin 1s linear infinite' }} />
{runningSteps} {locale === 'my' ? 'လုပ်နေသည်' : 'running'}
</div>
)}
<button
onClick={clearComputerUseSteps}
className="text-[10px] px-2 py-1 rounded-md hover:bg-white/5 transition-colors"
style={{ color: 'var(--text-muted)' }}
>
{locale === 'my' ? 'ရှင်းလင်း' : 'Clear'}
</button>
<button
onClick={() => setComputerUseOpen(false)}
className="p-1 rounded-md hover:bg-white/5 transition-colors"
style={{ color: 'var(--text-muted)' }}
>
<X size={14} />
</button>
</div>
</div>
{/* Steps */}
<div className="flex-1 overflow-y-auto">
{computerUseSteps.length === 0 ? (
<div className="flex flex-col items-center justify-center h-48 gap-3">
<div className="w-12 h-12 rounded-2xl flex items-center justify-center"
style={{ background: 'rgba(124,58,237,0.08)', border: '1px solid rgba(124,58,237,0.15)' }}>
<MonitorPlay size={20} style={{ color: '#6d28d9' }} />
</div>
<div className="text-center">
<div className="text-xs font-semibold" style={{ color: 'var(--text-muted)' }}>
{locale === 'my' ? 'လုပ်ဆောင်မှုမရှိသေးပါ' : 'No activity yet'}
</div>
<div className="text-[10px] mt-1" style={{ color: 'var(--text-muted)' }}>
{locale === 'my'
? 'Chat မှာ task တစ်ခုပေးပြီး agent ၏ computer အသုံးပြုမှုကြည့်ပါ'
: 'Send a task in chat to see Manus-style agent activity here'}
</div>
</div>
</div>
) : (
<>
{computerUseSteps.map(step => (
<StepCard key={step.id} step={step} />
))}
<div ref={bottomRef} />
</>
)}
</div>
{/* Footer Stats */}
<div className="px-4 py-2.5 shrink-0 flex items-center justify-between"
style={{ borderTop: '1px solid var(--border)' }}>
<span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
{computerUseSteps.length} {locale === 'my' ? 'အဆင့်' : 'steps'}
</span>
<span className="text-[10px]" style={{ color: 'var(--text-muted)' }}>
{computerUseSteps.filter(s => s.type === 'complete').length} {locale === 'my' ? 'ပြီးဆုံး' : 'completed'}
</span>
</div>
</div>
)
}