|
| 1 | +# @badaitech/badai-api-example |
| 2 | + |
| 3 | +A comprehensive example demonstrating how to use the **@badaitech/badai-api** package for building AI-powered chat applications with real-time capabilities. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +The BadAI API provides a powerful GraphQL-based interface for creating conversational AI experiences. This example showcases the complete lifecycle of building a chat application with LLM agents, including authentication, chat room management, real-time messaging, and WebSocket subscriptions. |
| 8 | + |
| 9 | +## Features |
| 10 | + |
| 11 | +### 🔐 **Authentication & Security** |
| 12 | +- **Wallet-based authentication** using Web3 standards (MetaMask/Ethereum signatures) |
| 13 | +- **Session management** with JWT tokens |
| 14 | +- **Secure message signing** using private keys |
| 15 | + |
| 16 | +### 💬 **Chat Engine Capabilities** |
| 17 | +- **Create and manage chat rooms** with multiple participants |
| 18 | +- **Add AI agents** to conversations |
| 19 | +- **Real-time message streaming** with WebSocket subscriptions |
| 20 | +- **Message delta updates** for streaming LLM responses |
| 21 | +- **System and user message differentiation** |
| 22 | + |
| 23 | +### 🤖 **AI Agent Integration** |
| 24 | +- **Deploy custom AI agents** with configurable parameters |
| 25 | +- **Agent marketplace** for discovering and using community agents |
| 26 | +- **Multi-agent conversations** with different roles and purposes |
| 27 | +- **Tool integration** for agents (web search, code execution, etc.) |
| 28 | +- **Token usage tracking** and cost management |
| 29 | + |
| 30 | +### 🔄 **Real-time Features** |
| 31 | +- **WebSocket subscriptions** for live updates |
| 32 | +- **Message events**: created, delta updates, finished |
| 33 | +- **Automatic reconnection** with exponential backoff |
| 34 | +- **Connection health monitoring** with ping/pong |
| 35 | + |
| 36 | +## Installation |
| 37 | + |
| 38 | +```bash |
| 39 | +# Using npm |
| 40 | +npm install @badaitech/badai-api graphql graphql-ws viem |
| 41 | + |
| 42 | +# Using yarn |
| 43 | +yarn add @badaitech/badai-api graphql graphql-ws viem |
| 44 | + |
| 45 | +# Using bun |
| 46 | +bun add @badaitech/badai-api graphql graphql-ws viem |
| 47 | +``` |
| 48 | + |
| 49 | +## Quick Start |
| 50 | + |
| 51 | +### 1. Environment Setup |
| 52 | + |
| 53 | +Create a `.env` file based on `.env.example`: |
| 54 | + |
| 55 | +```env |
| 56 | +REST_API_URL=https://api.badai.io/graphql |
| 57 | +WS_API_URL=wss://api.badai.io/graphql-ws |
| 58 | +AGENT_ID=your-agent-id-here |
| 59 | +``` |
| 60 | + |
| 61 | +### 2. Basic Usage |
| 62 | + |
| 63 | +```typescript |
| 64 | +import { createGraphQLClient, GraphQL } from '@badaitech/badai-api' |
| 65 | +import { createClient } from 'graphql-ws' |
| 66 | +import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts' |
| 67 | + |
| 68 | +// Initialize clients |
| 69 | +const restClient = createGraphQLClient('https://api.badai.io/graphql') |
| 70 | +const wsClient = createClient({ url: 'wss://api.badai.io/graphql-ws' }) |
| 71 | + |
| 72 | +// Generate wallet credentials |
| 73 | +const privateKey = generatePrivateKey() |
| 74 | +const account = privateKeyToAccount(privateKey) |
| 75 | + |
| 76 | +// Authenticate |
| 77 | +const { authMetamaskMessage } = await restClient.request( |
| 78 | + GraphQL.AuthMetamaskMessageDocument, |
| 79 | + { address: account.address } |
| 80 | +) |
| 81 | + |
| 82 | +const signature = await account.signMessage({ message: authMetamaskMessage }) |
| 83 | + |
| 84 | +const { authMetamaskLogin } = await restClient.request( |
| 85 | + GraphQL.AuthMetamaskLoginDocument, |
| 86 | + { |
| 87 | + input: { |
| 88 | + authMessage: authMetamaskMessage, |
| 89 | + sign: signature, |
| 90 | + } |
| 91 | + } |
| 92 | +) |
| 93 | + |
| 94 | +const session = authMetamaskLogin.session |
| 95 | +``` |
| 96 | + |
| 97 | +## Core Concepts |
| 98 | + |
| 99 | +### Authentication Flow |
| 100 | + |
| 101 | +1. **Generate Wallet**: Create or use existing Ethereum wallet |
| 102 | +2. **Request Auth Message**: Get a unique message from the server |
| 103 | +3. **Sign Message**: Sign with private key to prove ownership |
| 104 | +4. **Exchange for Session**: Trade signature for JWT session token |
| 105 | + |
| 106 | +### Chat Room Lifecycle |
| 107 | + |
| 108 | +1. **Create Room**: Initialize with optional AI agents |
| 109 | +2. **Subscribe to Events**: Listen for real-time updates |
| 110 | +3. **Send Messages**: User messages trigger AI responses |
| 111 | +4. **Receive Streams**: Get token-by-token updates from LLMs |
| 112 | +5. **Handle Completion**: Process final responses |
| 113 | + |
| 114 | +### Message Events |
| 115 | + |
| 116 | +- **`SUBSCRIBED`**: Connection established |
| 117 | +- **`MESSAGE_CREATED`**: New message added to chat |
| 118 | +- **`MESSAGE_DELTA_ADD`**: Streaming token from LLM |
| 119 | +- **`MESSAGE_FINISHED`**: Complete response received |
| 120 | +- **`MESSAGE_DELETED`**: Message removed |
| 121 | +- **`MESSAGE_EDITED`**: Message content updated |
| 122 | + |
| 123 | +## API Reference |
| 124 | + |
| 125 | +### Core Types |
| 126 | + |
| 127 | +#### Session Management |
| 128 | +```typescript |
| 129 | +type Session = string // JWT token |
| 130 | +type UserProfile = { |
| 131 | + id: UserID |
| 132 | + email: string |
| 133 | + name: string |
| 134 | + role: UserRole |
| 135 | + tariffCurrent: UserTariff |
| 136 | +} |
| 137 | +``` |
| 138 | +
|
| 139 | +#### Chat Entities |
| 140 | +```typescript |
| 141 | +type ChatRoom = { |
| 142 | + id: ChatID |
| 143 | + name: string |
| 144 | + participants: Participant[] |
| 145 | + created_at: Time |
| 146 | + last_message: Message |
| 147 | +} |
| 148 | + |
| 149 | +type Message = { |
| 150 | + id: MessageID |
| 151 | + text: string |
| 152 | + author: ParticipantID |
| 153 | + chat_id: ChatID |
| 154 | + finished: boolean |
| 155 | + is_system: boolean |
| 156 | + need_answer: boolean |
| 157 | + participant: Participant |
| 158 | + time: Time |
| 159 | + version: number |
| 160 | +} |
| 161 | +``` |
| 162 | +
|
| 163 | +#### Agent Configuration |
| 164 | +```typescript |
| 165 | +type AgentMeta = { |
| 166 | + agent_id: AgentID |
| 167 | + username: string |
| 168 | + first_name: string |
| 169 | + last_name: string |
| 170 | + avatar: string |
| 171 | + role: string |
| 172 | + llm_config: LLMConfig |
| 173 | + template_params: JSON |
| 174 | + can_answer: boolean |
| 175 | + deployment_status: DeploymentStatus |
| 176 | +} |
| 177 | + |
| 178 | +type LLMConfig = { |
| 179 | + model: string // e.g., "gpt-4", "claude-3" |
| 180 | + temperature: number // 0.0 - 2.0 |
| 181 | + max_tokens: number // Maximum response length |
| 182 | +} |
| 183 | +``` |
| 184 | +
|
| 185 | +### Key Operations |
| 186 | +
|
| 187 | +#### Creating a Chat Room |
| 188 | +```typescript |
| 189 | +const { createChatRoom } = await restClient.request( |
| 190 | + GraphQL.CreateChatRoomDocument, |
| 191 | + { |
| 192 | + session, |
| 193 | + agents: [agentId1, agentId2], // Optional AI agents |
| 194 | + } |
| 195 | +) |
| 196 | +``` |
| 197 | + |
| 198 | +#### Subscribing to Messages |
| 199 | +```typescript |
| 200 | +wsClient.subscribe( |
| 201 | + { |
| 202 | + query: print(GraphQL.SubscribeMessagesDocument), |
| 203 | + variables: { |
| 204 | + session, |
| 205 | + chat_id: chatRoomId, |
| 206 | + limitMessages: 100, |
| 207 | + } |
| 208 | + }, |
| 209 | + { |
| 210 | + next: ({ data }) => { |
| 211 | + const event = data.subscribeMessages |
| 212 | + switch (event.event) { |
| 213 | + case GraphQL.Event.MessageDeltaAdd: |
| 214 | + console.log('New token:', event.message.text) |
| 215 | + break |
| 216 | + case GraphQL.Event.MessageFinished: |
| 217 | + console.log('Complete response:', event.message.text) |
| 218 | + break |
| 219 | + } |
| 220 | + } |
| 221 | + } |
| 222 | +) |
| 223 | +``` |
| 224 | + |
| 225 | +#### Sending Messages |
| 226 | +```typescript |
| 227 | +const { sendMessage } = await restClient.request( |
| 228 | + GraphQL.SendMessageDocument, |
| 229 | + { |
| 230 | + session, |
| 231 | + chat_id: chatRoomId, |
| 232 | + message: { |
| 233 | + text: "What's the weather like?", |
| 234 | + finished: true, |
| 235 | + need_answer: true, |
| 236 | + is_system: false, |
| 237 | + } |
| 238 | + } |
| 239 | +) |
| 240 | +``` |
| 241 | + |
| 242 | +## WebSocket Connection Management |
| 243 | + |
| 244 | +The example includes robust WebSocket handling with: |
| 245 | + |
| 246 | +- **Automatic reconnection** with exponential backoff |
| 247 | +- **Connection health monitoring** via ping/pong |
| 248 | +- **Graceful error handling** and recovery |
| 249 | +- **Event-driven architecture** for state management |
| 250 | + |
| 251 | +```typescript |
| 252 | +const wsClient = createClient({ |
| 253 | + url: wsApiUrl, |
| 254 | + retryAttempts: Infinity, |
| 255 | + shouldRetry: () => true, |
| 256 | + retryWait: async (retries) => { |
| 257 | + const delay = Math.min(1000 * 2 ** retries, 10000) |
| 258 | + await new Promise(resolve => setTimeout(resolve, delay)) |
| 259 | + }, |
| 260 | + keepAlive: 10000, // 10 second ping interval |
| 261 | + on: { |
| 262 | + connected: () => console.log('Connected'), |
| 263 | + closed: () => console.log('Disconnected'), |
| 264 | + error: (err) => console.error('Error:', err), |
| 265 | + } |
| 266 | +}) |
| 267 | +``` |
| 268 | + |
| 269 | +## Running the Example |
| 270 | + |
| 271 | +```bash |
| 272 | +# Install dependencies |
| 273 | +bun install |
| 274 | + |
| 275 | +# Set environment variables |
| 276 | +cp .env.example .env |
| 277 | +# Edit .env with your configuration |
| 278 | + |
| 279 | +# Run the example |
| 280 | +bun run src/full-cycle-example.ts |
| 281 | +``` |
| 282 | + |
| 283 | +## Architecture Overview |
| 284 | + |
| 285 | +``` |
| 286 | +┌─────────────────┐ ┌──────────────────┐ |
| 287 | +│ Client App │◄────────┤ @badaitech/ │ |
| 288 | +│ │ │ badai-api │ |
| 289 | +└────────┬────────┘ └────────┬─────────┘ |
| 290 | + │ │ |
| 291 | + │ GraphQL + WebSocket │ |
| 292 | + ▼ ▼ |
| 293 | +┌─────────────────────────────────────────────┐ |
| 294 | +│ BadAI Platform │ |
| 295 | +│ ┌───────────┐ ┌──────────┐ ┌──────────┐ │ |
| 296 | +│ │ Auth │ │ Chat │ │ LLM │ │ |
| 297 | +│ │ Service │ │ Engine │ │ Agents │ │ |
| 298 | +│ └───────────┘ └──────────┘ └──────────┘ │ |
| 299 | +│ │ |
| 300 | +│ ┌───────────────────────────────────────┐ │ |
| 301 | +│ │ Knowledge Base (KDB) │ │ |
| 302 | +│ │ Documents, Q&A, Embeddings, Search │ │ |
| 303 | +│ └───────────────────────────────────────┘ │ |
| 304 | +└─────────────────────────────────────────────┘ |
| 305 | +``` |
| 306 | + |
| 307 | +## Best Practices |
| 308 | + |
| 309 | +1. **Session Management** |
| 310 | + - Store sessions securely |
| 311 | + - Implement token refresh logic |
| 312 | + - Handle session expiration gracefully |
| 313 | + |
| 314 | +2. **Error Handling** |
| 315 | + - Wrap API calls in try-catch blocks |
| 316 | + - Implement retry logic for transient failures |
| 317 | + - Log errors for debugging |
| 318 | + |
| 319 | +3. **Performance Optimization** |
| 320 | + - Use subscriptions for real-time updates |
| 321 | + - Batch operations when possible |
| 322 | + - Implement pagination for large datasets |
| 323 | + |
| 324 | +4. **Security** |
| 325 | + - Never expose private keys |
| 326 | + - Use environment variables for sensitive data |
| 327 | + - Validate all user inputs |
0 commit comments