Skip to main content
Learn how to connect your Flutter app to AI Voice Agents and send/receive messages.

Overview

The Flutter SDK provides a simple API to:
  • Connect to AI Voice Agent servers
  • Send messages (text and audio)
  • Receive responses from AI Voice Agents
  • Handle events (connection, messages, errors)

Step 1: Initialize the SDK

Initialize the SDK once in your app (typically in main() or app initialization):
import 'package:kuralit_sdk/kuralit.dart';

void main() {
  runApp(const MyApp());
  
  // Initialize SDK
  Kuralit.init(KuralitConfig(
    serverUrl: 'ws://localhost:8000/ws',  // Your server URL
    apiKey: 'demo-api-key',              // Your API key
    appId: 'my-app',                     // Your app ID
    debug: true,                         // Enable debug logging
  ));
}

Configuration Options

  • serverUrl (required) - WebSocket server URL
  • apiKey (required) - API key for authentication
  • appId (required) - Application identifier
  • debug (optional) - Enable debug logging (default: false)
  • reconnectEnabled (optional) - Auto-reconnect (default: true)
  • maxReconnectAttempts (optional) - Max reconnection attempts (default: 10)
  • reconnectDelayMs (optional) - Reconnection delay (default: 1000ms)
  • heartbeatIntervalMs (optional) - Heartbeat interval (default: 30000ms)

Step 2: Generate Session ID

Each conversation uses a unique session ID:
final sessionId = Kuralit.generateSessionId();

Step 3: Connect to Server

Connect to the WebSocket server:
try {
  await Kuralit.connect();
  print('Connected successfully');
} catch (e) {
  print('Connection failed: $e');
}

Step 4: Listen to Events

Listen to SDK events for real-time updates:
Kuralit.events.listen((event) {
  if (event is KuralitConnectedEvent) {
    // WebSocket connected
    print('Connected to server');
  } else if (event is KuralitDisconnectedEvent) {
    // WebSocket disconnected
    print('Disconnected from server');
  } else if (event is KuralitServerConnectedEvent) {
    // Server confirmed connection
    print('Server connected. Session: ${event.sessionId}');
  } else if (event is KuralitServerTextEvent) {
    // Received final text response
    print('Agent: ${event.text}');
  } else if (event is KuralitServerPartialEvent) {
    // Received streaming/partial response
    print('Agent (streaming): ${event.text}');
  } else if (event is KuralitServerSttEvent) {
    // Received STT transcription
    print('STT: ${event.text}');
  } else if (event is KuralitErrorEvent) {
    // Error occurred
    print('Error: ${event.message}');
  }
});

Step 5: Send Messages

Send Text Message

final sessionId = Kuralit.generateSessionId();
final sent = Kuralit.sendText(sessionId, 'Hello, AI Voice Agent!');

if (sent) {
  print('Message sent');
} else {
  print('Failed to send message');
}

Send Audio (Voice)

// Start audio streaming
Kuralit.startAudio(sessionId);

// Send audio chunks (from microphone)
final audioData = await captureAudioChunk();
Kuralit.sendAudioChunk(sessionId, audioData);

// End audio streaming
Kuralit.endAudio(sessionId);

Complete Example

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:kuralit_sdk/kuralit.dart';

class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key});

  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  final TextEditingController _textController = TextEditingController();
  final List<String> _messages = [];
  bool _isConnected = false;
  String? _sessionId;
  StreamSubscription<KuralitEvent>? _eventSubscription;

  @override
  void initState() {
    super.initState();
    _initializeSDK();
  }

  void _initializeSDK() {
    // Initialize SDK
    Kuralit.init(KuralitConfig(
      serverUrl: 'ws://localhost:8000/ws',
      apiKey: 'demo-api-key',
      appId: 'my-app',
      debug: true,
    ));

    // Generate session ID
    _sessionId = Kuralit.generateSessionId();

    // Listen to events
    _eventSubscription = Kuralit.events.listen((event) {
      if (event is KuralitConnectedEvent) {
        setState(() => _isConnected = true);
      } else if (event is KuralitServerTextEvent) {
        setState(() => _messages.add('Agent: ${event.text}'));
      }
    });

    // Connect
    _connect();
  }

  Future<void> _connect() async {
    try {
      await Kuralit.connect();
    } catch (e) {
      print('Connection failed: $e');
    }
  }

  void _sendMessage() {
    final text = _textController.text.trim();
    if (text.isEmpty || !_isConnected || _sessionId == null) return;

    setState(() {
      _messages.add('You: $text');
      _textController.clear();
    });

    Kuralit.sendText(_sessionId!, text);
  }

  @override
  void dispose() {
    _eventSubscription?.cancel();
    _textController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Chat with AI Voice Agent'),
        actions: [
          Icon(
            _isConnected ? Icons.check_circle : Icons.cancel,
            color: _isConnected ? Colors.green : Colors.red,
          ),
        ],
      ),
      body: Column(
        children: [
          Expanded(
            child: ListView.builder(
              itemCount: _messages.length,
              itemBuilder: (context, index) {
                return ListTile(title: Text(_messages[index]));
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _textController,
                    decoration: const InputDecoration(
                      hintText: 'Type a message...',
                    ),
                    onSubmitted: (_) => _sendMessage(),
                  ),
                ),
                IconButton(
                  icon: const Icon(Icons.send),
                  onPressed: _sendMessage,
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

Event Types

Connection Events

  • KuralitConnectedEvent - WebSocket connected
  • KuralitDisconnectedEvent - WebSocket disconnected
  • KuralitServerConnectedEvent - Server confirmed connection

Message Events

  • KuralitServerTextEvent - Final text response from agent
  • KuralitServerPartialEvent - Streaming/partial text response
  • KuralitServerSttEvent - Speech-to-text transcription

Tool Events

  • KuralitServerToolCallEvent - Agent is calling a tool
  • KuralitServerToolResultEvent - Tool execution result

Error Events

  • KuralitErrorEvent - Error occurred
Learn more about events →

Best Practices

Connection Management

  • Initialize once - Call Kuralit.init() once at app startup
  • Connect when needed - Connect when user opens chat
  • Disconnect when done - Disconnect when user closes chat
  • Handle reconnection - SDK handles automatic reconnection

Session Management

  • One session per conversation - Generate a new session ID for each conversation
  • Reuse session for continuity - Use the same session ID for multi-turn conversations
  • Store session ID - Save session ID if you want to resume conversations

Error Handling

  • Always handle errors - Listen for KuralitErrorEvent
  • Show user feedback - Display error messages to users
  • Retry on failure - SDK handles reconnection automatically

Next Steps