FakeLocalAiHost class

A scriptable LocalAiHost that records what reached it and lets a test push events back the way a real platform would.

Published rather than hidden in this package's own tests: an app built on flutter_local_ai cannot otherwise exercise its AI paths in a unit test, because there is no OS model behind flutter test.

final host = FakeLocalAiHost()..response = 'hello';
debugLocalAiHost = host;
addTearDown(() async {
  debugLocalAiHost = null;
  await host.dispose();
});

expect((await FlutterLocalAi().generateText(prompt: 'hi')).text, 'hello');
expect(host.sessions.single.transcript.toString(), 'hi');

Streaming needs the test to play the platform's part, because nothing generates tokens on its own:

final chunks = <String>[];
final done = session.getResponseAsync().listen(chunks.add).asFuture<void>();
await pumpEventQueue();
host.emitToken(1, 'partial');
host.emitDone(1);
await done;

So does a tool call: the fake plays the model asking for one, through the same registry the native host dispatches with, so a tool loop can be tested without a device.

final result = await host.invokeTool(1, 'weather', {'city': 'Rome'});
expect(result, '{"temp":21}');
expect(host.toolCalls.single.toolName, 'weather');
Implemented types

Constructors

FakeLocalAiHost({LocalAiAvailability availability = LocalAiAvailability.available, LocalAiBackendCapabilities? capabilities})

Properties

availability ↔ LocalAiAvailability
What checkAvailability answers. Mutate mid-test to model a download finishing.
getter/setter pair
calls → List<String>
Method names in call order, for the few assertions that are genuinely about sequencing. Prefer sessions for anything else.
final
capabilities ↔ LocalAiBackendCapabilities
What getBackendInfo answers.
getter/setter pair
closedIds → List<int>
Ids of sessions that were closed, in the order they closed.
final
countTokensError ↔ Object?
Thrown by countTokens when set. Use LocalAiTokenizerUnavailable to model a host with no tokenizer, or any other error to model a broken channel.
getter/setter pair
countTokensResult ↔ int
What countTokens returns, unless countTokensError is set.
getter/setter pair
createSessionError ↔ Object?
Thrown by createSession when set — models a host rejecting tools or an unsupported configuration.
getter/setter pair
events → Stream<LocalAiHostEvent>
Host events for every session, plus download progress. Broadcast: each session filters by its own id.
no setteroverride
hashCode → int
The hash code for this object.
no setterinherited
lastOverrides ↔ LocalAiGenerationOverrides?
The most recent generate call's sampling, across all sessions.
getter/setter pair
modelClosed ↔ bool
Whether closeModel ran.
getter/setter pair
modelSupportsImage ↔ bool?
Whether createModel was asked for image support.
getter/setter pair
reason ↔ String
What availabilityReason answers.
getter/setter pair
response ↔ String
What every non-streaming generate call returns.
getter/setter pair
runtimeType → Type
A representation of the runtime type of the object.
no setterinherited
sessions → List<FakeLocalAiSession>
Every session created, in order, open or closed.
final
toolCalls → List<FakeToolCall>
Every tool call invokeTool played, in order.
final

Methods

addImage({required int sessionId, required Uint8List imageBytes}) → Future<void>
override
addQueryChunk({required int sessionId, required String text}) → Future<void>
override
availabilityReason() → Future<String>
override
checkAvailability() → Future<LocalAiAvailability>
override
closeModel() → Future<void>
override
closeSession(int sessionId) → Future<void>
override
countTokens(String text) → Future<int>
Exact count where the host has a tokenizer; throws LocalAiTokenizerUnavailable where it doesn't, so the caller decides whether to estimate.
override
createModel({required bool supportImage}) → Future<void>
override
createSession({required int sessionId, required double temperature, required int topK, double? topP, int? maxOutputTokens, String? systemInstruction, List<LocalAiTool>? tools}) → Future<void>
override
dispose() → Future<void>
Closes the event stream. Call from a tear-down.
downloadFeature() → Future<void>
override
emit(LocalAiHostEvent event) → void
Pushes a raw event. The typed helpers below cover the usual cases.
emitDone(int sessionId, {String text = ''}) → void
The terminal event for sessionId, optionally carrying a last delta.
emitDownloadProgress(int bytesDownloaded, {int bytesTotal = 0}) → void
Download progress. bytesTotal of 0 models a host that reports no total, which is what Android does.
emitError(int sessionId, String message) → void
A generation failure on sessionId.
emitToken(int sessionId, String text) → void
A delta on sessionId.
generateResponse(int sessionId, {LocalAiGenerationOverrides? overrides}) → Future<String>
override
generateResponseAsync(int sessionId, {LocalAiGenerationOverrides? overrides}) → Future<void>
override
generateStructuredResponse({required int sessionId, required String schemaJson, LocalAiGenerationOverrides? overrides}) → Future<String>
override
getBackendInfo() → Future<LocalAiBackendCapabilities>
override
invokeTool(int sessionId, String toolName, [Map<String, dynamic> arguments = const {}]) → Future<String?>
Plays the model calling toolName on sessionId with arguments, and returns what the native host would hand back to the model: the tool's result as JSON, null when it yielded nothing, or {"error": ...} when the tool body threw.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
openAICorePlayStore() → Future<bool>
override
session(int id) → FakeLocalAiSession?
The session with id, or null when it was never created.
stopGeneration(int sessionId) → Future<void>
override
toString() → String
A string representation of this object.
inherited

Operators

operator ==(Object other) → bool
The equality operator.
inherited

Constants

defaultCapabilities → const LocalAiBackendCapabilities
A capable backend, so a test opts out of a feature rather than having to opt in to all of them.