Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions packages/genui/lib/genui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export 'src/model/chat_message.dart';
export 'src/model/data_model.dart';
export 'src/model/generation_events.dart';
export 'src/model/ui_models.dart';
export 'src/model/validation_helper.dart';
export 'src/primitives/cancellation.dart';
export 'src/primitives/constants.dart';
export 'src/primitives/logging.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import 'package:json_schema_builder/json_schema_builder.dart';

import '../../model/a2ui_schemas.dart';
import '../../model/catalog_item.dart';
import '../../model/data_model.dart';
import '../../model/ui_models.dart';
import '../../model/validation_helper.dart';
import '../../primitives/logging.dart';
import '../../primitives/simple_items.dart';
import '../../utils/validation_helper.dart';
import '../../widgets/widget_utilities.dart';

final _schema = S.object(
description: 'An interactive button that triggers an action when pressed.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import 'package:json_schema_builder/json_schema_builder.dart';
import '../../model/a2ui_schemas.dart';
import '../../model/catalog_item.dart';
import '../../model/data_model.dart';
import '../../model/validation_helper.dart';
import '../../primitives/simple_items.dart';
import '../../utils/validation_helper.dart';
import '../../widgets/widget_utilities.dart';

final _schema = S.object(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import '../../model/a2ui_schemas.dart';
import '../../model/catalog_item.dart';
import '../../model/data_model.dart';
import '../../model/ui_models.dart';
import '../../model/validation_helper.dart';
import '../../primitives/simple_items.dart';
import '../../utils/validation_helper.dart';
import '../../widgets/widget_utilities.dart';

final _schema = S.object(
Expand Down
7 changes: 4 additions & 3 deletions packages/genui/lib/src/functions/format_string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

import 'package:json_schema_builder/json_schema_builder.dart';
import 'package:meta/meta.dart';
import 'package:rxdart/rxdart.dart';
import 'package:stream_transform/stream_transform.dart';

import '../model/client_function.dart' as cf;
import '../model/data_model.dart';
import '../primitives/logging.dart';
import '../primitives/simple_items.dart';
import '../utils/stream_extensions.dart';

/// Formats a value as a string.
class FormatStringFunction implements cf.ClientFunction {
Expand Down Expand Up @@ -173,7 +174,7 @@ class ExpressionParser {
return Stream<Object?>.value(val);
}).toList();

return CombineLatestStream.list(streams).switchMap((List<Object?> values) {
return streams.combineLatestAll().switchMap((List<Object?> values) {
final Map<String, Object?> combinedArgs = {};
for (var i = 0; i < keys.length; i++) {
combinedArgs[keys[i]] = values[i];
Expand Down Expand Up @@ -249,7 +250,7 @@ class ExpressionParser {
return Stream<Object?>.value(part);
}).toList();

return CombineLatestStream.list(streams).map((List<Object?> values) {
return streams.combineLatestAll().map((List<Object?> values) {
return values.map((e) => e?.toString() ?? '').join('');
});
}
Expand Down
22 changes: 20 additions & 2 deletions packages/genui/lib/src/model/data_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import 'dart:async';
import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';
import 'package:stream_transform/stream_transform.dart';

import '../primitives/logging.dart';
import '../primitives/simple_items.dart';
import '../utils/stream_extensions.dart';
import 'client_function.dart' as cf;

import 'data_path.dart';
Expand Down Expand Up @@ -155,7 +156,7 @@ class DataContext implements cf.ExecutionContext {

final Stream<List<Object?>> combinedStream = streams.isEmpty
? Stream.value([])
: CombineLatestStream.list(streams);
: streams.combineLatestAll();

return combinedStream.switchMap((List<Object?> values) {
final Map<String, Object?> combinedArgs = {};
Expand All @@ -180,6 +181,23 @@ class DataContext implements cf.ExecutionContext {
}
}

/// Resolves a context map definition against a [DataContext].
///
Future<JsonMap> resolveContext(
DataContext dataContext,
JsonMap? contextDefinition,
) async {
final resolved = <String, Object?>{};
if (contextDefinition == null) return resolved;

for (final MapEntry<String, Object?> entry in contextDefinition.entries) {
final String key = entry.key;
final Object? value = entry.value;
resolved[key] = await dataContext.resolve(value).first;
}
return resolved;
}

/// Exception thrown when a value in the [DataModel] is not of the expected
/// type.
class DataModelTypeException implements Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:rxdart/rxdart.dart';

import '../model/data_model.dart';
import '../primitives/simple_items.dart';
import '../widgets/widget_utilities.dart';
import '../utils/stream_extensions.dart';
import 'data_model.dart';

/// A validation error with a message.
class ValidationError {
Expand Down Expand Up @@ -47,7 +45,7 @@ class ValidationHelper {
);
}

return CombineLatestStream.list(streams).map((results) {
return streams.combineLatestAll().map((results) {
for (final (isValid, msg) in results) {
if (!isValid) return msg;
}
Expand Down
19 changes: 19 additions & 0 deletions packages/genui/lib/src/utils/stream_extensions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright 2025 The Flutter Authors.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:stream_transform/stream_transform.dart';

/// Extensions for [Iterable] of [Stream]s.
extension CombineLatestAll<T> on Iterable<Stream<T>> {
/// Combines all streams in this iterable into a single stream that emits a
/// list of the latest values from each stream.
///
/// The resulting stream will not emit until every stream in the iterable has
/// emitted at least one value.
Stream<List<T>> combineLatestAll() {
if (isEmpty) return Stream.value([]);

return first.combineLatestAll(skip(1));
}
}
20 changes: 2 additions & 18 deletions packages/genui/lib/src/widgets/widget_utilities.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import 'package:flutter/material.dart';

import '../model/data_model.dart';
import '../primitives/logging.dart';
import '../primitives/simple_items.dart';

export '../model/data_model.dart' show resolveContext;

/// A builder widget that simplifies handling of nullable `ValueListenable`s.
///
Expand Down Expand Up @@ -376,20 +377,3 @@ class _ToNumberNotifier extends ValueNotifier<num?> {
super.dispose();
}
}

/// Resolves a context map definition against a [DataContext].
///
Future<JsonMap> resolveContext(
DataContext dataContext,
JsonMap? contextDefinition,
) async {
final resolved = <String, Object?>{};
if (contextDefinition == null) return resolved;

for (final MapEntry<String, Object?> entry in contextDefinition.entries) {
final String key = entry.key;
final Object? value = entry.value;
resolved[key] = await dataContext.resolve(value).first;
}
return resolved;
}
2 changes: 1 addition & 1 deletion packages/genui/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dependencies:
json_schema_builder: ^0.1.3
logging: ^1.3.0
meta: ^1.17.0
rxdart: ^0.28.0
stream_transform: ^2.1.1
url_launcher: ^6.3.2
uuid: ^4.4.0

Expand Down
Loading