Skip to main content

Your first request

This page walks from nothing to a real text completion in four steps. You start offline with a fake, then read a key from the environment, then swap the fake for a real provider client. The generateText call stays the same the whole way.

Step 1: run it offline with the fake​

FakeTextGenerator returns a fixed completion and never touches the network. Use it to check the shape of the call before you have a key. It implements the same TextGenerator contract as every real client.

import 'package:ai_abstracted/ai_abstracted.dart';

Future<void> main() async {
final generator = FakeTextGenerator(text: 'Hello from the fake.');
final result = await generator.generateText(
const TextRequest(prompt: 'Write a one-line greeting.'),
);
print(result.text); // Hello from the fake.
}

result.text decodes the result bytes as UTF-8. Every text result carries its bytes plus normalized metadata; see result types.

Step 2: get a key and read it from the environment​

For Claude, create an ANTHROPIC_API_KEY in your Anthropic console, then export it in your shell. For Gemini, use GEMINI_API_KEY from Google AI Studio.

credentialsFromEnv reads that variable and returns ProviderCredentials?. It returns null when the key is absent, so guard the result. Platform.environment comes from dart:io in your own program; the package itself stays free of dart:io.

// Fragment inside main().
final credentials = credentialsFromEnv(ProviderId.claude, Platform.environment);
if (credentials == null) {
stderr.writeln('Set ANTHROPIC_API_KEY and try again.');
return;
}

Step 3: swap the fake for a real client​

ClaudeTextClient takes those credentials and exposes the same generateText method. Nothing else about the call changes. This step sends a real request and bills your account.

import 'dart:io';

import 'package:ai_abstracted/ai_abstracted.dart';

Future<void> main() async {
final credentials = credentialsFromEnv(ProviderId.claude, Platform.environment);
if (credentials == null) {
stderr.writeln('Set ANTHROPIC_API_KEY and try again.');
return;
}

final generator = ClaudeTextClient(credentials: credentials);
final result = await generator.generateText(
const TextRequest(prompt: 'Write a one-line greeting.'),
);
print(result.text);
}

To use Gemini instead, read ProviderId.gemini in step 2 and construct GeminiTextClient(credentials: credentials) here. The rest is identical.

Step 4: handle a non-text result​

Image, video, speech, sound effect, and music results come back as raw bytes in result.bytes (a Uint8List). The package never writes files, so you decide where they go. Write them yourself with dart:io.

// Fragment: persisting bytes from any media result.
await File('out.png').writeAsBytes(result.bytes);

Each capability has its own request and metadata fields. See result types for the six shapes and what their metadata reports.

Next​