7 files changed
+27
-9
lib/features/chat/data/mcp_client.dart
+2
@@ -1,3 +1,5 @@
1
+// ignore_for_file: prefer_initializing_formals
2
+
3
import 'dart:async';
4
import 'dart:convert';
5
lib/features/chat/data/mcp_server_manager.dart
+2
@@ -1,3 +1,5 @@
1
+// ignore_for_file: prefer_initializing_formals
2
+
3
import 'mcp_client.dart';
4
5
const exampleMcpServerLabel = 'Example MCP';
lib/features/chat/views/chat_screen.dart
+2
-1
@@ -2,6 +2,7 @@ import 'dart:convert';
2
import 'dart:ui';
3
4
import 'package:flutter/material.dart';
5
+import 'package:flutter/rendering.dart';
6
import 'package:flutter/services.dart';
7
import 'package:flutter_riverpod/flutter_riverpod.dart';
8
import 'package:go_router/go_router.dart';
@@ -1388,7 +1389,7 @@ class _MessageList extends StatelessWidget {
1389
1390
return ListView.builder(
1391
controller: scrollController,
1391
- cacheExtent: 1000,
1392
+ scrollCacheExtent: const ScrollCacheExtent.pixels(1000),
1393
padding: EdgeInsets.only(
1394
top: 16,
1395
bottom: 120 + (hasSmartReplies ? 64 : 0) + bottomInset,
lib/features/on_device/data/on_device_gemma_service.dart
+4
-2
@@ -2,6 +2,7 @@ import 'dart:io';
2
3
import 'package:flutter_gemma/flutter_gemma.dart';
4
import 'package:flutter_gemma/core/domain/model_source.dart';
5
+import 'package:flutter_gemma_litertlm/flutter_gemma_litertlm.dart';
6
import 'package:path_provider/path_provider.dart';
7
8
import '../../../core/logger/app_logger.dart';
@@ -20,6 +21,7 @@ class OnDeviceGemmaService {
21
22
static Future<void> initialize({String? huggingFaceToken}) async {
23
await FlutterGemma.initialize(
24
+ inferenceEngines: const [LiteRtLmEngine()],
25
huggingFaceToken: huggingFaceToken,
26
maxDownloadRetries: 10,
27
);
@@ -60,7 +62,7 @@ class OnDeviceGemmaService {
62
final installed = await FlutterGemma.listInstalledModels();
63
final installedSet = installed.toSet();
64
final installedIds = <String>[];
63
-
65
+
66
for (final model in OnDeviceModel.curatedModels) {
67
if (installedSet.contains(model.fileName)) {
68
installedIds.add(model.id);
@@ -118,7 +120,7 @@ class OnDeviceGemmaService {
120
(m) => m.id == modelId,
121
orElse: () => throw Exception('Model not found: $modelId'),
122
);
121
-
123
+
124
final spec = InferenceModelSpec(
125
name: model.fileName,
126
modelSource: ModelSource.network(model.huggingFaceUrl),
pubspec.lock
+8
@@ -470,6 +470,14 @@ packages:
470
url: "https://pub.dev"
471
source: hosted
472
version: "1.0.0"
473
+ flutter_gemma_litertlm:
474
+ dependency: "direct main"
475
+ description:
476
+ name: flutter_gemma_litertlm
477
+ sha256: "6b801403f1f682b699dbf31b485bddba2692296a894b7f23f1c78f171fc62fa3"
478
+ url: "https://pub.dev"
479
+ source: hosted
480
+ version: "1.0.0"
481
flutter_lints:
482
dependency: "direct dev"
483
description:
pubspec.yaml
+5
-3
@@ -16,10 +16,11 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
16
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
17
# In Windows, build-name is used as the major, minor, and patch parts
18
# of the product and file versions while build-number is used as the build suffix.
19
-version: 1.4.0+43
19
+version: 1.4.0+44
20
21
environment:
22
- sdk: ">=3.11.0 <4.0.0"
22
+ sdk: ">=3.12.0 <4.0.0"
23
+ flutter: ">=3.44.0"
24
25
# Dependencies specify other packages that your package needs in order to work.
26
# To automatically upgrade your package dependencies to the latest versions
@@ -59,7 +60,8 @@ dependencies:
60
objectbox: ^5.3.1
61
objectbox_flutter_libs: ^5.3.1
62
path: ^1.9.1
62
- flutter_gemma: 1.0.0
63
+ flutter_gemma: ^1.0.0
64
+ flutter_gemma_litertlm: ^1.0.0
65
wakelock_plus: ^1.2.8
66
flutter_local_notifications: ^22.0.1
67
audioplayers: ^6.4.0
test/features/on_device/on_device_model_catalog_test.dart
+4
-3
@@ -27,13 +27,14 @@ void main() {
27
expect(ids.length, OnDeviceModel.curatedModels.length);
28
});
29
30
- test('uses concrete downloadable bundle urls', () {
30
+ test('uses concrete downloadable LiteRT-LM bundle urls', () {
31
for (final model in OnDeviceModel.curatedModels) {
32
expect(model.huggingFaceUrl, startsWith('https://huggingface.co/'));
33
expect(
34
model.huggingFaceUrl,
35
- anyOf(endsWith('.litertlm'), endsWith('.task')),
36
- reason: '${model.id} must point to a LiteRT model bundle',
35
+ endsWith('.litertlm'),
36
+ reason:
37
+ '${model.id} must stay compatible with flutter_gemma_litertlm',
38
);
39
expect(model.fileName, isNotEmpty);
40
expect(model.fileName, isNot(contains('/')));