Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
b49f458
-
polina-c Dec 24, 2025
62e769d
-
polina-c Dec 24, 2025
5b70ebc
Update mesage.dart
polina-c Dec 24, 2025
47f4ef5
Update mesage.dart
polina-c Dec 24, 2025
ed024ad
-
polina-c Dec 24, 2025
0f37256
Update genai_primitives.dart
polina-c Dec 24, 2025
918e4d9
Update genai_primitives_test.dart
polina-c Dec 24, 2025
daaa464
-
polina-c Dec 24, 2025
0452bea
-
polina-c Dec 24, 2025
87cc5dd
-
polina-c Dec 24, 2025
724ba2b
-
polina-c Dec 24, 2025
2ea87b5
-
polina-c Dec 24, 2025
5887cc4
-
polina-c Dec 24, 2025
f6af083
-
polina-c Dec 24, 2025
f259308
Update genai_primitives_test.dart
polina-c Dec 24, 2025
5110939
-
polina-c Dec 24, 2025
31e666a
Update message_parts.dart
polina-c Dec 24, 2025
6a245e8
-
polina-c Dec 26, 2025
52eb3a7
Update message_parts.dart
polina-c Dec 26, 2025
af0d06b
ci: add workflow_dispatch to enable manual CI triggers (#633)
andrewkolos Jan 5, 2026
4ebab33
Add A2UI support section to README (#648)
jacobsimionato Jan 5, 2026
0d4e92d
Update dartantic_ai dependency (#649)
gspencergoog Jan 5, 2026
910f4c5
Post publish commit to add sections to CHANGELOGs (#650)
gspencergoog Jan 5, 2026
4bf48a4
[docs] Suggest using `flutter pub add` for adding dependencies (#645)
parlough Jan 6, 2026
9f14e62
Improve error handling for catalog example loading (#653)
nan-yu Jan 6, 2026
c29fca4
-
polina-c Jan 9, 2026
56e12a8
Update message.dart
polina-c Jan 9, 2026
36593a0
---
polina-c Jan 9, 2026
167109f
--
polina-c Jan 9, 2026
dee7e6b
-
polina-c Jan 9, 2026
1eb2b23
-
polina-c Jan 9, 2026
b3c3014
Create custom_part_test.dart
polina-c Jan 9, 2026
aebee60
Update custom_part_test.dart
polina-c Jan 9, 2026
62a421d
-
polina-c Jan 9, 2026
29381ee
[examples] Verdure client cleanup and dependency updates (#646)
parlough Jan 8, 2026
1715110
Document how to get permissions to publish. (#657)
polina-c Jan 12, 2026
f16ca7d
- (#658)
polina-c Jan 13, 2026
1742057
-
polina-c Jan 15, 2026
006181f
-
polina-c Jan 15, 2026
f6814ee
Update genai_primitives_test.dart
polina-c Jan 15, 2026
19e9ad3
-
polina-c Jan 15, 2026
85825a6
-
polina-c Jan 15, 2026
41b1d1c
-
polina-c Jan 15, 2026
bc12115
-
polina-c Jan 15, 2026
551b51c
-
polina-c Jan 15, 2026
57b30c6
-
polina-c Jan 15, 2026
d6f56a0
-
polina-c Jan 15, 2026
5f9d61c
Post publish commit to add sections to CHANGELOGs (#650)
gspencergoog Jan 5, 2026
1bb74ba
Make ContentGeneratorError be an Exception (#660)
gspencergoog Jan 15, 2026
9f90508
Enable stricter dynamic-related analysis (#652)
parlough Jan 15, 2026
4456cec
Move Chat widgets to facade and rename. (#661)
polina-c Jan 15, 2026
f961c42
Reorganize specifications. (#662)
polina-c Jan 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 1 addition & 90 deletions .gemini/GEMINI.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,3 @@
# Gemini Code Assistant Context

This document provides context for the Gemini Code Assistant to understand the `genui` project.

## Project Overview

This is a monorepo for a Generative UI SDK (`genui`). The SDK allows developers to add interactive, dynamic, and graphical UI to their applications, generated by a Large Language Model (LLM). Instead of rendering static text responses from an LLM, this SDK allows the LLM to compose UIs from a developer-provided widget catalog.

The project is structured as a monorepo containing several Dart and Flutter packages, along with example applications.

### Key Packages

| Package | Description |
| ------------------------------------ | ----------------------------------------------------------------------- |
| `packages/genui` | The core framework for employing Generative UI. |
| `packages/genui_a2ui` | Integration with the A2UI Streaming UI Protocol. |
| `packages/genui_firebase_ai` | Firebase AI integration for `genui`. |
| `packages/genui_google_generative_ai`| Integration with Google Cloud Generative Language API. |
| `packages/json_schema_builder` | A Dart JSON Schema package with validation, used by the core framework. |

### Example Applications

The `examples` directory contains sample applications demonstrating the usage of the `genui` SDK.

| Example | Description |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `simple_chat` | A minimal example of a conversational chat application. It demonstrates the fundamental concepts of `genui`, such as initializing the `GenUiConversation`, sending user messages, and rendering the AI-generated UI surfaces using the default core widget catalog. |
| `travel_app` | A more advanced example of a travel planning assistant. It showcases dynamic UI generation, the use of a custom, domain-specific widget catalog, and how user interactions with the UI can be fed back to the AI to refine the conversation. |
| `catalog_gallery` | A simple application that displays the widgets available in the catalog. It's a useful tool for developers to visualize the components that the AI can use to build UIs. |
| `verdure` | A full-stack example (Flutter client + Python server) of a landscape design agent using the A2A protocol. |
| `custom_backend` | Demonstrates how a custom backend can interact with `genui`. |

The `simple_chat` and `travel_app` examples are good starting points for understanding the library's capabilities.

## Implementation Details

For a deeper understanding of the project's architecture and data flow, refer to the following documents:

- **`packages/genui/DESIGN.md`**: Provides a comprehensive overview of the core `genui` package's architecture, purpose, and implementation.

## Building and Running

The project uses standard `flutter` and `dart` commands. A comprehensive script is provided to automate fixes, formatting, analysis, and testing.

### Key Commands

- **Run all checks and tests:**

```bash
./tool/run_all_tests_and_fixes.sh
```

This script wraps the `test_and_fix` Dart tool (`tool/test_and_fix`) to run `dart fix`, `dart format`, `fix_copyright` (in `tool/fix_copyright`), `flutter test`, and `flutter analyze` for all packages and examples in the repository. It is used by developers before comitting code. It takes a while to run, and is not idempotent: it will reformat code and add copyright notices if necessary.

## Development Conventions

### Code Style and Formatting

- The project follows the linting rules in the `analysis_options.yaml` file at the top of the repo.
- Code formatting is enforced using the `dart_format` tool.
- The `tool/run_all_tests_and_fixes.sh` script should be run before committing to ensure all files are correctly formatted and analyzed. Don't run it every time you want to test something, just before you commit, since it does more than just test things, and takes a while.

### Testing

- Widget and unit tests are located in the `test` directory of each package/example.
- Tests are run using `flutter test`.
- The CI pipeline, defined in `.github/workflows/flutter_packages.yaml`, runs tests for all packages on every push and pull request to the `main` branch.

### Copyright Headers

- All files must have a copyright header.
- The `tool/fix_copyright.sh` script (which is called by `run_all_tests_and_fixes.sh`) can be used to automatically add or update copyright headers.

### Firebase Integration

- The examples and the `genui_firebase_ai` package use Firebase.
- A script at `tool/stub_firebase_options.sh` is used in CI to create a stub `firebase_options.dart` file. For local development, developers need to configure their own Firebase project by following the instructions in [`packages/genui/README.md`](packages/genui/README.md#configure-firebase-ai-logic).

## Updating the Guides (`packages/genui/.guides`)

When asked to update the developer guides located in `packages/genui/.guides`, it is critical to ensure the documentation accurately reflects the current state of the codebase. Before making any changes to the guides, you must read *all* the Dart code in the following packages:

- `packages/genui`
- `packages/genui_firebase_ai`
- `packages/genui_google_generative_ai`
- `packages/genui_a2ui`

This ensures that any code examples, API references, and architectural explanations in the guides are up-to-date and consistent with the actual implementation.

## Draft pull requests

Do not review pull requests when they are in draft state. Wait them to be ready for review.
Follow the specifications in `specs/README.md`.
1 change: 0 additions & 1 deletion .gemini/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ The files in this directory are used to customize the behavior of these tools fo

- **`GEMINI.md`**: Provides project-specific context, instructions, and guidelines that are included in the context when using Gemini CLI and Code Assist. This helps the AI understand the project's conventions and requirements.
- **`config.yaml`**: Configuration for the Gemini for GitHub tools, such as settings for code review.
- **`styleguide.md`**: Contains the project's style guide, which is used by the Gemini for Github tools to ensure that generated reviews adhere to the project's conventions.
- **`commands/`**: A directory containing custom command definitions (e.g., `fix_code.toml`) for the Gemini CLI.

## Documentation
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/flutter_packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
name: Flutter GenUI CI

on:
workflow_dispatch:
push:
branches:
- main
Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ graph TD
genui_google_generative_ai --> genui
```

## A2UI Support

The Flutter Gen UI SDK uses the [A2UI protocol](https://a2ui.org) to represent UI content internally. The [genui_a2ui](packages/genui_a2ui/) package allows it to act as a renderer for UIs generated by an A2UI backend agent, similar to the [other A2UI renderers](https://github.com/google/A2UI/tree/main/renderers) which are maintained within the A2UI repository.

The Flutter Gen UI SDK currently supports A2UI v0.8.

## Getting started

See the [genui getting started guide](packages/genui/README.md#getting-started-with-genui).
Expand Down
5 changes: 4 additions & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ analyzer:
language:
strict-casts: true
strict-inference: true
strict-raw-types: true

linter:
rules:
Expand All @@ -28,6 +29,7 @@ linter:

# correctness
- always_declare_return_types
- avoid_annotating_with_dynamic
- avoid_catching_errors
- avoid_dynamic_calls
- comment_references
Expand All @@ -41,4 +43,5 @@ linter:

- omit_obvious_local_variable_types
- specify_nonobvious_local_variable_types
- specify_nonobvious_property_types
- specify_nonobvious_property_types
- strict_top_level_inference
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,15 @@ class BookingService {
}

Future<HotelSearchResult> listHotels(HotelSearch search) async {
// ignore: inference_failure_on_instance_creation
await Future.delayed(const Duration(milliseconds: 100));
await Future<void>.delayed(const Duration(milliseconds: 100));
return listHotelsSync(search);
}

Future<void> bookSelections(
List<String> listingSelectionIds,
String paymentMethodId,
) async {
// ignore: inference_failure_on_instance_creation
await Future.delayed(const Duration(milliseconds: 400));
await Future<void>.delayed(const Duration(milliseconds: 400));
}

/// Synchronous version for example data generation.
Expand Down
8 changes: 4 additions & 4 deletions examples/travel_app/lib/src/widgets/conversation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class Conversation extends StatelessWidget {
case UserMessage():
return userPromptBuilder != null
? userPromptBuilder!(context, message)
: ChatMessageWidget(
: ChatMessageView(
text: message.parts
.whereType<TextPart>()
.map((part) => part.text)
Expand All @@ -63,7 +63,7 @@ class Conversation extends StatelessWidget {
if (text.trim().isEmpty) {
return const SizedBox.shrink();
}
return ChatMessageWidget(
return ChatMessageView(
text: text,
icon: Icons.smart_toy_outlined,
alignment: MainAxisAlignment.start,
Expand All @@ -78,13 +78,13 @@ class Conversation extends StatelessWidget {
),
);
case InternalMessage():
return InternalMessageWidget(content: message.text);
return InternalMessageView(content: message.text);
case UserUiInteractionMessage():
return userUiInteractionBuilder != null
? userUiInteractionBuilder!(context, message)
: const SizedBox.shrink();
case ToolResponseMessage():
return InternalMessageWidget(content: message.results.toString());
return InternalMessageView(content: message.results.toString());
}
},
);
Expand Down
2 changes: 1 addition & 1 deletion examples/verdure/client/lib/features/ai/ai_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class AiClientState {
required this.surfaceUpdateController,
});

/// The A2uiMessageProcessor.
/// The A2UI message processor.
final A2uiMessageProcessor a2uiMessageProcessor;

/// The content generator.
Expand Down
21 changes: 10 additions & 11 deletions examples/verdure/client/lib/features/ai/ai_provider.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class OrderConfirmationScreen extends ConsumerWidget {
error: (error, stackTrace) => Center(child: Text('Error: $error')),
),
bottomNavigationBar: Padding(
padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(16),
child: ElevatedButton(
onPressed: () => context.go('/'),
child: const Text('Back to Start'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ class _QuestionnaireScreenState extends ConsumerState<QuestionnaireScreen> {
@override
Widget build(BuildContext context) {
ref.listen<AsyncValue<AiClientState>>(aiProvider, (previous, next) {
if (next is AsyncData && !_initialRequestSent) {
if (_initialRequestSent) return;
if (next case AsyncData(value: final aiState)) {
setState(() {
_initialRequestSent = true;
});
final AiClientState? aiState = next.value;
aiState?.conversation.sendRequest(
aiState.conversation.sendRequest(
UserMessage.text('USER_SUBMITTED_DETAILS'),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class UploadPhotoScreen extends ConsumerWidget {
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expand All @@ -52,7 +52,9 @@ class UploadPhotoScreen extends ConsumerWidget {
),
const SizedBox(height: 16),
Text(
'''Upload a photo of your front or back yard, and our designers will use it to create a custom vision. Get ready to see the potential.''',
'Upload a photo of your front or back yard, '
'and our designers will use it to create a custom vision. '
'Get ready to see the potential.',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onSurface,
Expand Down Expand Up @@ -146,34 +148,34 @@ class InfoCard extends StatelessWidget {
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16.0),
padding: const EdgeInsets.all(16),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 16,
children: [
CircleAvatar(
maxRadius: 25,
child: Icon(icon, size: 25, color: const Color(0xff15a34a)),
),
if (title != null || subtitle != null) const SizedBox(width: 16),
if (title != null || subtitle != null)
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
children: [
if (title != null)
if (title case final title?)
Text(
title!,
title,
style: Theme.of(context).textTheme.titleMedium!
.copyWith(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.onSurface,
),
),
if (subtitle != null) const SizedBox(height: 4),
if (subtitle != null)
if (subtitle case final subtitle?)
Text(
subtitle!,
subtitle,
style: Theme.of(context).textTheme.bodyMedium!
.copyWith(
color: Theme.of(context).colorScheme.onSurface,
Expand Down
Loading
Loading