Example
Agent Chat Interface
A complete agent chat interface built with ASH UI components. Includes message display, tool call visualization, streaming text, and thinking blocks.
Interactive Demo
Click "Run Demo" to see the full agent interaction flow with thinking, tool calls, and streaming response.
Agent Chat
Can you help me create a new React component?
I'd be happy to help you create a React component! What kind of component would you like to build?
I need a button component with loading state
Components Used
Implementation
AgentChat.tsx
import {
MessageList,
ToolCallCard,
StreamingText,
LoadingIndicator,
ThemeProvider,
} from '@ash-cloud/ash-ui';
import type { NormalizedEntry } from '@ash-cloud/ash-ui/types';
import { useState } from 'react';
export function AgentChat() {
const [entries, setEntries] = useState<NormalizedEntry[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [streamingContent, setStreamingContent] = useState<string>();
const sendMessage = async (content: string) => {
// Add user message
setEntries(prev => [...prev, {
id: crypto.randomUUID(),
entryType: 'user_message',
content,
timestamp: new Date().toISOString(),
}]);
setIsLoading(true);
// Connect to SSE endpoint
const response = await fetch('/api/agent/send', {
method: 'POST',
body: JSON.stringify({ message: content }),
});
const reader = response.body?.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader?.read() ?? { done: true };
if (done) break;
const chunk = decoder.decode(value);
const events = chunk.split('\n\n').filter(Boolean);
for (const event of events) {
const data = JSON.parse(event.replace('data: ', ''));
switch (data.type) {
case 'thinking':
setEntries(prev => [...prev, {
id: data.id,
entryType: 'thinking',
content: data.content,
timestamp: new Date().toISOString(),
}]);
break;
case 'tool_call':
setEntries(prev => [...prev, {
id: data.id,
entryType: 'tool_call',
content: '',
toolCall: data.toolCall,
timestamp: new Date().toISOString(),
}]);
break;
case 'text_delta':
setStreamingContent(prev => (prev ?? '') + data.content);
break;
case 'message_complete':
setEntries(prev => [...prev, {
id: data.id,
entryType: 'assistant_message',
content: streamingContent ?? '',
timestamp: new Date().toISOString(),
}]);
setStreamingContent(undefined);
break;
}
}
}
setIsLoading(false);
};
return (
<ThemeProvider defaultTheme="dark">
<div className="flex flex-col h-screen">
<MessageList
entries={entries}
loading={isLoading}
streamingContent={streamingContent}
className="flex-1"
/>
<ChatInput onSend={sendMessage} disabled={isLoading} />
</div>
</ThemeProvider>
);
}