flutter_agentic β Flutter AI Agent SDK
The Flutter AI agent SDK β build tool-calling AI agents, multi-step LLM pipelines, and on-device / cloud hybrid apps in Flutter.
flutter_agentic gives Flutter developers a single, clean API across 7 AI providers β Gemini, OpenAI, Anthropic, HuggingFace, Ollama, on-device Gemma, and GGUF (llama.cpp). ReAct reasoning loop, per-call routing, observable multi-step flows, persistent memory, and a full safety layer β all Flutter-first, no backend required.
π View on pub.dev Β· GitHub Β· PLATFORM_SETUP.md
Why use this Flutter AI SDK?
- One API, every provider β swap Gemini for Ollama for on-device Gemma with one line
- True ReAct agent loop β the agent reasons, calls tools, observes results, and repeats
- Per-call routing β
PolicyRouterroutes each request cloud/on-device by your rules - Multi-step flows β
AgenticFlowchains LLM calls into named, observable pipelines - Production-ready safety β PII redaction, rate limiting, input/output guards built-in
- Full offline support β run Gemma or any GGUF model entirely on-device, no internet
Features
| Feature | Description |
|---|---|
| π§ ReAct agent loop | Reasons β calls tools β observes β repeats until done |
| π 7 AI providers | Gemini, OpenAI, Anthropic, HuggingFace (cloud), Ollama (local server), on-device Gemma, on-device GGUF (llama.cpp) |
| π§ Per-call routing | PolicyRouter β route each call cloud/on-device by your own rules (NEW in 0.2.0) |
| π AI flows | AgenticFlow β chain multi-step AI pipelines with named, observable steps (NEW in 0.2.0) |
| π οΈ Built-in tools | Calculator, date/time, HTTP fetch, mock weather β zero config |
| π§ Custom tools | Type-safe AgenticTool.define() with auto JSON Schema |
| πΎ Persistent memory | HiveMemoryStore β history survives app restarts |
| π Smart retry | Exponential backoff on 429 / 5xx with RetryProvider |
| π¦ Safety layer | Input guard, PII redaction, rate limiter, concurrency limiter |
| πΊοΈ Model registry | Pre-configured context windows & costs for 20+ models |
| π‘ Streaming | Token-by-token streaming for all cloud providers |
| π Web safe | Cloud providers work on web; on-device excluded automatically |
Installation
dependencies:
flutter_agentic: ^1.0.0
Or directly from source:
dependencies:
flutter_agentic:
git:
url: https://github.com/Devanshv17/flutter_agentic
Quick start β Flutter AI agent in 10 lines
import 'package:flutter_agentic/flutter_agentic.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AgenticAI.init(
providers: {
'gemini': GeminiProvider(apiKey: 'YOUR_GEMINI_API_KEY'),
},
defaultProviderKey: 'gemini',
);
final agent = AgenticAgent(
provider: AgenticAI.defaultProvider,
systemPrompt: 'You are a helpful Flutter AI assistant.',
tools: AgenticTools.all, // calculator + dateTime + httpRequest + mockWeather
);
final response = await agent.chat('What is 1337 * 42?');
print(response.text); // β "The answer is 56154."
}
AI Providers
Gemini (Google)
GeminiProvider(
apiKey: 'YOUR_KEY',
model: 'gemini-2.0-flash', // default
)
Get a free key at aistudio.google.com.
OpenAI
OpenAIProvider(
apiKey: 'YOUR_KEY',
model: 'gpt-4o-mini', // default
)
Anthropic (Claude)
AnthropicProvider(
apiKey: 'YOUR_KEY',
model: 'claude-haiku-4-5', // default β fast & cheap
)
Ollama (local server β desktop / LAN)
OllamaProvider(model: 'llama3.2') // localhost:11434
final status = await OllamaProvider(model: 'phi4').checkStatus();
if (!status.isReady) print(status.reason);
- Install: ollama.ai
- Pull:
ollama pull llama3.2 - Ollama starts automatically β no extra config needed.
On-device Gemma (Android / iOS / macOS / Windows)
import 'package:flutter_agentic/src/providers/gemma_provider.dart';
final path = '/data/user/0/com.example.app/files/gemma-3n.task';
if (await GemmaModelManager.isDownloaded(path)) {
final provider = GemmaProvider(
modelId: 'gemma-3n-e2b-it',
modelPath: path,
supportImage: true,
);
}
final url = GemmaModelManager.downloadUrl('gemma-3n-e2b-it');
final sizeMb = GemmaModelManager.approximateSizeMb('gemma-3n-e2b-it'); // 1100
Supported model IDs: gemma-3n-e2b-it, gemma-3n-e4b-it, gemma-3-1b-it,
function-gemma-270m, phi-4-mini, qwen3-0.6b, smollm-135m.
GemmaProviderusesdart:ffiβ import it directly and guard withif (!kIsWeb).
HuggingFace Inference (cloud β any HF model, no download)
final provider = HFInferenceProvider(
modelId: 'Qwen/Qwen2.5-0.5B-Instruct',
apiToken: 'hf_xxxx', // free at huggingface.co/settings/tokens
);
final agent = AgenticHub.fromHFCloud(
modelId: 'Qwen/Qwen2.5-0.5B-Instruct',
apiToken: 'hf_xxxx',
systemPrompt: 'You are a helpful assistant.',
);
| Backend | Best for |
|---|---|
featherless (default) |
Virtually all public HF models |
nebius |
Large / quantised models |
together |
Llama, Mixtral, popular OSS |
sambanova |
Very fast Llama inference |
hfNative |
HF's own GPU fleet |
On-device GGUF / llama.cpp (Android / macOS / Windows / Linux)
import 'package:flutter_agentic/src/providers/llama_cpp_provider.dart';
final provider = LlamaCppProvider(
modelPath: '/path/to/model.gguf',
nCtx: 2048,
nThreads: 4,
);
// Or auto-detect via AgenticHub:
final agent = await AgenticHub.fromFile('/path/to/model.gguf');
final reply = await agent.chat('What is the capital of France?');
final modelsDir = await AgenticHub.platformModelsDir();
// Android: /data/user/0/com.example.app/files/genesis_models
// iOS/macOS: <NSApplicationSupport>/genesis_models
// Windows/Linux: <ApplicationSupport>/genesis_models
LlamaCppProviderrequiresdart:ffi. Import it directly. GGUF on iOS needsllama.cppas an xcframework β seePLATFORM_SETUP.md.
Custom tools
final weatherTool = AgenticTool.define(
name: 'get_weather',
description: 'Returns current weather for a city.',
params: [
ToolParam.string('city', 'City name, e.g. "Mumbai"'),
ToolParam.stringEnum('unit', 'Temperature unit', ['celsius', 'fahrenheit']),
],
execute: (args) async {
final city = args['city'] as String;
final unit = args['unit'] as String? ?? 'celsius';
return (await fetchWeather(city, unit)).toJson();
},
);
final agent = AgenticAgent(
provider: myProvider,
tools: [weatherTool, AgenticTools.calculator],
);
ToolParam types
| Constructor | JSON Schema type |
|---|---|
ToolParam.string(name, desc) |
string |
ToolParam.number(name, desc) |
number (double) |
ToolParam.integer(name, desc) |
integer |
ToolParam.boolean(name, desc) |
boolean |
ToolParam.stringEnum(name, desc, values) |
string + enum |
ToolParam.array(name, desc, items) |
array |
ToolParam.object(name, desc, props) |
object |
Persistent memory
await HiveMemoryStore.initialize();
final agent = AgenticAgent(
provider: myProvider,
memory: HiveMemoryStore(),
sessionId: 'user_${userId}',
);
await agent.clearHistory();
final history = await agent.getHistory();
Use InMemoryStore() (default) for ephemeral memory.
Streaming
final agent = AgenticAgent(provider: myProvider);
await for (final chunk in agent.chatStream('Tell me a story.')) {
stdout.write(chunk);
}
ReAct step callbacks
final response = await agent.chat(
'What is the weather in Tokyo and what is 100^0.5?',
onStep: (step) {
switch (step) {
case ThinkingStep(:final thought):
print('π $thought');
case ToolCallStep(:final toolName, :final arguments):
print('π§ calling $toolName($arguments)');
case ToolResultStep(:final toolName, :final result):
print('β
$toolName β $result');
case FinalResponseStep(:final text):
print('π $text');
case ErrorStep(:final message):
print('β $message');
}
},
);
Safety layer
// Input guard β blocks empty, too-long, and injected inputs
final guard = InputGuard();
final clean = guard.validate(userInput);
final strict = InputGuard.withInjectionDetection();
// Output guard β PII redaction, truncation, blocklists
final safe = OutputGuard.withPiiRedaction();
final text = safe.process(rawLlmText);
// Rate limiter + concurrency cap
final limiter = RateLimiter(maxRequests: 20, windowDuration: Duration(minutes: 1));
limiter.check(sessionId);
final concurrency = ConcurrencyLimiter(maxConcurrent: 3);
final response = await concurrency.run(userId, () => agent.chat(message));
Smart routing & fallback
// Fallback to secondary if primary fails
final router = SmartRouter(
primary: GeminiProvider(apiKey: '...'),
secondary: OllamaProvider(model: 'llama3.2'),
);
// Strip PII before sending to the cloud
final privacyRouter = PrivacyRouter(
cloudProvider: OpenAIProvider(apiKey: '...'),
sensitiveKeys: ['email', 'phone', 'ssn'],
);
Per-call routing β PolicyRouter (NEW in 0.2.0)
SmartRouter picks one backend at init; PolicyRouter re-decides on every call β cheap / private / offline-friendly tasks stay on-device, hard reasoning goes to the cloud. Your agent call sites never change:
final router = PolicyRouter(
providers: {
'local': GemmaProvider(...), // private, free, offline
'cloud': GeminiProvider(apiKey: ''), // smart, paid
},
defaultProvider: 'cloud',
rules: [
RouteRules.sensitive(useProvider: 'local'), // PII stays on-device
RouteRules.shortInput(useProvider: 'local'), // small tasks stay local
RouteRules.needsTools(useProvider: 'cloud'), // tool calls need cloud
],
onRoute: (d) => print(d), // log / show a "π local" badge in your UI
);
final agent = AgenticAgent(provider: router); // call sites never change
Built-in rules: sensitive(), shortInput(), longContext(), needsTools(), streaming(), custom().
Need a one-off override? Force a provider per call:
await agent.chat('My salary is 95k, plan my budget', provider: localGemma);
AgenticFlow β multi-step AI pipelines (NEW in 0.2.0)
Chain agent calls, tool runs, and transforms into one named, type-safe, observable pipeline (inspired by Genkit flows, built Flutter-first):
final tripPlanner = AgenticFlow.start<String>('trip-planner')
.then<String>('extract-city', (input, ctx) async {
return (await extractor.chat('Extract the city: $input')).text;
})
.then<String>('fetch-weather', (city, ctx) async {
ctx.set('city', city);
return await weatherApi.forecast(city);
})
.then<String>('write-plan', (weather, ctx) async {
final city = ctx.get<String>('city');
return (await planner.chat('Plan a day in $city. Weather: $weather')).text;
});
final plan = await tripPlanner.run(
'I want to visit Tokyo tomorrow',
onEvent: (e) => print(e), // FlowStepStarted / Completed / Failed β live UI
);
Failures throw FlowException(flowName, stepName, cause) β logs point straight at the failing stage.
Retry on failures
final resilient = RetryProvider(
inner: GeminiProvider(apiKey: '...'),
maxAttempts: 3,
initialDelayMs: 500, // doubles each retry with Β±25% jitter
);
Model registry
final config = ModelRegistry.get('gemini-2.0-flash');
print(config.contextWindow); // 1048576
print(config.inputCostPer1MTokens); // 0.075
final manager = ContextManager.forModel('gemini-2.0-flash');
final fitted = manager.fit(messages);
Logging
await AgenticAI.init(
providers: { ... },
logLevel: LogLevel.debug,
);
AgenticLogger.setHandler((level, message, [error]) {
Crashlytics.instance.log('[$level] $message');
});
Default: LogLevel.none β silent in production.
Platform support
| Platform | Cloud (Gemini / OpenAI / Anthropic / HF) | Ollama | On-device Gemma | On-device GGUF |
|---|---|---|---|---|
| Android | β | β | β | β |
| iOS | β | β | β | β οΈ xcframework needed |
| macOS | β | β | β | β |
| Windows | β | β | β | β |
| Web | β | β | β | β |
| Linux | β | β | β | β |
See PLATFORM_SETUP.md for native setup instructions per platform.
The flutter_agentic family
flutter_agentic is an umbrella β companion packages extend the core SDK:
| Package | What it adds |
|---|---|
| flutter_agentic_graph | LangGraph-style stateful agent graphs β cycles, checkpointing, human-in-the-loop |
| flutter_agentic_ui | Drop-in chat UI β streaming bubbles, ReAct step visualizer, input bar |
| flutter_agentic_tools | Device tools β clipboard, sandboxed files, guarded HTTP, system info |
| flutter_agentic_memory | Semantic memory β embeddings, on-device vector search, long-term recall |
Roadmap
- More providers: Mistral, Groq, Cohere, local llama.cpp server
- Parallel graph branches (fan-out / fan-in) in flutter_agentic_graph
- More device tools: location, camera, contacts
License
MIT β see LICENSE.
Libraries
- flutter_agentic
- flutter_agentic β Build AI agents in Flutter. Local and cloud, one API.