feat: attachment context for LLM, markdown rendering, mobile layout with back arrow

This commit is contained in:
Agent Zero
2026-07-17 13:45:21 +02:00
parent 202d80c750
commit 70b8a66fd4
5 changed files with 1490 additions and 131 deletions
+35 -38
View File
@@ -8,58 +8,55 @@ export function AIAssistantPage() {
const [activeSessionId, setActiveSessionId] = useState<string | null>(null);
const [agents, setAgents] = useState<AIAgent[]>([]);
const [selectedAgentId, setSelectedAgentId] = useState<string | null>(null);
const [mobileView, setMobileView] = useState<'list' | 'chat'>('list');
const { registerItems, unregisterPlugin } = usePluginToolbarStore();
useEffect(() => {
fetchAgents().then(setAgents).catch(() => {});
}, []);
useEffect(() => { fetchAgents().then(setAgents).catch(() => {}); }, []);
useEffect(() => {
registerItems('ai_assistant', [
{
id: 'agent-select',
label: 'Agent',
type: 'select',
options: agents.map((a) => ({ value: a.id, label: a.name })),
value: selectedAgentId || '',
onChange: (val: string) => setSelectedAgentId(val || null),
},
{
id: 'new-chat',
label: 'Neuer Chat',
type: 'button',
onClick: () => setActiveSessionId(null),
},
{ id: 'agent-select', label: 'Agent', type: 'select', options: agents.map((a) => ({ value: a.id, label: a.name })), value: selectedAgentId || '', onChange: (val: string) => setSelectedAgentId(val || null) },
{ id: 'new-chat', label: 'Neuer Chat', type: 'button', onClick: () => { setActiveSessionId(null); setMobileView('list'); } },
]);
return () => unregisterPlugin('ai_assistant');
}, [agents, selectedAgentId, registerItems, unregisterPlugin]);
const handleSelectSession = (id: string) => { setActiveSessionId(id); setMobileView('chat'); };
return (
<div className="flex h-full" data-testid="ai-assistant-page">
{/* Left: Session List with TreeView */}
<div className="w-72 flex-shrink-0 border-r border-secondary-200 bg-white">
<div className="h-16 flex items-center px-6 border-b border-secondary-200">
<h1 className="text-lg font-bold text-secondary-900">KI Assistent</h1>
</div>
<SessionList
activeSessionId={activeSessionId}
onSelectSession={setActiveSessionId}
className="h-[calc(100%-4rem)]"
/>
{/* Desktop: two-pane layout */}
<div className="hidden md:flex w-72 flex-shrink-0 border-r border-secondary-200 bg-white flex-col">
<div className="h-16 flex items-center px-6 border-b border-secondary-200"><h1 className="text-lg font-bold text-secondary-900">KI Assistent</h1></div>
<SessionList activeSessionId={activeSessionId} onSelectSession={setActiveSessionId} className="h-[calc(100%-4rem)]" />
</div>
{/* Right: Chat Window */}
<div className="flex-1 flex flex-col">
{activeSessionId ? (
<ChatWindow sessionId={activeSessionId} agentId={selectedAgentId} className="flex-1" />
) : (
<div className="flex-1 flex items-center justify-center text-secondary-400">
<div className="text-center">
<div className="text-4xl mb-3">🤖</div>
<div className="text-sm">Wähle einen Chat oder erstelle einen neuen</div>
</div>
<div className="hidden md:flex flex-1 flex-col">
{activeSessionId ? <ChatWindow sessionId={activeSessionId} agentId={selectedAgentId} className="flex-1" /> : (
<div className="flex-1 flex items-center justify-center text-secondary-400"><div className="text-center"><div className="text-4xl mb-3">🤖</div><div className="text-sm">Wähle einen Chat oder erstelle einen neuen</div></div></div>
)}
</div>
{/* Mobile: single-pane view switching */}
<div className="flex md:hidden flex-1 flex-col overflow-hidden">
{mobileView === 'list' && (
<div className="flex-1 flex flex-col bg-white">
<div className="h-14 flex items-center px-4 border-b border-secondary-200"><h1 className="text-lg font-bold text-secondary-900">KI Assistent</h1></div>
<SessionList activeSessionId={activeSessionId} onSelectSession={handleSelectSession} className="flex-1" />
</div>
)}
{mobileView === 'chat' && activeSessionId && (
<div className="flex-1 flex flex-col">
<div className="h-14 flex items-center gap-2 px-3 border-b border-secondary-200 bg-white">
<button onClick={() => setMobileView('list')} className="p-2 rounded-lg hover:bg-secondary-100" aria-label="Zurück">
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" /></svg>
</button>
<span className="text-sm font-medium text-secondary-700 truncate">Chat</span>
</div>
<ChatWindow sessionId={activeSessionId} agentId={selectedAgentId} className="flex-1" />
</div>
)}
{mobileView === 'chat' && !activeSessionId && (
<div className="flex-1 flex items-center justify-center text-secondary-400"><div className="text-center"><div className="text-4xl mb-3">🤖</div><div className="text-sm">Wähle einen Chat</div></div></div>
)}
</div>
</div>
);