pub tag buymeacoffee sponsor patreon discord instagram license


Provider-agnostic Dart abstraction over Claude, OpenAI, and Gemini. One interface for listing models, single-shot completions, multi-turn chat, and token streaming.

Why

Most apps that touch more than one LLM provider end up with three near-duplicate HTTP wrappers. ai_broker collapses them behind one interface so a feature written against AiBroker runs against any provider — and adding the next provider is one file in lib/src/brokers/, not three.

Shape

abstract class AiBroker {
  String get id;                                        // 'openai' | 'anthropic' | 'gemini'
  String get label;
  Future<List<String>> listModels(String apiKey);
  Future<String> complete({ ... });                     // single-shot
  Future<String> chat({ ... ChatRequest request });     // multi-turn
  Stream<String> stream({ ... ChatRequest request });   // token-by-token
}

Concrete brokers: OpenAiBroker, AnthropicBroker, GeminiBroker. Wire once via AiBrokerRegistry, look up by id thereafter.

Quick start

import 'package:ai_broker/ai_broker.dart';

void main() async {
  AiBrokerRegistry.instance
    ..register(OpenAiBroker())
    ..register(AnthropicBroker())
    ..register(GeminiBroker());

  final broker = AiBrokerRegistry.instance.lookup('anthropic')!;
  final keys = EnvKeyResolver();                 // reads ANTHROPIC_API_KEY
  final apiKey = await keys.require(broker.id);

  final answer = await broker.complete(
    apiKey: apiKey,
    model: 'claude-opus-4-7',
    system: 'You answer concisely.',
    user: 'Capital of France?',
  );
  print(answer);

  // Streaming:
  final stream = broker.stream(
    apiKey: apiKey,
    model: 'claude-opus-4-7',
    request: const ChatRequest(
      system: 'You write short prose.',
      messages: [AiMessage.user('Describe an ocean sunset.')],
    ),
  );
  await for (final chunk in stream) {
    stdout.write(chunk);
  }
}

Key resolution

API keys arrive per call. Pick a KeyResolver:

Resolver Use when
EnvKeyResolver CLI / backend code. Reads OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY (overridable).
MapKeyResolver Tests, or apps that already hold keys in a map.
(your own) Flutter apps using secure storage — implement KeyResolver against your store.

For Flutter apps that already manage settings + secure storage, you can skip KeyResolver and pass apiKey: directly.

What it doesn't do

  • No safety gate. Read-only SQL enforcement, prompt sanitisation, output filtering — call-site concern, not this package's.
  • No persistence. Settings, key storage, model selection — caller's problem.
  • No tools / function calling. Add when a consumer actually needs it.
  • No Flutter widgets. Pure Dart. Build pickers / settings dialogs on top in the consuming app.

## Run the example

```sh
dart pub get
ANTHROPIC_API_KEY=sk-... dart run example/example.dart anthropic
OPENAI_API_KEY=sk-...    dart run example/example.dart openai gpt-4o-mini
GEMINI_API_KEY=...       dart run example/example.dart gemini gemini-2.5-flash

🔍 For more information, refer to the API reference.


💬 Contributing and Discussions

This is an open-source project, and we warmly welcome contributions from everyone, regardless of experience level. Whether you're a seasoned developer or just starting out, contributing to this project is a fantastic way to learn, share your knowledge, and make a meaningful impact on the community.

☝️ Ways you can contribute

  • Find us on Discord: Feel free to ask questions and engage with the community here: https://discord.gg/gEQ8y2nfyX.
  • Share your ideas: Every perspective matters, and your ideas can spark innovation.
  • Help others: Engage with other users by offering advice, solutions, or troubleshooting assistance.
  • Report bugs: Help us identify and fix issues to make the project more robust.
  • Suggest improvements or new features: Your ideas can help shape the future of the project.
  • Help clarify documentation: Good documentation is key to accessibility. You can make it easier for others to get started by improving or expanding our documentation.
  • Write articles: Share your knowledge by writing tutorials, guides, or blog posts about your experiences with the project. It's a great way to contribute and help others learn.

No matter how you choose to contribute, your involvement is greatly appreciated and valued!

☕ We drink a lot of coffee...

If you're enjoying this package and find it valuable, consider showing your appreciation with a small donation. Every bit helps in supporting future development. You can donate here: https://www.buymeacoffee.com/dev_cetera

LICENSE

This project is released under the MIT License. See LICENSE for more information.

Libraries

_common
ai_broker
One Dart surface over Claude / OpenAI / Gemini. Apps depend on AiBroker (not a concrete provider) so swapping models is a registry lookup, not a code change.