Appearance
Chat System Architecture
The Gnosari chat system provides real-time, streaming AI conversations with agents and teams. Built on WebSocket technology, it delivers instant responses with live typing indicators and seamless message delivery.
Overview
The chat system powers all conversational interfaces in Gnosari:
- Public chat pages (
/chat/[agent_identifier]) - Agent chat pages (
/gnosaris/[id]/chat) - Team chat pages (
/teams/[id]/chat) - Session continuation (
/sessions/[session_id]/chat) - Embedded widgets (
/embed/agent/[identifier])
Core Features
| Feature | Description |
|---|---|
| Real-time streaming | AI responses appear word-by-word as they're generated |
| WebSocket connection | Persistent connection for instant messaging |
| Message types | User, Assistant, Function Call, Function Result, Reasoning |
| Session persistence | Continue conversations across page reloads |
| Public & authenticated | Works for both logged-in users and anonymous visitors |
| Team routing | Intelligent agent selection for team conversations |
Chat Routes
The system provides multiple entry points for starting conversations:
1. Public Chat (/chat/[agent_identifier])
Chat with any public agent using their identifier:
URL: /chat/customer-support
URL: /chat/sales-assistant
Features:
- No login required for public agents
- Password prompt for protected agents
- Session creation on first message
- Chat interface without the owner conversation sidebar (session-history panel requires authentication)Use Cases:
- Public-facing chatbots on websites
- Customer support bots
- Sales assistants
2. Agent Chat (/chat/agent/[agent_identifier])
Alternative route specifically for agent chats:
URL: /chat/agent/customer-support
Features:
- Same as public chat
- Explicit "agent" route for clarity
- Useful for programmatic navigation3. Authenticated Agent Chat (/gnosaris/[id]/chat)
Chat with any agent (public or private) when logged in:
URL: /gnosaris/123/chat
Features:
- Full authentication required
- Access to private agents
- Session history in sidebar
- New chat buttonUse Cases:
- Internal agent testing
- Private agent conversations
- Multi-session management
4. Team Chat (/teams/[id]/chat)
Chat with entire teams:
URL: /teams/456/chat
Features:
- All team agents available
- Agent sidebar for switching
- Manager/orchestrator routing
- Seamless agent handoffs5. Session Continuation (/sessions/[session_id]/chat)
Continue existing conversations:
URL: /sessions/ui_1704067200000_abc123/chat
Features:
- Load full message history
- Pick up where you left off
- Session metadata visible
- Same interface as new chatsWebSocket Architecture
Real-time messaging is powered by WebSocket connections.
Connection Flow
1. Page loads → Chat component mounts
2. useChatGnosari() initializes
3. WebSocket connects to server
4. Server sends 'connected' event
5. Session created or loaded
6. User sends message
7. Server streams response in real-time
8. Connection maintained until page closesConnection States
| State | Description | User Experience |
|---|---|---|
| Connecting | Initial connection attempt | Loading indicator |
| Connected | Active WebSocket connection | Green status dot, can send messages |
| Disconnected | Connection lost | Red banner, "Reconnect" button |
| Reconnecting | Auto-retry in progress | Yellow spinner, exponential backoff |
WebSocket Events
The system handles these event types:
Incoming Events (Server → Client)
| Event Type | Description | Triggers |
|---|---|---|
text_delta | Streaming text chunk | Update message content in real-time |
agent_completed | Agent finished response | Hide typing indicator, enable input |
tool_call_started | Tool invocation beginning | Show tool activity badge |
tool_call_progress | Tool executing | Update progress indicator |
tool_call_completed | Tool finished | Display result, hide badge |
agent_thinking | Agent processing | Show thinking indicator |
error | Error occurred | Display error message banner |
Outgoing Events (Client → Server)
| Event Type | Description | Payload |
|---|---|---|
user_message | User sent message | { content: string, session_id: string } |
select_agent | Switch agent (teams) | { agent_id: number } |
end_session | Close conversation | { session_id: string } |
Auto-Reconnect Logic
When connection drops:
typescript
Attempt 1: Wait 1 second → Try reconnect
Attempt 2: Wait 2 seconds → Try reconnect
Attempt 3: Wait 4 seconds → Try reconnect
Attempt 4: Wait 8 seconds → Try reconnect
Attempt 5: Wait 16 seconds → Try reconnect
Max wait: 30 seconds between retries
If all fail: Show manual "Reconnect" buttonSession Preservation:
- Messages saved to state during connection loss
- No data lost during reconnect
- Full history restored on successful reconnect
Message Rendering
The chat system displays five types of messages:
1. User Messages
Messages you send to the AI.
Appearance:
- Right-aligned (your side of conversation)
- Teal/emerald gradient background
- White text
- Timestamp when grouped messages change speaker
Example:
[How do I reset my password?]
[10:30 AM]2. Assistant Messages
AI responses.
Appearance:
- Left-aligned (AI side of conversation)
- Indigo/blue gradient background
- Markdown rendering for rich text
- Agent name and avatar
- Timestamp
Features:
- Markdown support: Bold, italics, lists, code blocks, links
- Code syntax highlighting: Language-specific coloring
- Streaming: Text appears word-by-word as generated
- Typing indicator: Shows when AI is composing
Example:
[🤖 Support Bot]
To reset your password:
1. Go to Settings
2. Click "Change Password"
3. Enter new password
4. Click Save
[10:30 AM]3. Function Call Messages
When AI invokes a tool.
Appearance:
- Purple badge with tool icon
- Shows tool name (human-readable)
- Collapsible to show parameters
- Technical details hidden by default
Example:
🔧 Searching Knowledge Base
▼ Show details
Query: "password reset"
Source: "Support Docs"
Max Results: 5Toggle Visibility:
Use the "Tools" toggle in chat header to show/hide function call messages.
4. Function Result Messages
Output from tool executions.
Appearance:
- Gray background
- JSON-formatted data
- Collapsible for long results
- Shows execution time
Example:
📊 Knowledge Base Results
Found 3 relevant documents:
1. "How to Reset Password"
2. "Account Security Guide"
3. "Password Requirements"
Execution time: 245ms5. Reasoning Messages
Agent's internal thinking process (when enabled).
Appearance:
- Light background
- Italic text
- Collapsible section
- Shows step-by-step reasoning
Example:
💭 Agent Thinking
▼ Show reasoning
1. User asks about password reset
2. I should search our knowledge base
3. Tool call: search_knowledge_base
4. Results found, I'll summarize the steps
5. Provide clear, numbered instructionsWhen Enabled:
Reasoning messages appear when:
- Agent has "Advanced Reasoning" capability enabled
- Chat theme has reasoning display enabled
Chat Composables
The system uses specialized Vue composables for different concerns:
Core Composable: useChatGnosari()
Location: ~/composables/features/useChatGnosari.ts
Purpose: Main chat state and WebSocket management
Provides:
| Property | Type | Description |
|---|---|---|
state | Readonly<ChatState> | Reactive chat state (session, messages, agents) |
messages | ComputedRef<ParsedMessage[]> | Parsed message list with metadata |
hasMessages | ComputedRef<boolean> | Whether conversation has started |
canSendMessage | ComputedRef<boolean> | Whether input is enabled |
Actions:
| Method | Parameters | Description |
|---|---|---|
sendMessage() | content: string | Send user message |
selectTeam() | team: Team | Switch to team chat |
selectAgent() | agent: ChatAgent | null | Switch agent in team chat |
loadSession() | sessionId: string | Load existing session |
clearChat() | - | Reset conversation |
manualReconnect() | - | Force WebSocket reconnect |
cleanup() | - | Disconnect and cleanup |
Usage:
vue
<script setup lang="ts">
const chat = useChatGnosari()
// Send message
const handleSendMessage = async (message: string) => {
try {
await chat.sendMessage(message)
} catch (error) {
console.error('Failed to send:', error)
}
}
// Check connection
const isConnected = computed(() => chat.state.isConnected)
// Access messages
const messageList = computed(() => chat.messages.value)
</script>Supporting Composables
useChatActions()
Purpose: User action handlers (copy, share, retry)
Provides:
copyToClipboard(): Copy conversation to clipboardshareConversation(): Generate shareable linkretryLastMessage(): Resend failed messageclearConversation(): Reset with confirmation
useChatInitialization()
Purpose: Initial setup and configuration
Provides:
initializeChat(): Set up WebSocket and sessionloadAgentConfig(): Fetch agent settingsapplyTheme(): Apply chat theme configuration
useChatModals()
Purpose: Modal state management
Provides:
showPasswordModal: Password prompt stateshowWelcomeModal: Welcome modal stateshowContactModal: Contact form stateshowSettingsModal: Settings modal state
useChatSidebar()
Purpose: Global chat sidebar state (for floating widget)
Provides:
isOpen: Sidebar visibilityopen(): Open sidebar with agentclose(): Close sidebartoggle(): Toggle open/close
Public vs Authenticated Chat
The system adapts to different user types:
Public Chat (Anonymous Users)
Features:
- No login required
- Password prompt for protected agents
- Session stored in localStorage
- Limited to public agents only
- Basic chat interface
Limitations:
- Cannot access private agents
- No session history sidebar
- Cannot view past conversations
- Session lost if localStorage cleared
- No owner conversation/session-history sidebar — the
ChatSidebarpanel is hidden for anonymous visitors regardless of agent preset
Authenticated Chat (Logged In)
Features:
- Access to all agents (public & private)
- Full session history
- Session persistence across devices
- Agent management capabilities
- Advanced features (model selection, etc.)
Benefits:
- Sessions saved to account
- Continue on any device
- View full conversation history
- Create and manage agents
Message Parsing
Raw WebSocket events are parsed into structured messages.
ParsedMessage Interface
typescript
interface ParsedMessage {
// Core fields
sessionMessageId: number // Unique message ID
role: 'user' | 'assistant' | 'function_call' | 'function_call_output' | 'reasoning'
displayContent: string // Rendered content
timestamp: Date // When sent
// Optional metadata
agentName?: string // Which agent responded
toolName?: string // Tool invoked (function calls)
toolArguments?: any // Tool parameters
toolResult?: any // Tool output
messageId?: string // WebSocket message ID
callId?: string // Tool call ID
}Message Grouping
Messages are grouped by speaker for visual clarity:
User A: Message 1 ──┐
User A: Message 2 ├─ Grouped (same speaker)
User A: Message 3 ──┘
AI: Response ──── New group (different speaker)Rules:
- Group consecutive messages from same speaker
- Break group when speaker changes
- Show timestamp only on group boundaries
Error Handling
The system gracefully handles errors:
Connection Errors
| Error | Cause | User Experience |
|---|---|---|
| WebSocket failed | Network issue | Red banner, auto-reconnect |
| Authentication failed | Invalid token/password | Password prompt re-appears |
| Session not found | Session deleted | Error message, "New Chat" button |
| Agent unavailable | Agent deleted/disabled | Error banner, cannot send messages |
Message Errors
| Error | Cause | User Experience |
|---|---|---|
| Send failed | Network timeout | Message marked failed, retry button |
| Rate limit | Too many messages | Warning banner, temporary disable |
| Content violation | Filtered content | Error message, prompt to rephrase |
Recovery Actions
For connection errors:
1. Show error banner with description
2. Provide "Reconnect" button
3. Auto-retry with backoff
4. Preserve message queueFor message errors:
1. Mark message as failed
2. Keep message in input (user can edit)
3. Show retry button
4. Log error for debuggingBest Practices
Component Integration
DO:
vue
<script setup lang="ts">
const chat = useChatGnosari()
// Initialize on mount
onMounted(() => {
chat.initialize()
})
// Cleanup on unmount
onUnmounted(() => {
chat.cleanup()
})
</script>DON'T:
vue
<script setup lang="ts">
// ❌ Don't create multiple chat instances
const chat1 = useChatGnosari()
const chat2 = useChatGnosari()
// ❌ Don't forget cleanup
// (no onUnmounted cleanup)
</script>State Management
DO:
vue
<script setup lang="ts">
const chat = useChatGnosari()
// Use computed for derived state
const isEmpty = computed(() => !chat.hasMessages.value)
const canInteract = computed(() =>
chat.state.isConnected && !chat.state.isLoading
)
</script>DON'T:
vue
<script setup lang="ts">
// ❌ Don't mutate state directly
chat.state.messages.push(newMessage)
// ❌ Don't rely on synchronous updates
chat.sendMessage('Hello')
// messages not updated yet!
</script>Error Handling
DO:
vue
<script setup lang="ts">
const handleSend = async (message: string) => {
try {
await chat.sendMessage(message)
} catch (error) {
// Show user-friendly error
toast.add({
title: 'Message failed',
description: 'Please try again',
color: 'error'
})
}
}
</script>Performance Optimization
Message Rendering
Virtual Scrolling: For conversations with 100+ messages Lazy Loading: Load messages in chunks Memo-ization: Cache parsed message objects
WebSocket Optimization
Reconnect Debouncing: Prevent rapid reconnect attempts Message Batching: Group rapid messages when possible State Cleanup: Remove old messages from memory
What's Next?
- Chat Themes: Customize visual appearance and behavior
- Chat Sidebar: Implement global floating chat widget
- Widget Embedding: Embed chat on external websites