genui_a2ui 0.6.0 copy "genui_a2ui: ^0.6.0" to clipboard
genui_a2ui: ^0.6.0 copied to clipboard

Integration package for genui and A2UI Streaming UI Protocol.

genui_a2ui #

An integration package for genui and the A2UI Streaming UI Protocol. This package allows Flutter applications to connect to an A2A (Agent-to-Agent) server and render dynamic user interfaces generated by an AI agent using the genui framework.

Features #

  • A2A Server Connection: Establishes and manages a WebSocket connection to any server implementing the A2A protocol.
  • A2UI Message Processing: Receives and parses A2UI messages (like SurfaceUpdate, DataModelUpdate, BeginRendering) from the A2A stream.
  • Dynamic UI Rendering: Integrates seamlessly with genui's GenUiSurface to render UIs based on the received A2UI messages.
  • Content Generator Implementation: Provides A2uiContentGenerator, a specialized ContentGenerator for genui's GenUiConversation to handle the A2A communication flow.
  • Event Handling: Captures UI events from genui and sends them back to the A2A server as A2A messages.
  • Stateful Conversation: Maintains the conversation context (taskId, contextId) with the A2A server.

Getting Started #

Prerequisites #

  • A Flutter project.
  • An A2A server endpoint that implements the A2UI Streaming UI Protocol.

Installation #

Add the following to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  genui: ^0.5.1 # Or the latest version
  genui_a2ui: ^0.5.1 # Or the latest version
  a2a: ^3.1.0 # Or the latest version

Then run flutter pub get.

Basic Usage #

  1. Initialize A2uiMessageProcessor: Set up A2uiMessageProcessor with your widget Catalog.
  2. Create A2uiContentGenerator: Instantiate A2uiContentGenerator, providing the A2A server Uri.
  3. Create GenUiConversation: Pass the A2uiContentGenerator to the GenUiConversation.
  4. Render with GenUiSurface: Use GenUiSurface widgets in your UI to display the agent-generated content.
  5. Send Messages: Use GenUiConversation.sendRequest to send user input to the agent.
import 'package:flutter/material.dart';
import 'package:genui/genui.dart';
import 'package:genui_a2ui/genui_a2ui.dart';
import 'package:logging/logging.dart';

void main() {
  // Setup logging
  Logger.root.level = Level.ALL;
  Logger.root.onRecord.listen((record) {
    print('${record.level.name}: ${record.time}: ${record.message}');
    if (record.error != null) {
      print(record.error);
    }
    if (record.stackTrace != null) {
      print(record.stackTrace);
    }
  });

  runApp(const GenUIExampleApp());
}

class GenUIExampleApp extends StatelessWidget {
  const GenUIExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'A2UI Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const ChatScreen(),
    );
  }
}

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

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

class _ChatScreenState extends State<ChatScreen> {
  final TextEditingController _textController = TextEditingController();
  final A2uiMessageProcessor _a2uiMessageProcessor =
      A2uiMessageProcessor(catalog: CoreCatalogItems.asCatalog());
  late final A2uiContentGenerator _contentGenerator;
  late final GenUiConversation _uiAgent;
  final List<ChatMessage> _messages = [];

  @override
  void initState() {
    super.initState();
    _contentGenerator = A2uiContentGenerator(
      serverUrl: Uri.parse('http://localhost:8080'), // Replace with your A2A server URL
    );
    _uiAgent = GenUiConversation(
      contentGenerator: _contentGenerator,
      a2uiMessageProcessor: _a2uiMessageProcessor,
    );

    // Listen for text responses from the agent
    _contentGenerator.textResponseStream.listen((String text) {
      setState(() {
        _messages.insert(0, AgentMessage.text(text));
      });
    });

    // Listen for errors
    _contentGenerator.errorStream.listen((ContentGeneratorError error) {
      print('Error from ContentGenerator: ${error.error}');
      // Optionally show error to the user
    });
  }

  @override
  void dispose() {
    _textController.dispose();
    _uiAgent.dispose();
    _a2uiMessageProcessor.dispose();
    _contentGenerator.dispose();
    super.dispose();
  }

  void _handleSubmitted(String text) {
    if (text.isEmpty) return;
    _textController.clear();
    final message = UserMessage.text(text);
    setState(() {
      _messages.insert(0, message);
    });
    _uiAgent.sendRequest(message);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('A2UI Example'),
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            child: ListView.builder(
              padding: const EdgeInsets.all(8.0),
              reverse: true,
              itemBuilder: (_, int index) =>
                  _buildMessage(_messages[index]),
              itemCount: _messages.length,
            ),
          ),
          const Divider(height: 1.0),
          Container(
            decoration: BoxDecoration(color: Theme.of(context).cardColor),
            child: _buildTextComposer(),
          ),
          // Surface for the main AI-generated UI
          SizedBox(
              height: 300,
              child: GenUiSurface(
                host: _a2uiMessageProcessor,
                surfaceId: 'main_surface',
              )),
        ],
      ),
    );
  }

  Widget _buildMessage(ChatMessage message) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 10.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Container(
            margin: const EdgeInsets.only(right: 16.0),
            child: CircleAvatar(child: Text(message is UserMessage ? 'U' : 'A')),
          ),
          Expanded(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Text(message is UserMessage ? 'User' : 'Agent',
                    style: const TextStyle(fontWeight: FontWeight.bold)),
                Container(
                  margin: const EdgeInsets.only(top: 5.0),
                  child: Text(message.parts.whereType<TextPart>().map((e) => e.text).join('\n')),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildTextComposer() {
    return IconTheme(
      data: IconThemeData(color: Theme.of(context).colorScheme.secondary),
      child: Container(
        margin: const EdgeInsets.symmetric(horizontal: 8.0),
        child: Row(
          children: <Widget>[
            Flexible(
              child: TextField(
                controller: _textController,
                onSubmitted: _handleSubmitted,
                decoration:
                    const InputDecoration.collapsed(hintText: 'Send a message'),
              ),
            ),
            Container(
              margin: const EdgeInsets.symmetric(horizontal: 4.0),
              child: IconButton(
                  icon: const Icon(Icons.send),
                  onPressed: () => _handleSubmitted(_textController.text)),
            ),
          ],
        ),
      ),
    );
  }
}

Key Components #

  • A2uiContentGenerator: Implements ContentGenerator. Manages the connection to the A2A server and processes incoming A2UI messages, updating the A2uiMessageProcessor.
  • A2uiAgentConnector: Handles the low-level WebSocket communication with the A2A server, including sending messages and parsing stream events.
  • AgentCard: A data class holding metadata about the connected AI agent.

Example App #

See the example/ directory for a more complete application demonstrating the usage of this package.

Further Information #

4
likes
160
points
268
downloads

Publisher

verified publisherlabs.flutter.dev

Weekly Downloads

Integration package for genui and A2UI Streaming UI Protocol.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

a2a, flutter, genui, json_schema_builder, logging, uuid

More

Packages that depend on genui_a2ui