Skip to content

Conversation

@csells
Copy link

@csells csells commented Dec 9, 2025

Adds genui_dartantic package - a new ContentGenerator implementation that enables GenUI to work with multiple AI providers (OpenAI, Anthropic, Google, Mistral, Cohere, Ollama) via the dartantic_ai package.

Issues fixed

Elements of the package

  • DartanticContentGenerator
  • DartanticContentConverter
  • DartanticSchemaAdapter
  • Simplified Travel Planner Example App
    • including the complete catalog -- should that come from somewhere else?

Pre-launch Checklist

  • I read the [Flutter Style Guide] recently, and have followed its advice.
  • I signed the [CLA].
  • I read the [Contributors Guide].
  • I have added sample code updates to the [changelog].
  • I updated/added relevant documentation (doc comments with ///).

csells added 14 commits December 7, 2025 09:57
… use. Here's a summary:

## Summary

The `genui_dartantic` package and example app are now complete:

### Package Structure
```
packages/genui_dartantic/
├── lib/
│   ├── genui_dartantic.dart              # Public exports
│   └── src/
│       ├── dartantic_content_generator.dart   # Main ContentGenerator
│       ├── dartantic_content_converter.dart   # Message conversion
│       └── dartantic_schema_adapter.dart      # Schema adaptation
├── test/                                 # 44 passing tests
├── example/
│   ├── lib/main.dart                     # Example Flutter app
│   └── pubspec.yaml                      # Dependencies
├── pubspec.yaml
└── README.md
```

### Example App
Located at `packages/genui_dartantic/example/`, it demonstrates:
- Using `DartanticContentGenerator` with `Providers.google`
- Chat interface with surface navigation
- GenUI widget rendering

### Running the Example
```bash
export GOOGLE_API_KEY=your-key-here
cd packages/genui_dartantic/example
flutter run
```

You can also use other providers by changing the code:
- `Providers.openai` (requires `OPENAI_API_KEY`)
- `Providers.anthropic` (requires `ANTHROPIC_API_KEY`)
- `Providers.ollama` (local, no API key required)
…are the most important to fix:

1. **warning** at line 153: Unnecessary type check (always true)
2. **warning** at line 158: Unnecessary null comparison (condition always true)

Most of the info issues are style-related (specifying types for variables, line length, import ordering).

I'm in plan mode, so I can't make edits. Would you like me to:
1. Exit plan mode so I can fix these warnings and info issues?
2. Just leave the warnings as-is since the code works?

The warnings don't affect functionality - the tests all pass - but they indicate code that could be cleaner. The info-level issues are style guidelines that could also be cleaned up.
## Analysis Summary

**Warnings fixed (2):**
- Fixed unnecessary type check at line 153 (`result.output is Map` was always true)
- Fixed unnecessary null comparison at line 158 (`result.output != null` was always true)

**Info-level issues fixed (13):**
- Fixed line lengths exceeding 80 chars
- Fixed import ordering in test file
- Fixed comment references in library doc
- Added type annotations where required
- Removed type annotations where they were obvious

**Remaining (45 info-level):**
All remaining issues are in test files and are style hints (`specify_nonobvious_local_variable_types`) that don't affect code correctness. The warnings are gone and all 44 tests pass.
…ic example:

**Changes made:**

1. **`.vscode/launch.json`** - Added new configuration:
   ```json
   {
     "name": "genui_dartantic_example",
     "cwd": "packages/genui_dartantic/example",
     "request": "launch",
     "type": "dart",
     "args": [
       "--dart-define=GOOGLE_API_KEY=${env:GEMINI_API_KEY}"
     ]
   }
   ```

2. **Example app (`main.dart`)** - Updated to read API key from dart-define:
   - Reads `GOOGLE_API_KEY` from `String.fromEnvironment`
   - Passes it to `GoogleProvider(apiKey: _googleApiKey)`
   - Falls back to environment variable if dart-define is empty (dartantic's default behavior)

To run: Set `GEMINI_API_KEY` in your environment, then select "genui_dartantic_example" from VS Code's Run and Debug menu.
## Summary

I've refactored `DartanticContentGenerator` to be **stateless** and properly integrate with GenUI's conversation history:

### Changes Made

1. **`dartantic_content_converter.dart`** - Added `toHistory()` method:
   - Converts GenUI `ChatMessage` history to dartantic `ChatMessage` list
   - Maps `UserMessage`/`UserUiInteractionMessage` → `ChatMessage.user()`
   - Maps `AiTextMessage`/`AiUiMessage` → `ChatMessage.model()`
   - Prepends system instruction as `ChatMessage.system()` if provided
   - Skips `InternalMessage` and `ToolResponseMessage` (handled internally by dartantic)

2. **`dartantic_content_generator.dart`** - Replaced `Chat` with `Agent`:
   - Removed `_chat` field, now uses `_agent` field
   - Removed `_hasWarnedAboutHistory` flag
   - `sendRequest()` now converts GenUI history via `_converter.toHistory()` and passes it to `_agent.sendFor<T>()`
   - Updated class docstring to document the stateless design

3. **`dartantic_content_converter_test.dart`** - Added 9 new tests for `toHistory()`:
   - Tests for null/empty history
   - Tests for system instruction
   - Tests for each message type conversion
   - Tests for skipping internal/tool messages
   - Tests for full conversation with system instruction

### Results
- All **53 tests** pass
- No analysis issues in source code
- The generator now properly uses the history provided by `GenUiConversation` instead of maintaining its own internal state
## Summary

I've replaced the simple genui_dartantic example with a full travel planner example based on `examples/travel_app/`.

### What was done:

1. **Copied from travel_app:**
   - `lib/src/catalog/` - 12 custom catalog items (travelCarousel, itinerary, inputGroup, etc.)
   - `lib/src/catalog.dart` - catalog definition
   - `lib/src/tools/` - booking service and `ListHotelsTool`
   - `lib/src/widgets/` - `Conversation` widget
   - `lib/src/utils.dart` - utility functions (MarkdownWidget)
   - `assets/travel_images/` and `assets/booking_service/` - images

2. **Created new main.dart:**
   - Uses `DartanticContentGenerator` with `GoogleProvider`
   - Includes the full travel planner system prompt
   - Uses `travelAppCatalog` with all 12 custom catalog items
   - Includes `ListHotelsTool` for hotel search functionality
   - API key passed via `--dart-define=GOOGLE_API_KEY`

3. **Updated pubspec.yaml:**
   - Added `gpt_markdown`, `intl`, `json_schema_builder` dependencies
   - Added asset paths for travel images

4. **Updated .vscode/launch.json:**
   - Renamed launch config to "travel_app (dartantic)"

### Results:
- `dart analyze` shows no issues
- All 53 tests pass
- Web build succeeds
- Ready to run with VS Code launch configuration "travel_app (dartantic)"
…ly, I realize `sendFor` **should** work with tools - the documentation explicitly shows:

```dart
// Typed output + tool calls in one request
final result = await agent.sendFor<Recipe>(
  'Get grandma\'s recipe for cookies',
  outputSchema: recipeSchema,
  outputFromJson: Recipe.fromJson,
  tools: [recipeLookupTool],
);
```

The issue might not be `sendFor` vs `send`, but something else. Let me reconsider:

1. **Tools ARE registered** with the Agent at construction time
2. **sendFor with outputSchema** should still execute tools - dartantic handles tool loops internally
3. The `return_result` pseudo-tool is added **in addition to** existing tools, not replacing them

I may have misdiagnosed the problem. Let me investigate further - the actual issue could be:
- The system instruction isn't being passed correctly
- The tools aren't being converted properly to dartantic format
- Google's native `responseSchema` mode conflicts with tool calling (provider-specific)
- Something else in the tool execution loop

Should I explore deeper to find the real root cause rather than making this change?
## Summary

**Root cause**: The example prompt told the model to "call the provideFinalOutput tool" but dartantic_ai doesn't have that tool - it handles typed output internally via `return_result`.

**Changes made**:

1. **`packages/genui_dartantic/lib/src/dartantic_content_generator.dart`**:
   - Restored `json_schema` import
   - Restored `_outputSchema` static field
   - Kept using `sendFor` with `outputSchema` (typed output works correctly with dartantic)

2. **`packages/genui_dartantic/example/lib/main.dart`**:
   - Removed the reference to `provideFinalOutput` tool from the prompt (line 388)
   - Changed "conversation turn is complete, and you should call the provideFinalOutput tool." to "conversation turn is complete."

**Results**:
- All 53 tests pass
- Web build succeeds
- The model should now properly call the GenUI tools (surfaceUpdate, beginRendering) and dartantic will handle the typed output automatically
**Changes made to `packages/genui_dartantic/example/lib/main.dart`:**

1. **Added tabs structure** - `DefaultTabController` with 2 tabs ("Travel" and "Widget Catalog")
2. **Added proper AppBar** - menu icon, airplane icon + centered title, person icon, TabBar at bottom
3. **Added `CatalogTab` widget** - displays `DebugCatalogView` with `travelAppCatalog`
4. **Updated title** - "Agentic Travel Inc (Dartantic)" to distinguish from the original
5. **Removed `provideFinalOutput` reference** from the prompt (dartantic uses `return_result` internally)

The app structure now matches the working `examples/travel_app/`:
- Tab 1: "Travel" → `TravelPlannerPage` with the AI chat interface
- Tab 2: "Widget Catalog" → `CatalogTab` showing all available catalog items in `DebugCatalogView`

The build succeeded. You can now run the app with VS Code launch config "travel_app (dartantic)" or:
```bash
cd packages/genui_dartantic/example && flutter run --dart-define=GEMINI_API_KEY=$GEMINI_API_KEY
```
## Summary

**Files created:**
- `packages/genui_dartantic/example/lib/src/asset_images.dart` - identical to travel_app
- `packages/genui_dartantic/example/lib/src/travel_planner_page.dart` - adapted from travel_app

**Files modified:**
- `packages/genui_dartantic/example/lib/main.dart` - reduced from 646 lines to 117 lines

**Key differences between travel_app and dartantic example:**

| File | Difference |
|------|------------|
| `main.dart` | No Firebase init, teal color, "(Dartantic)" in title, const actions |
| `travel_planner_page.dart` | Uses `DartanticContentGenerator` + `dartantic.GoogleProvider`, no AiBackend switch, prompt says "conversation turn is complete" instead of "call provideFinalOutput" |
| `asset_images.dart` | Identical |

The dartantic example now has the same modular structure as travel_app, with the only meaningful differences being the content generator and prompt - exactly as you requested.
- Updated `DartanticContentConverter` to include a new method `toPromptAndParts` that converts GenUI messages into a prompt string along with associated parts for better handling of multimodal content.
- Adjusted `DartanticContentGenerator` to utilize the new conversion method, ensuring that both text and tool content are preserved in requests.
- Modified tests to validate the new functionality, ensuring proper conversion and handling of various message types, including tool calls and results.
- Cleaned up code and comments for clarity and consistency.
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the genui_dartantic package, which is a significant and well-executed addition. It integrates genui with dartantic_ai to enable support for multiple AI providers, and includes a comprehensive example app to demonstrate its capabilities. The code is well-structured, documented, and tested. My review focuses on improving code robustness, type safety, and fixing a few minor issues in the example application to further enhance its quality.

csells and others added 9 commits December 8, 2025 22:56
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…ip.dart

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…el.dart

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
…er.dart

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@parlough
Copy link
Member

parlough commented Dec 9, 2025

Exciting @csells! :D

I'm not familiar with the setup here, but should this be separate from this repo so we can point to it as an exemplary example of a community-maintained provider/generator?

@csells
Copy link
Author

csells commented Dec 9, 2025

Seth and Greg asked for a PR but making this an external repo works for me, too.

@sethladd
Copy link
Collaborator

sethladd commented Dec 9, 2025

thanks @csells ! I think it's OK to keep in this repo now. We might split it out later, once APIs stabilize.

@parlough
Copy link
Member

parlough commented Dec 9, 2025

Keeping it here sounds good to me! Thanks for clarifying :)

@gspencergoog
Copy link
Collaborator

/gemini summary

@gemini-code-assist
Copy link
Contributor

Summary of Changes

This pull request significantly enhances GenUI by introducing the genui_dartantic package, which integrates with dartantic_ai to provide support for a wide array of AI providers. This integration allows for more flexible and powerful dynamic UI generation. The PR also includes a comprehensive example application, the Travel Planner, to illustrate the practical application of these new capabilities, alongside various utility components and tools to facilitate the development of AI-driven user interfaces.

Highlights

  • New genui_dartantic Package: Introduces a new package, genui_dartantic, which provides a ContentGenerator implementation for GenUI, enabling integration with various AI providers.
  • Multi-AI Provider Support: Leverages the dartantic_ai package to support multiple AI providers including OpenAI, Anthropic, Google, Mistral, Cohere, and Ollama, expanding GenUI's generative capabilities.
  • Core Components: Includes key components like DartanticContentGenerator for content generation, DartanticContentConverter for message type conversion, and DartanticSchemaAdapter for schema adaptation.
  • Travel Planner Example App: Adds a simplified Travel Planner Example App to demonstrate the new package's functionality, showcasing dynamic UI generation for travel planning scenarios.
  • Issue Fixed: Addresses and fixes issue Dartantic ContentGenerator for the GenUI package #570, improving the overall functionality or addressing a known bug within the GenUI system.
Changelog
  • .gitignore
    • Added .vscode/settings.json to the ignore list.
  • .vscode/launch.json
    • Added GEMINI_API_KEY dart-define argument to the travel_app launch configuration.
    • Added a new travel_app (dartantic) launch configuration for the example app.
  • packages/genui_dartantic/README.md
    • New README detailing features, getting started, supported providers, API keys, and configuration for the genui_dartantic package.
  • packages/genui_dartantic/example/.gitignore
    • Added a new .gitignore file for the example application.
  • packages/genui_dartantic/example/analysis_options.yaml
    • Added a new analysis_options.yaml file for the example application.
  • packages/genui_dartantic/example/assets/booking_service/README.md
    • Added a new README for hotel image generation prompts used in the example.
  • packages/genui_dartantic/example/assets/prompt_images/README.md
    • Added a new README for prompt images, clarifying they are not included in pubspec.yaml assets.
  • packages/genui_dartantic/example/assets/travel_images/_images.json
    • Added a JSON file listing travel images and their descriptions for use in the example app.
  • packages/genui_dartantic/example/lib/main.dart
    • Added the main entry point for the example travel app, including logging setup and basic UI structure.
  • packages/genui_dartantic/example/lib/src/asset_images.dart
    • Added utility to load and process asset image catalog JSON, prepending asset paths to image file names.
  • packages/genui_dartantic/example/lib/src/catalog.dart
    • Defined the travelAppCatalog with a curated collection of UI components for the travel app, including custom widgets and a subset of core GenUI widgets.
  • packages/genui_dartantic/example/lib/src/catalog/checkbox_filter_chips_input.dart
    • Added a new CheckboxFilterChipsInput widget for selecting multiple options from a predefined list, typically used within an InputGroup.
  • packages/genui_dartantic/example/lib/src/catalog/common.dart
    • Added TravelIcon enum and iconFor utility function for consistent icon usage across travel-related widgets.
  • packages/genui_dartantic/example/lib/src/catalog/date_input_chip.dart
    • Added a new DateInputChip widget for interactive date selection, typically used within an InputGroup.
  • packages/genui_dartantic/example/lib/src/catalog/information_card.dart
    • Added a new InformationCard widget for displaying detailed information with an optional image, title, subtitle, and markdown-supported body.
  • packages/genui_dartantic/example/lib/src/catalog/input_group.dart
    • Added a new InputGroup widget to visually group input chips and provide a single submit button for user actions.
  • packages/genui_dartantic/example/lib/src/catalog/itinerary.dart
    • Added a new Itinerary widget for displaying travel plans, including nested ItineraryDay and ItineraryEntry components with booking status and actions.
  • packages/genui_dartantic/example/lib/src/catalog/listings_booker.dart
    • Added a new ListingsBooker widget for selecting and booking listings, including payment method selection and booking status.
  • packages/genui_dartantic/example/lib/src/catalog/options_filter_chip_input.dart
    • Added a new OptionsFilterChipInput widget for selecting a single option from a predefined list, typically used within an InputGroup.
  • packages/genui_dartantic/example/lib/src/catalog/tabbed_sections.dart
    • Added a new TabbedSections widget for organizing content into a series of tabs, each with a title and child widget.
  • packages/genui_dartantic/example/lib/src/catalog/text_input_chip.dart
    • Added a new TextInputChip widget for free text input, with support for obscured text, typically used within an InputGroup.
  • packages/genui_dartantic/example/lib/src/catalog/trailhead.dart
    • Added a new Trailhead widget for presenting suggested topics or follow-up questions as interactive chips.
  • packages/genui_dartantic/example/lib/src/tools/booking/booking_service.dart
    • Added a fake BookingService for simulating hotel listings and bookings in the example app.
  • packages/genui_dartantic/example/lib/src/tools/booking/list_hotels_tool.dart
    • Added a ListHotelsTool for integrating hotel listing functionality with the AI, allowing the AI to search for hotels.
  • packages/genui_dartantic/example/lib/src/tools/booking/model.dart
    • Defined data models for HotelSearchResult, Listing, HotelListing, and HotelSearch used by the booking service.
  • packages/genui_dartantic/example/lib/src/travel_planner_page.dart
    • Added the TravelPlannerView which integrates GenUI with Dartantic AI for a travel planning chat interface, including API key handling and conversation management.
  • packages/genui_dartantic/example/lib/src/utils.dart
    • Added a MarkdownWidget for rendering markdown text within the example application.
  • packages/genui_dartantic/example/lib/src/widgets/conversation.dart
    • Added a Conversation widget to display chat messages and GenUI surfaces, handling different message types.
  • packages/genui_dartantic/example/lib/src/widgets/dismiss_notification.dart
    • Added a DismissNotification for indicating a request to dismiss a modal or similar UI element.
  • packages/genui_dartantic/example/pubspec.yaml
    • Added pubspec.yaml for the example app, including dependencies on dartantic_ai, genui, genui_dartantic, gpt_markdown, intl, json_schema_builder, and logging.
  • packages/genui_dartantic/example/web/index.html
    • Added index.html for the example web application.
  • packages/genui_dartantic/example/web/manifest.json
    • Added manifest.json for the example web application.
  • packages/genui_dartantic/lib/genui_dartantic.dart
    • New library export file for the genui_dartantic package, exposing its core components.
  • packages/genui_dartantic/lib/src/dartantic_content_converter.dart
    • Added DartanticContentConverter for converting GenUI ChatMessage types to dartantic_ai compatible prompt strings and parts, handling various message and tool result types.
  • packages/genui_dartantic/lib/src/dartantic_content_generator.dart
    • Added DartanticContentGenerator which implements GenUI's ContentGenerator interface using dartantic_ai, supporting tool calling and structured output.
  • packages/genui_dartantic/lib/src/dartantic_schema_adapter.dart
    • Added DartanticSchemaAdapter for converting json_schema_builder schemas to json_schema format, with error handling for unsupported keywords.
  • packages/genui_dartantic/pubspec.yaml
    • Added pubspec.yaml for the genui_dartantic package, including dependencies on dartantic_ai, dartantic_interface, flutter, genui, json_schema, and json_schema_builder.
  • packages/genui_dartantic/test/dartantic_content_converter_test.dart
    • Added unit tests for DartanticContentConverter to ensure correct message and part conversion.
  • packages/genui_dartantic/test/dartantic_content_generator_test.dart
    • Added unit tests for DartanticContentGenerator focusing on construction, streams, and configuration.
  • packages/genui_dartantic/test/dartantic_schema_adapter_test.dart
    • Added unit tests for DartanticSchemaAdapter to verify schema adaptation and error handling.
  • packages/genui_google_generative_ai/README.md
    • Updated the README to clarify the recommended environment variable for the API key to GEMINI_API_KEY.
  • pubspec.lock
    • Updated various package dependencies, including anthropic_sdk_dart, csslib, dartantic_ai, dartantic_interface, html, json_schema, mistralai_dart, ollama_dart, openai_core, openai_dart, quiver, rfc_6901, and uri.
  • pubspec.yaml
    • Added packages/genui_dartantic and packages/genui_dartantic/example to the workspace definition.
Activity
  • parlough inquired if the new package should be maintained externally as an exemplary community-maintained provider/generator.
  • csells, the author, expressed openness to making the package external if preferred.
  • sethladd suggested keeping the package within the current repository for now, with a potential split later once APIs stabilize.
  • parlough agreed with the decision to keep the package in the current repository.
  • gspencergoog requested a summary of the pull request.
  • gemini-code-assist[bot] recommended refactoring assetImageCatalogJson to use JSON parsing and re-serialization for robustness, rather than string replacement.
  • gemini-code-assist[bot] suggested improving the label consistency in _DateInputChip when widget.label is null.
  • gemini-code-assist[bot] advised creating an _ActionData extension type to enhance type safety and readability when accessing action data in itinerary.dart, listings_booker.dart, trailhead.dart, and input_group.dart.
  • csells requested a suggestion for the _ActionData extension type.
  • gemini-code-assist[bot] provided a detailed suggestion for the _ActionData extension type.
  • gemini-code-assist[bot] reiterated the suggestion for the _ActionData extension type.
  • gemini-code-assist[bot] recommended simplifying the _CustomRadio widget from a StatefulWidget to a StatelessWidget as it doesn't manage internal state.
  • csells requested a suggestion for refactoring _CustomRadio.
  • gemini-code-assist[bot] provided the suggested code for refactoring _CustomRadio to a StatelessWidget.
  • gemini-code-assist[bot] pointed out that listingSelectionId values in _hotelExample were hardcoded and suggested using dynamic values from hotel1 and hotel2 objects.
  • gemini-code-assist[bot] recommended defining _geminiApiKey as a static final field for efficiency, as its value from String.fromEnvironment is constant.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it makes sense to duplicate the entire travel_app example here. It would probably make more sense to have a separate, simpler, example for dartantic. Something that doesn't require lots of assets, with less code to maintain would be ideal. The idea isn't to have an example of GenUI (that's what the top level examples are for), but rather to have an example of what is different about using Dartantic from the other content generators.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants