import { type KeyboardEvent, useEffect, useMemo, useRef, useState } from 'react';
import { AlertCircle, ArrowUp, Bot, Loader2, User } from 'lucide-react';
import {
buildAgentActivityRows,
formatAgentActivityLabel,
isAgentActivityActive,
isAgentActivityCompleted,
type SessionActivityState,
} from '@renderer/lib/sessionActivity';
import type { PatternDefinition } from '@shared/domain/pattern';
import type { ProjectRecord } from '@shared/domain/project';
import type { SessionRecord } from '@shared/domain/session';
function ThinkingDots() {
return (
);
}
interface ChatPaneProps {
activity?: SessionActivityState;
project: ProjectRecord;
pattern: PatternDefinition;
session: SessionRecord;
onSend: (content: string) => Promise;
}
export function ChatPane({ activity, project, pattern, session, onSend }: ChatPaneProps) {
const [input, setInput] = useState('');
const transcriptRef = useRef(null);
const textareaRef = useRef(null);
const isBusy = session.status === 'running';
const activityRows = useMemo(
() => buildAgentActivityRows(activity, pattern.agents, isBusy),
[activity, isBusy, pattern.agents],
);
useEffect(() => {
transcriptRef.current?.scrollTo({
top: transcriptRef.current.scrollHeight,
behavior: 'smooth',
});
}, [session.messages.length, isBusy]);
async function handleSubmit() {
const text = input.trim();
if (!text || isBusy) return;
setInput('');
await onSend(text);
}
function handleKeyDown(e: KeyboardEvent) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
void handleSubmit();
}
}
return (
{/* Header — extra top padding clears the title bar overlay zone */}
{/* Messages */}
{session.messages.length === 0 ? (
Send a message to start the conversation
Using {pattern.name} in{' '}
{project.name}
) : (
{session.messages.map((message) => {
const isUser = message.role === 'user';
return (
{isUser ? : }
{message.authorName}
{message.content}
{message.pending && message.content && (
)}
{message.pending && !message.content &&
}
);
})}
{isBusy && activityRows.length > 0 && (
Agent activity
{activityRows.map((row) => (
{row.agentName}
{formatAgentActivityLabel(row.activity)}
))}
)}
)}
{/* Input area */}
{session.lastError && (
)}
);
}