Skip to main content

Getting Started

koel is a premium Dart/Flutter SDK for the AG-UI protocol — the agent-to-UI event protocol behind CopilotKit. It gives you typed AG-UI events, a framework-free HTTP/SSE transport, a folded ChatState, and Flutter glue, so a chat surface backed by any AG-UI agent is a few lines rather than a protocol implementation.

koel is a faithful, contract-first port of the AG-UI standard: every public symbol is a one-way door, every error reaches a surface, and the sealed event union is exhaustive. There is no hidden state and no silent failure path.

Install

For most apps, depend on the koel meta-package — it re-exports koel_core, koel_http, and koel_flutter so a single dependency gives you the whole quickstart path.

dart pub add koel
# or, in a Flutter app:
flutter pub add koel

Widgets ship separately (they are not re-exported by the meta-package), so add koel_widgets when you want the prebuilt chat UI:

flutter pub add koel_widgets

Your first run (offline)

You do not need a backend to see koel work. koel_test's MockAgent replays a canned event sequence, so the wiring is identical to production — only the agent changes.

import 'package:koel/koel.dart' show KoelClient;
import 'package:koel_test/koel_test.dart' show MockAgent;

Future<void> main() async {
final agent = MockAgent.programmatic()
.runStarted()
.textMessage('Hello, world!')
.runFinished()
.build();

final client = KoelClient(agent: agent);
final session = client.newSession();

await session.send('Hi!'); // the mock ignores the prompt and replays its script
print(session.state.messages.last.content); // → Hello, world!

client.dispose();
}

KoelClient owns the agent and every session it mints; disposing the client tears them all down. ChatSession.state is the folded ChatState after the reducer has applied the run's events — see The reducer.

Swap in a real backend

The only line that changes is the agent. Point an HttpAgent at any AG-UI SSE endpoint:

import 'package:koel/koel.dart' show HttpAgent, KoelClient;

final client = KoelClient(
agent: HttpAgent(url: Uri.parse('https://your-backend.example/agui')),
);

For a specific backend, use its bridge package — koel_agno, koel_langgraph, or koel_runtime (CopilotKit). They all speak the same native AG-UI/SSE wire and expose the same KoelClient API.

In Flutter

Drive a chat UI from a KoelChatController (a ChangeNotifier over the session's state) and the koel_widgets building blocks:

import 'package:koel/koel.dart' show KoelChatController, KoelClient;
import 'package:koel_test/koel_test.dart' show MockAgent;

final client = KoelClient(agent: MockAgent.programmatic().runStarted().runFinished().build());
final controller = KoelChatController(session: client.newSession());
// ListenableBuilder(listenable: controller, builder: ...) rebuilds on each
// ChatState fold. Dispose the controller, then the client, in State.dispose().

The runnable reference app is at example/ in the repo.

Where to next

  • Concepts — events, interceptors, the reducer, and sessions, one page each.
  • Recipes — 14 working scenarios, from connecting a backend to generative UI.
  • Adapter Cookbook — write your own backend bridge against the conformance contract.
  • Migration Guide — the 1.x forward-compatibility policy.
  • API Reference — the per-package dart doc on pub.dev.