syni
Flutter SDK for Syni โ adaptive on-device LLM inference with hybrid local/cloud chat, structured persona conditioning, and a streaming chat API designed for the UI thread.
Features
- ๐ง On-device inference โ Qwen 2 / 2.5 and Gemma 3 GGUF models out of the box; bring your own GGUF for other supported architectures.
- ๐ Hybrid local / cloud โ same agent API, choose execution mode
per call (
localFirst,cloudFirst,localOnly,cloudOnly). - ๐ญ Versioned personas โ load by id from bundled syni-spec JSON; the same id resolves to the same behavior on client and server.
- ๐งต Worker isolate so engine load + token generation don't block the UI thread.
- ๐ Verified model downloads โ pinned SHA-256 per model, checked at install time.
- ๐ก Streaming chat with token-level deltas plus a final structured response.
Getting started
Add the dependency:
flutter pub add syni
Install the runtime via the Synheart CLI:
synheart install runtime syni
This drops the platform binaries into your app's vendor tree
(synheart/vendor/syni-runtime/) so Gradle / Cocoapods can link them. Re-run
the command anytime you want to refresh โ it's idempotent.
Then import the agent layer:
import 'package:syni/agent.dart';
Usage
A complete runnable Flutter app lives in example/. The
abridged version:
import 'package:flutter/material.dart';
import 'package:syni/agent.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final agent = SyniAgent();
// Load a persona by id from the bundled spec assets.
final persona = await SyniSpecPersona.load('focus.coach.v1');
// First-run install: download + verify the model, load the engine,
// bind the persona. Emits lifecycle events on agent.installState.
await agent.install(
persona: persona,
model: SyniModels.qwen25_15bInstructQ4,
);
// Single-turn chat.
final response = await agent.chat('How can I focus right now?');
debugPrint(response.displayText);
}
Streaming
agent.chatStream('hello').listen((event) {
switch (event) {
case SyniChatDelta(:final delta):
stdout.write(delta);
case SyniChatFinal(:final response):
print('\n[${response.displayText.length} chars]');
}
});
Structured turns
turn() keeps the host's task, the conversation and the user's message
separate all the way to the runtime, instead of flattening them into one
prompt. turnStream() is its streaming form. Both run on device.
final request = SyniTurnRequest(
requestId: 'req-1',
task: const SyniTaskContract(
instruction: 'Answer in two short sentences.',
),
userMessage: 'How was my focus today?',
context: {'focus_minutes_today': 95},
);
// Whole answer at once.
final result = await agent.turn(request);
debugPrint(result.response.displayText);
// Or word by word.
final subscription = agent.turnStream(request).listen((event) {
switch (event) {
case SyniTurnDelta(:final text):
stdout.write(text);
case SyniTurnFinal(:final result):
print('\n[${result.finishReason}]');
}
});
// Cancelling the subscription stops the generation.
await subscription.cancel();
Hybrid local / cloud
final agent = SyniAgent(
cloudConfig: SyniCloudConfig(
baseUrl: 'https://api.synheart.ai',
authToken: () async => '<bearer-token>',
tenantId: '<tenant>',
userId: '<user>',
),
);
await agent.chat(
'how was my recent session?',
mode: SyniExecutionMode.cloudFirst, // try cloud, fall back to local
);
Where this fits
package:syni is the agent layer โ inference, install lifecycle,
persona binding, chat orchestration. It does not own:
- HSI signal collection (the
synheart_coreSDK does), or - the four-authority gate (consent + capability + activation + session; also a host concern).
Synheart-ecosystem apps typically depend on synheart_core and use
Synheart.syni, which wraps this package with those layers. Standalone
use of package:syni is fully supported when you don't need the wider
Synheart contract.
Documentation
- API reference on pub.dev
- Syni overview โ Synheart's on-device LLM stack
- Syni Spec โ canonical persona / safety / schema contracts
Also available on
| Platform | Package | Repo |
|---|---|---|
| iOS / macOS | Syni (SwiftPM + CocoaPods) |
syni-swift |
| Android | ai.synheart:syni-sdk (Maven Central) |
syni-kotlin |
All three SDKs expose the same SyniAgent API โ same methods, same
states, same persona/model catalog โ only the platform idioms differ
(Future / Stream here, async/AnyPublisher on Swift, suspend/Flow
on Kotlin).
Contributing
This is a source-available repository. Issues and feature requests are welcome; pull requests are not accepted at this time. See CONTRIBUTING.md for the rationale and the supported contribution path. Security reports go through SECURITY.md.
License
Apache 2.0 ยฉ Synheart.