feat: show agent model, effort, and description in activity panel

Each agent now renders as a card with:
- Status dot and name
- Model badge (e.g. gpt-5.4) and reasoning effort badge
- Agent description text
- Live activity status label
Cards highlight with blue/emerald borders when active/completed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
David Kaya
2026-03-21 19:16:06 +01:00
co-authored by Copilot
parent 879c6c145c
commit c4502c9661
+89 -21
View File
@@ -1,5 +1,5 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { Activity } from 'lucide-react'; import { Activity, Bot, Cpu, Sparkles } from 'lucide-react';
import { import {
buildAgentActivityRows, buildAgentActivityRows,
@@ -11,6 +11,21 @@ import {
import type { PatternDefinition } from '@shared/domain/pattern'; import type { PatternDefinition } from '@shared/domain/pattern';
import type { SessionRecord } from '@shared/domain/session'; import type { SessionRecord } from '@shared/domain/session';
function formatModel(model: string): string {
return model.replace(/-/g, '\u2011');
}
function formatEffort(effort: string | undefined): string | undefined {
if (!effort) return undefined;
const labels: Record<string, string> = {
low: 'Low effort',
medium: 'Medium effort',
high: 'High effort',
xhigh: 'Max effort',
};
return labels[effort] ?? effort;
}
interface ActivityPanelProps { interface ActivityPanelProps {
activity?: SessionActivityState; activity?: SessionActivityState;
pattern: PatternDefinition; pattern: PatternDefinition;
@@ -38,30 +53,82 @@ export function ActivityPanel({ activity, pattern, session }: ActivityPanelProps
</div> </div>
</div> </div>
{/* Agent list */} {/* Agent cards */}
<div className="flex-1 overflow-y-auto px-4 py-3"> <div className="flex-1 overflow-y-auto px-3 py-3">
<div className="space-y-3"> <div className="space-y-2">
{activityRows.map((row) => ( {activityRows.map((row, index) => {
<div className="flex items-start gap-2.5" key={row.key}> const agent = pattern.agents[index];
<span const isActive = isAgentActivityActive(row.activity);
className={`mt-1.5 size-2 shrink-0 rounded-full ${ const isCompleted = isAgentActivityCompleted(row.activity);
isAgentActivityActive(row.activity)
? 'animate-pulse bg-blue-400' return (
: isAgentActivityCompleted(row.activity) <div
? 'bg-emerald-400' className={`rounded-lg border px-3 py-2.5 transition-colors ${
: 'bg-zinc-700' isActive
? 'border-blue-500/20 bg-blue-500/5'
: isCompleted
? 'border-emerald-500/15 bg-emerald-500/5'
: 'border-zinc-800 bg-zinc-900/40'
}`} }`}
/> key={row.key}
<div className="min-w-0 flex-1"> >
<div className="truncate text-[12px] font-medium text-zinc-300"> {/* Agent name + status dot */}
{row.agentName} <div className="flex items-center gap-2">
<span
className={`size-2 shrink-0 rounded-full ${
isActive
? 'animate-pulse bg-blue-400'
: isCompleted
? 'bg-emerald-400'
: 'bg-zinc-700'
}`}
/>
<span className="truncate text-[12px] font-semibold text-zinc-200">
{row.agentName}
</span>
</div> </div>
<div className="truncate text-[12px] text-zinc-500">
{formatAgentActivityLabel(row.activity)} {/* Model + reasoning effort badges */}
{agent && (
<div className="mt-1.5 flex flex-wrap items-center gap-1.5">
<span className="inline-flex items-center gap-1 rounded bg-zinc-800 px-1.5 py-0.5 text-[10px] font-medium text-zinc-400">
<Cpu className="size-2.5" />
{formatModel(agent.model)}
</span>
{agent.reasoningEffort && (
<span className="inline-flex items-center gap-1 rounded bg-zinc-800 px-1.5 py-0.5 text-[10px] font-medium text-zinc-400">
<Sparkles className="size-2.5" />
{formatEffort(agent.reasoningEffort)}
</span>
)}
</div>
)}
{/* Description */}
{agent?.description && (
<p className="mt-1.5 text-[11px] leading-relaxed text-zinc-500">
{agent.description}
</p>
)}
{/* Activity status */}
<div className="mt-2 flex items-center gap-1.5">
<Bot className="size-3 text-zinc-600" />
<span
className={`text-[11px] ${
isActive
? 'text-blue-400'
: isCompleted
? 'text-emerald-400'
: 'text-zinc-600'
}`}
>
{formatAgentActivityLabel(row.activity)}
</span>
</div> </div>
</div> </div>
</div> );
))} })}
</div> </div>
{activityRows.length === 0 && ( {activityRows.length === 0 && (
@@ -73,3 +140,4 @@ export function ActivityPanel({ activity, pattern, session }: ActivityPanelProps
</div> </div>
); );
} }