import type { AgentLogEntry } from "@kb/core"; import { ProviderIcon } from "./ProviderIcon"; interface ModelInfo { provider?: string; modelId?: string; } interface AgentLogViewerProps { entries: AgentLogEntry[]; loading: boolean; executorModel?: ModelInfo | null; validatorModel?: ModelInfo | null; } /** * Renders agent log entries in a scrollable, monospace container. * Displays entries in reverse chronological order (newest first). */ export function AgentLogViewer({ entries, loading, executorModel, validatorModel }: AgentLogViewerProps) { if (loading && entries.length === 0) { return (
Loading agent logs…
); } if (entries.length === 0) { return (
No agent output yet.
); } // Reverse entries so newest appear first const reversedEntries = [...entries].reverse(); const hasExecutorOverride = executorModel?.provider && executorModel?.modelId; const hasValidatorOverride = validatorModel?.provider && validatorModel?.modelId; return (
{/* Model info header */}
Executor: {hasExecutorOverride ? ( {executorModel.provider}/{executorModel.modelId} ) : ( Using default )}
Validator: {hasValidatorOverride ? ( {validatorModel.provider}/{validatorModel.modelId} ) : ( Using default )}
{reversedEntries.map((entry, i) => { // Look at previous entry in reversed array (= next chronologically) for deduplication const prev = reversedEntries[i - 1]; const isBlockLevel = entry.type === "tool" || entry.type === "tool_result" || entry.type === "tool_error"; const showBadge = entry.agent ? isBlockLevel || i === 0 || (prev && (prev.agent !== entry.agent || prev.type !== entry.type)) : false; const agentBadge = showBadge ? ( [{entry.agent}] ) : null; if (entry.type === "tool") { return (
{agentBadge}⚡ {entry.text} {entry.detail && ( — {entry.detail} )}
); } if (entry.type === "thinking") { return ( {agentBadge}{entry.text} ); } if (entry.type === "tool_result") { return (
{agentBadge}✓ {entry.text} {entry.detail && ( — {entry.detail} )}
); } if (entry.type === "tool_error") { return (
{agentBadge}✗ {entry.text} {entry.detail && ( — {entry.detail} )}
); } // Default: text entries return ( {agentBadge}{entry.text} ); })}
); }