Skip to content

Commit dc19744

Browse files
Move Firebase AI logic to a separate package (#290)
1 parent bc91f3b commit dc19744

26 files changed

+232
-168
lines changed

README.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,20 @@ final catalog = CoreCatalogItems.asCatalog().copyWith([
4848
]);
4949
5050
/// Initializing the library.
51-
late final _uiAgent = UiAgent(
52-
'''
51+
final genUiManager = GenUiManager(catalog: catalog);
52+
final aiClient = FirebaseAiClient(
53+
systemInstruction: '''
5354
You are a bicycle maintenance assistant who is an expert in diagnosing issues and
5455
giving step-by-step instructions.
5556
''',
56-
catalog: catalog,
57+
tools: genUiManager.getTools(),
58+
);
59+
late final _uiAgent = UiAgent(
60+
genUiManager: genUiManager,
61+
aiClient: aiClient,
5762
onSurfaceAdded: _onSurfaceAdded,
63+
onSurfaceDeleted: (_) {},
64+
onTextResponse: (_) {},
5865
// ignore: avoid_print
5966
onWarning: (value) => print('Warning from UiAgent: $value'),
6067
);
@@ -107,10 +114,11 @@ Widget build(BuildContext context) {
107114

108115
## Packages
109116

110-
| Package | Description | Version |
111-
| ---------------------------------------------------- | ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
112-
| [flutter_genui](packages/flutter_genui/) | (work in progress) A framework to employ Generative UI. | [![pub package](https://img.shields.io/pub/v/flutter_genui.svg)](https://pub.dev/packages/flutter_genui) |
113-
| [dart_schema_builder](packages/dart_schema_builder/) | (work in progress) A fully featured Dart JSON Schema package with validation. | [![pub package](https://img.shields.io/pub/v/dart_schema_builder.svg)](https://pub.dev/packages/dart_schema_builder) |
117+
| Package | Description |
118+
| ---------------------------------------------------- | ----------------------------------------------------------------------------- |
119+
| [flutter_genui](packages/flutter_genui/) | (work in progress) A framework to employ Generative UI. |
120+
| [flutter_genui_firebase_ai](packages/flutter_genui_firebase_ai/) | (work in progress) Firebase AI integration for flutter_genui. |
121+
| [dart_schema_builder](packages/dart_schema_builder/) | (work in progress) A fully featured Dart JSON Schema package with validation. |
114122

115123
## Usage
116124

examples/simple_chat/lib/main.dart

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'package:flutter/material.dart';
66
import 'package:firebase_core/firebase_core.dart';
77
import 'package:flutter_genui/flutter_genui.dart';
8+
import 'package:flutter_genui_firebase_ai/flutter_genui_firebase_ai.dart';
89
import 'package:simple_chat/message.dart';
910
import 'firebase_options.dart';
1011
import 'package:logging/logging.dart';
@@ -40,22 +41,34 @@ class ChatScreen extends StatefulWidget {
4041
class _ChatScreenState extends State<ChatScreen> {
4142
final TextEditingController _textController = TextEditingController();
4243
final List<MessageController> _messages = [];
43-
// TODO: Demonstrate how to create a GenerativeModel via
44-
// FirebaseAI.googleAI().generativeModel and pass it as a dependency here.
45-
late final UiAgent _uiAgent = UiAgent(
46-
'''
44+
late final GenUiManager _genUiManager;
45+
late final UiAgent _uiAgent;
46+
final ScrollController _scrollController = ScrollController();
47+
48+
@override
49+
void initState() {
50+
super.initState();
51+
const instruction = '''
4752
You are a helpful assistant who chats with user,
4853
giving exactly one response for each user message.
4954
Your responses should contain acknowledgment
5055
of the user message.
51-
''',
52-
catalog: CoreCatalogItems.asCatalog(),
53-
onSurfaceAdded: _handleSurfaceAdded,
54-
onTextResponse: _onTextResponse,
55-
// ignore: avoid_print
56-
onWarning: (value) => print('Warning from UiAgent: $value'),
57-
);
58-
final ScrollController _scrollController = ScrollController();
56+
''';
57+
final catalog = CoreCatalogItems.asCatalog();
58+
_genUiManager = GenUiManager(catalog: catalog);
59+
final aiClient = FirebaseAiClient(
60+
systemInstruction: '$instruction\n\n${GenUiPromptFragments.basicChat}',
61+
tools: _genUiManager.getTools(),
62+
);
63+
_uiAgent = UiAgent(
64+
genUiManager: _genUiManager,
65+
aiClient: aiClient,
66+
onSurfaceAdded: _handleSurfaceAdded,
67+
onTextResponse: _onTextResponse,
68+
// ignore: avoid_print
69+
onWarning: (value) => print('Warning from UiAgent: $value'),
70+
);
71+
}
5972

6073
void _handleSurfaceAdded(SurfaceAdded surface) {
6174
if (!mounted) return;

examples/simple_chat/pubspec.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ dependencies:
1414
sdk: flutter
1515

1616
cupertino_icons: ^1.0.8
17-
firebase_ai: ^3.0.0
1817
firebase_core: ^4.0.0
1918
flutter_genui:
2019
path: ../../packages/flutter_genui
20+
flutter_genui_firebase_ai:
21+
path: ../../packages/flutter_genui_firebase_ai
2122
logging: ^1.3.0
2223

2324
dev_dependencies:

examples/travel_app/lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:firebase_app_check/firebase_app_check.dart';
99
import 'package:firebase_core/firebase_core.dart';
1010
import 'package:flutter/material.dart';
1111
import 'package:flutter_genui/flutter_genui.dart';
12+
import 'package:flutter_genui_firebase_ai/flutter_genui_firebase_ai.dart';
1213
import 'package:logging/logging.dart';
1314

1415
import 'firebase_options.dart';

examples/travel_app/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ dependencies:
1515
dart_schema_builder:
1616
path: ../../packages/dart_schema_builder
1717
file: ^7.0.1
18-
firebase_ai: ^3.0.0
1918
firebase_app_check: ^0.4.0
20-
firebase_auth: ^6.0.0
2119
firebase_core: ^4.0.0
2220
firebase_core_platform_interface: ^6.0.0
2321
flutter:
2422
sdk: flutter
2523
flutter_genui:
2624
path: ../../packages/flutter_genui
25+
flutter_genui_firebase_ai:
26+
path: ../../packages/flutter_genui_firebase_ai
2727
flutter_markdown: ^0.7.1
2828
json_rpc_2: ^4.0.0
2929
logging: ^1.3.0

packages/flutter_genui/README.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,14 @@ A Flutter package for building dynamic, conversational user interfaces powered b
44

55
`flutter_genui` allows you to create applications where the UI is not static or predefined, but is instead constructed by an AI in real-time based on a conversation with the user. This enables highly flexible, context-aware, and interactive user experiences.
66

7+
This package provides the core functionality for GenUI. For a concrete implementation that uses Firebase AI, see the `flutter_genui_firebase_ai` package.
8+
79
## Features
810

911
- **Dynamic UI Generation**: Render Flutter UIs from structured data returned by a generative AI.
1012
- **Simplified Conversation Flow**: A high-level `UiAgent` facade manages the interaction loop with the AI.
1113
- **Customizable Widget Catalog**: Define a "vocabulary" of Flutter widgets that the AI can use to build the interface.
12-
- **Extensible AI Client**: Abstract interface for connecting to different AI model backends. A ready-to-use `GeminiAiClient` for Firebase is included.
14+
- **Extensible AI Client**: Abstract interface for connecting to different AI model backends.
1315
- **Event Handling**: Capture user interactions (button clicks, text input) and send them back to the AI as context for the next turn in the conversation.
1416

1517
## Core Concepts
@@ -20,7 +22,7 @@ The package is built around three main components:
2022

2123
2. **`Catalog`**: A collection of `CatalogItem`s that defines the set of widgets the AI is allowed to use. Each `CatalogItem` specifies a widget's name (for the AI to reference), a data schema for its properties, and a builder function to render the Flutter widget.
2224

23-
3. **`AiClient`**: An interface for communicating with a generative AI model. The package includes `GeminiAiClient` for interacting with Gemini models via the [Firebase AI Logic SDK](https://pub.dev/packages/firebase_ai).
25+
3. **`AiClient`**: An interface for communicating with a generative AI model. For a concrete implementation, see `FirebaseAiClient` in the `flutter_genui_firebase_ai` package.
2426

2527
## Getting Started
2628

@@ -29,6 +31,7 @@ To use `flutter_genui`, you need to initialize a `UiAgent`, provide it with a sy
2931
```dart
3032
import 'package:flutter/material.dart';
3133
import 'package:flutter_genui/flutter_genui.dart';
34+
import 'package:flutter_genui_firebase_ai/flutter_genui_firebase_ai.dart';
3235
3336
void main() {
3437
// Initialize Firebase, etc.
@@ -51,9 +54,14 @@ class _MyAppState extends State<MyApp> {
5154
super.initState();
5255
5356
// 1. Create a UiAgent with a system instruction
57+
final genUiManager = GenUiManager(catalog: CoreCatalogItems.asCatalog());
58+
final aiClient = FirebaseAiClient(
59+
systemInstruction: 'You are a helpful AI assistant that builds UIs.',
60+
tools: genUiManager.getTools(),
61+
);
5462
_uiAgent = UiAgent(
55-
'You are a helpful AI assistant that builds UIs.',
56-
catalog: CoreCatalogItems.asCatalog(),
63+
genUiManager: genUiManager,
64+
aiClient: aiClient,
5765
onSurfaceAdded: _onSurfaceAdded,
5866
);
5967
}

packages/flutter_genui/USAGE.md

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,21 @@ If `flutterfire configure` fails, try one or all of these:
4242

4343
### Employ `flutter_genui`
4444

45-
For a complete example, refer to [main.dart in the minimal_genui example](../../examples/minimal_genui/lib/main.dart). The following steps outline the details of setting up your project to use `flutter_genui`:
45+
For a complete example, refer to [main.dart in the simple_chat example](../../examples/simple_chat/lib/main.dart). The following steps outline the details of setting up your project to use `flutter_genui`:
4646

47-
1. In your `pubspec.yaml` file, add `flutter_genui` to the `dependencies` section with one of the following options:
47+
1. In your `pubspec.yaml` file, add `flutter_genui` and `flutter_genui_firebase_ai` to the `dependencies` section with one of the following options:
4848

4949
- Reference the github project directly:
5050

5151
```yaml
5252
flutter_genui:
53-
git:
54-
url: https://github.com/flutter/genui.git
55-
path: packages/flutter_genui
53+
git:
54+
url: https://github.com/flutter/genui.git
55+
path: packages/flutter_genui
56+
flutter_genui_firebase_ai:
57+
git:
58+
url: https://github.com/flutter/genui.git
59+
path: packages/flutter_genui_firebase_ai
5660
```
5761
5862
- In the future: download from [pub.dev](https://pub.dev)! (We're not ready to publish this as a package until the API is more stable.)
@@ -72,8 +76,14 @@ For a complete example, refer to [main.dart in the minimal_genui example](../../
7276
@override
7377
void initState() {
7478
super.initState();
79+
final genUiManager = GenUiManager(catalog: CoreCatalogItems.asCatalog());
80+
final aiClient = FirebaseAiClient(
81+
systemInstruction: 'You are a helpful AI assistant.',
82+
tools: genUiManager.getTools(),
83+
);
7584
uiAgent = UiAgent(
76-
'You are a helpful AI assistant.',
85+
genUiManager: genUiManager,
86+
aiClient: aiClient,
7787
onSurfaceAdded: _onSurfaceAdded,
7888
);
7989
}

packages/flutter_genui/lib/flutter_genui.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// found in the LICENSE file.
44

55
export 'src/ai_client/ai_client.dart';
6-
export 'src/ai_client/firebase_ai_client.dart';
76
export 'src/catalog/core_widgets/checkbox_group.dart';
87
export 'src/catalog/core_widgets/column.dart';
98
export 'src/catalog/core_widgets/elevated_button.dart';
@@ -15,10 +14,13 @@ export 'src/core/core_catalog.dart';
1514
export 'src/core/genui_configuration.dart';
1615
export 'src/core/genui_manager.dart';
1716
export 'src/core/genui_surface.dart';
17+
export 'src/core/prompt_fragments.dart';
1818
export 'src/core/widgets/chat_primitives.dart';
1919
export 'src/facade/ui_agent.dart';
2020
export 'src/model/catalog.dart';
2121
export 'src/model/catalog_item.dart';
2222
export 'src/model/chat_message.dart';
23+
export 'src/model/tools.dart';
2324
export 'src/model/ui_models.dart';
2425
export 'src/primitives/logging.dart';
26+
export 'src/primitives/simple_items.dart';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2025 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
/// A collection of prompt fragments for use with GenUI.
6+
class GenUiPromptFragments {
7+
/// A basic chat prompt fragment.
8+
static const String basicChat = '''
9+
10+
# Outputting UI information
11+
12+
Use the provided tools to respond to the user using rich UI elements.
13+
14+
Important considerations:
15+
- When you are asking for information from the user, you should always include
16+
at least one submit button of some kind or another submitting element so that
17+
the user can indicate that they are done providing information.
18+
- After you have modified the UI, be sure to use the provideFinalOutput to give
19+
control back to the user so they can respond.
20+
''';
21+
}

packages/flutter_genui/lib/src/facade/ui_agent.dart

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,12 @@ import 'package:dart_schema_builder/dart_schema_builder.dart';
88
import 'package:flutter/foundation.dart';
99

1010
import '../ai_client/ai_client.dart';
11-
import '../ai_client/firebase_ai_client.dart';
12-
import '../core/genui_configuration.dart';
1311
import '../core/genui_manager.dart';
14-
import '../model/catalog.dart';
1512
import '../model/chat_message.dart';
1613
import '../model/ui_models.dart';
1714

1815
const _maxConversationLength = 1000;
1916

20-
const _genuiSystemPromptFragment = '''
21-
22-
# Outputting UI information
23-
24-
Use the provided tools to respond to the user using rich UI elements.
25-
26-
Important considerations:
27-
- When you are asking for information from the user, you should always include
28-
at least one submit button of some kind or another submitting element so that
29-
the user can indicate that they are done providing information.
30-
- After you have modified the UI, be sure to use the provideFinalOutput to give
31-
control back to the user so they can respond.
32-
''';
33-
3417
/// A high-level facade for the GenUI package.
3518
///
3619
/// This class simplifies the process of creating a generative UI by managing
@@ -40,32 +23,17 @@ Important considerations:
4023
class UiAgent {
4124
/// Creates a new [UiAgent].
4225
///
43-
/// The [instruction] is a system prompt that guides the AI's behavior.
44-
///
45-
/// The [catalog] defines the set of widgets available to the AI. If not
46-
/// provided, a default catalog of core widgets is used.
47-
///
4826
/// Callbacks like [onSurfaceAdded] and [onSurfaceDeleted] can be provided to
4927
/// react to UI changes initiated by the AI.
50-
UiAgent(
51-
String instruction, {
52-
required Catalog catalog,
28+
UiAgent({
5329
this.onSurfaceAdded,
5430
this.onSurfaceDeleted,
5531
this.onTextResponse,
5632
this.onWarning,
57-
GenUiConfiguration configuration = const GenUiConfiguration(),
58-
AiClient? aiClient,
59-
}) : _genUiManager = GenUiManager(
60-
catalog: catalog,
61-
configuration: configuration,
62-
) {
63-
_aiClient =
64-
aiClient ??
65-
FirebaseAiClient(
66-
systemInstruction: '$instruction\n\n$_genuiSystemPromptFragment',
67-
tools: _genUiManager.getTools(),
68-
);
33+
required GenUiManager genUiManager,
34+
required AiClient aiClient,
35+
}) : _genUiManager = genUiManager,
36+
_aiClient = aiClient {
6937
_aiClient.activeRequests.addListener(_handleActivityUpdates);
7038
_aiMessageSubscription = _genUiManager.surfaceUpdates.listen(
7139
_handleAiMessage,

0 commit comments

Comments
 (0)