Kai Engine Chat UI

Pub Version GitHub

Flutter chat UI widgets designed for Kai Engine. State-management agnostic - works with any state management solution.

Features

  • Ready-to-use chat view with message list and composer
  • Real-time streaming text display
  • Typing indicator during AI generation
  • Customizable message bubbles and theming
  • Message filtering support
  • Responsive design (mobile/desktop bubble widths)
  • Cancel generation support

Getting Started

Add the dependency to your pubspec.yaml:

dependencies:
  kai_engine: ^0.1.1
  kai_engine_chat_ui: ^0.1.1

Or install via command line:

flutter pub add kai_engine kai_engine_chat_ui

Usage

Basic Usage

import 'package:kai_engine/kai_engine.dart';
import 'package:kai_engine_chat_ui/kai_engine_chat_ui.dart';

class ChatScreen extends StatelessWidget {
  final ChatControllerBase controller;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<CoreMessage>>(
      stream: controller.messagesStream,
      builder: (context, messagesSnapshot) {
        return StreamBuilder<GenerationState<GenerationResult>>(
          stream: controller.generationStateStream,
          builder: (context, stateSnapshot) {
            return KaiChatView(
              messages: messagesSnapshot.data ?? [],
              generationState: stateSnapshot.data,
              onSend: (text) => controller.submit(text),
              onCancel: controller.cancel,
            );
          },
        );
      },
    );
  }
}

Customization

Custom Message Builder

KaiChatView(
  messages: messages,
  generationState: generationState,
  onSend: onSend,
  messageBuilder: (context, message) {
    final isUser = message.type == CoreMessageType.user;
    return Container(
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: isUser ? Colors.blue : Colors.grey[200],
        borderRadius: BorderRadius.circular(12),
      ),
      child: Text(message.content),
    );
  },
)

Custom Transient (Streaming) Builder

KaiChatView(
  messages: messages,
  generationState: generationState,
  onSend: onSend,
  transientBuilder: (context, state) {
    return state.maybeWhen(
      streamingText: (text) => Card(
        child: Padding(
          padding: const EdgeInsets.all(12),
          child: Text(text),
        ),
      ),
      loading: (_) => const CircularProgressIndicator(),
      orElse: () => const SizedBox.shrink(),
    );
  },
)

Message Filtering

KaiChatView(
  messages: messages,
  generationState: generationState,
  onSend: onSend,
  // Only show user and AI messages (hide system messages, tool calls, etc.)
  messageFilter: (message) {
    return message.type == CoreMessageType.user ||
           message.type == CoreMessageType.ai;
  },
)

Custom Composer

KaiChatView(
  messages: messages,
  generationState: generationState,
  onSend: onSend,
  composerBuilder: (context, defaultComposer) {
    // Use the default composer with custom wrapper
    return Container(
      decoration: BoxDecoration(
        color: Colors.white,
        boxShadow: [BoxShadow(blurRadius: 4, color: Colors.black12)],
      ),
      child: defaultComposer,
    );
  },
)

Theming

Add KaiChatTheme to your app's theme:

MaterialApp(
  theme: ThemeData(
    extensions: [
      KaiChatTheme(
        maxBubbleWidthMobile: 320,
        maxBubbleWidthDesktop: 480,
        bubbleRadius: 16,
        bubblePadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
        listPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
        itemSpacing: 12,
        userBubbleColor: Colors.blue,
        aiBubbleColor: Colors.grey[200],
        userTextColor: Colors.white,
        aiTextColor: Colors.black87,
      ),
    ],
  ),
  // ...
)

Theme Properties

Property Type Default Description
maxBubbleWidthMobile double 320 Max bubble width on mobile
maxBubbleWidthDesktop double 480 Max bubble width on desktop
bubbleRadius double 16 Border radius of message bubbles
bubblePadding EdgeInsets EdgeInsets.symmetric(horizontal: 12, vertical: 10) Padding inside bubbles
listPadding EdgeInsets EdgeInsets.symmetric(horizontal: 16, vertical: 12) Padding around message list
itemSpacing double 12 Spacing between messages
userBubbleColor Color? theme-based User message bubble color
aiBubbleColor Color? theme-based AI message bubble color
userTextColor Color? theme-based User message text color
aiTextColor Color? theme-based AI message text color

Widgets

KaiChatView

The main chat widget combining message list and composer.

KaiChatView(
  messages: messages,              // Required: List<CoreMessage>
  onSend: (text) async {},         // Required: Send callback
  generationState: state,          // Optional: Current generation state
  onCancel: () {},                 // Optional: Cancel generation callback
  messageFilter: (msg) => true,    // Optional: Filter messages
  messageBuilder: (ctx, msg) => Widget,          // Optional: Custom message UI
  transientBuilder: (ctx, state) => Widget,      // Optional: Custom streaming UI
  onMessageTap: (msg) {},          // Optional: Message tap callback
  reverse: true,                   // Optional: Reverse list order (default: true)
  controller: ScrollController(),  // Optional: Custom scroll controller
  composerPadding: EdgeInsets,     // Optional: Composer padding
  listPadding: EdgeInsets,         // Optional: List padding
  composerBuilder: (ctx, composer) => Widget,    // Optional: Custom composer wrapper
)

KaiComposer

Standalone text input with send/cancel buttons.

KaiComposer(
  onSend: (text) async {},         // Required: Send callback
  onCancel: () {},                 // Optional: Cancel callback
  isGenerating: false,             // Optional: Show cancel instead of send
  hintText: 'Type a message…',     // Optional: Input hint
  controller: TextEditingController(), // Optional: Custom controller
  autofocus: false,                // Optional: Auto-focus input
  maxLines: 6,                     // Optional: Max input lines
  onError: (e, s) {},              // Optional: Error callback
)

License

This project is licensed under the MIT License - see the LICENSE file for details.

Libraries

kai_engine_chat_ui