๐Ÿค– AI SDK Dart

A Dart/Flutter SDK inspired by Vercel AI SDK โ€” provider-agnostic APIs for text generation, streaming, structured output, tool use, embeddings, image generation, speech, and more.

ai_sdk_dart pub.dev ai_sdk_openai pub.dev ai_sdk_anthropic pub.dev ai_sdk_google pub.dev ai_sdk_azure pub.dev ai_sdk_cohere pub.dev ai_sdk_groq pub.dev ai_sdk_mistral pub.dev ai_sdk_ollama pub.dev ai_sdk_flutter_ui pub.dev ai_sdk_mcp pub.dev ai_sdk_provider pub.dev ai_sdk_conversation pub.dev ai_sdk_remote pub.dev ai_sdk_json_schema pub.dev ai_sdk_telemetry pub.dev CI License: MIT Dart SDK


What is this?

AI SDK Dart brings Vercel AI SDK concepts to Dart and Flutter with Dart types, streams, and lifecycle primitives. Core workflows share a provider-neutral API; provider-specific capabilities remain explicit.

What's new in 3.0

Version 3.0 was reviewed against Vercel AI SDK 7.0.111 / provider 4.0.17. See the v2-to-v3 migration guide for the full upgrade path and the contract comparison for the implementation-by-implementation audit.

  • instructions โ€” the canonical top-level instruction, retained across steps; system remains a deprecated fallback. System-role input messages are rejected by default unless allowSystemInMessages: true.
  • Canonical stream + callbacks โ€” result.stream is now the exhaustive typed event stream (the old provider-part stream moved to providerStream); fullStream is a deprecated alias, not a second producer. onStart, onStepStart, onToolExecutionStart, onToolExecutionEnd, onStepEnd, and onEnd are the canonical lifecycle callbacks (onFinish/onStepFinish remain fallbacks).
  • Aggregate results + finalStep โ€” usage, content, toolCalls, sources, and files aggregate every step; text, structured output, reasoning, reasoningText, and finalStep describe the last step only. responseMessages holds just the turns generated by that call โ€” append it once to your own history with result.responseMessages.map(ModelMessage.fromProvider).
  • Context, approval, and concurrency โ€” toolWithContext binds typed application context to a tool executor without sending it to the provider; approvalPolicy moves approval to the request/agent boundary; a restored approval is bound to the exact call ID, arguments, and policy revision. maxToolConcurrency admits more than one tool call at a time (serial by default).
  • Cancellation and deadlines โ€” a shared CancellationToken (abortSignal) reaches every adapter and closes real transport work. TimeoutConfiguration distinguishes total/step/first-chunk/chunk/tool deadlines for generateText, streamText, and ToolLoopAgent. Set timeout: const TimeoutConfiguration(total: Duration(seconds: 30)) for a total deadline. Object, embedding, media, and reranking functions accept Duration.
  • BodyInclusionPolicy โ€” request/response bodies and raw provider chunks are omitted by default; opt in per call when an integration needs to retain them.
  • OpenAI Responses, Files and Batch โ€” openai.responses(id) with hosted tools (web search, file search, code interpreter, image generation, remote MCP), plus Files and Batch lifecycle clients.
  • Reasoning controls โ€” one reasoning option mapped to OpenAI reasoning effort, Anthropic thinking and Gemini thinking budgets; signed reasoning is replayed through responseMessages.
  • Provider file references โ€” canonical file parts distinguish bytes, a URL, and an opaque DataContentProviderReference (namespace + ID) that an unrelated provider must reject rather than reinterpret as a URL.
  • New companion packages โ€” ai_sdk_conversation (immutable persisted snapshots + codec), ai_sdk_remote (trusted-backend UI-message-stream transport), ai_sdk_json_schema (optional local schema validation before decoding), and ai_sdk_telemetry (OTLP/HTTP metrics export) โ€” see the package table below. ai_sdk_realtime tracks the same contracts as an unpublished preview.
  • MCP modern protocol โ€” MCPProtocolMode.modern, host-owned auth discovery (MCPAuthConfiguration/MCPAuthDiscovery), typed progress, and explicit retryOnTransportFailure now that a lost tools/call reply is no longer retried automatically by default.

Model IDs remain open strings. The dated capability catalog separates upstream catalog information from protocol fixtures and live evidence; a model appearing in that catalog does not establish every SDK feature works with that model. Live-provider qualification (real API canaries, device audio for ai_sdk_realtime) is tracked separately and remains in progress โ€” see docs/provider-canaries.md.

Upgrading from 2.x or earlier? The 2.0 migration guide covers the V3โ†’V4 provider-seam rename first; apply it before the 3.0 guide above.


Screenshots

Flutter Chat App (examples/flutter_chat)

Multi-turn Chat Streaming Response
Multi-turn chat Chat response
Completion Object Stream
Completion result Object stream result
Tool Approval (Local tab) Localized RTL Strings
Local conversation waiting for tool approval Conversation with Arabic UI strings and right-to-left layout
Remote Backend (Remote tab) Chat Home
Two turns streamed from the reference backend through ai_sdk_remote Chat home with the Local and Remote tabs in the navigation bar

Advanced App (examples/advanced_app)

Provider Chat Tools Chat
Provider chat Tools chat
Image Generation Multimodal
Image generation Multimodal
In-memory Conversation Responses + Web Search
In-memory conversation with a pending tool approval OpenAI Responses answer with reasoning and web-search citations

โœจ Features

๐Ÿ—ฃ๏ธ Text Generation & Streaming

  • generateText โ€” single-turn or multi-step text generation with full result envelope
  • streamText โ€” real-time token streaming with typed event taxonomy
  • smoothStream transform โ€” configurable chunk-size smoothing; delayInMs option adds per-chunk delay for UX pacing
  • Multi-step agentic loops with maxSteps, prepareStep, and stopConditions
  • timeout accepts TimeoutConfiguration for text generation, streaming, and agents; object, embedding, media, and reranking functions accept a total Duration deadline
  • Canonical callbacks: onStart, onStepStart, onToolExecutionStart, onToolExecutionEnd, onStepEnd, onEnd (plus onChunk, onError, onAbort); deprecated onFinish/onStepFinish remain fallbacks

๐Ÿงฉ Structured Output

  • Output.object(schema) โ€” parse model output into a typed Dart object
  • Output.array(schema) โ€” parse model output into a typed Dart list
  • Output.choice(options) โ€” constrain output to a fixed set of string values
  • Output.json() โ€” raw JSON without schema validation
  • Final structured output requires complete JSON; use extractJsonMiddleware when a model needs code-fence normalization

๐Ÿ”ง Type-Safe Tools & Multi-Step Agents

  • tool<Input, Output>() โ€” fully typed tool definitions with JSON schema
  • dynamicTool() โ€” tools with unknown input type for dynamic use cases
  • Tool choice: auto, required, none, or specific tool
  • Tool approval workflow with needsApproval
  • Multi-step agentic loops with automatic tool result injection
  • onInputStart, onInputDelta, onInputAvailable lifecycle hooks

๐Ÿ–ผ๏ธ Multimodal

  • generateImage โ€” image generation (gpt-image-1 / DALLยทE via OpenAI)
  • generateSpeech โ€” text-to-speech audio synthesis
  • transcribe โ€” speech-to-text transcription
  • Image inputs in prompts (multimodal vision)

๐Ÿงฎ Embeddings & Cosine Similarity

  • embed() โ€” single value embedding with usage tracking
  • embedMany() โ€” batch embedding for multiple values with configurable chunk size
  • cosineSimilarity() โ€” built-in similarity computation
  • wrapEmbeddingModel() โ€” composable middleware pipeline for embedding models

๐Ÿงฑ Middleware System

  • wrapLanguageModel(model: ..., middleware: ...) โ€” composable middleware pipeline
  • extractReasoningMiddleware โ€” strips <think> tags into ReasoningPart
  • extractJsonMiddleware โ€” strips ```json ``` fences
  • simulateStreamingMiddleware โ€” converts non-streaming models to streaming
  • defaultSettingsMiddleware โ€” applies default temperature/top-p/etc.
  • addToolInputExamplesMiddleware โ€” enriches tool descriptions with examples
  • wrapEmbeddingModel / wrapImageModel โ€” the same composable middleware pattern for embedding and image models

๐ŸŒ Provider Registry

  • createProviderRegistry โ€” map provider aliases to model factories
  • customProvider() โ€” lightweight on-the-fly provider construction without a full registry
  • Resolve models by 'provider:modelId' string at runtime
  • Supports 6 model categories: language, embedding, image, speech, transcription, rerank
  • Mix providers in a single registry for multi-provider apps

๐Ÿ“ฑ Flutter UI Controllers & Widgets

  • ChatController โ€” multi-turn streaming chat with message history
  • CompletionController โ€” single-turn text completion with status
  • ObjectStreamController โ€” streaming typed JSON object updates
  • 19 prebuilt, themeable Material widgets โ€” AiChatScaffold, message list/bubbles, composer, streaming text, typing indicator, tool-call & approval cards, reasoning, citations, usage, and more

๐Ÿ”Œ MCP Client (Model Context Protocol)

  • MCPClient โ€” connect to MCP servers, discover tools, invoke them
  • StreamableHttpClientTransport โ€” MCP Streamable HTTP transport (2025-06-18) for remote servers
  • StdioMCPTransport โ€” stdio process transport (native platforms)
  • Web-safe โ€” dart:io is isolated behind conditional imports, so the client runs on Flutter web
  • Discovered tools are directly compatible with generateText/streamText

๐Ÿšจ Typed Errors

  • Sealed AiSdkError hierarchy โ€” AiApiCallError, AiNoObjectGeneratedError, and AiRetryError for exhausted retryable failures
  • Provider API errors are typed โ€” a non-2xx response throws AiApiCallError carrying the provider's message, type, code, statusCode, raw body, and an isRetryable flag, consistently across every provider

๐Ÿงช Conformance Suite

  • Comprehensive Dart and Flutter tests across every package and both example apps
  • A 99% line-coverage gate for published package libraries enforced in CI
  • Provider wire-format conformance tests for every provider (plus a typed-error conformance test per provider)
  • MockEmbeddingModelV2 testing utility for embedding model conformance

๐Ÿ“ฆ Packages

Package pub.dev What it gives you
ai_sdk_dart dart pub add ai_sdk_dart generateText, streamText, tools, middleware, embeddings, registry
ai_sdk_openai dart pub add ai_sdk_openai openai('gpt-4.1-mini'), embeddings, image gen, speech, transcription, reasoning options
ai_sdk_anthropic dart pub add ai_sdk_anthropic anthropic('claude-sonnet-4-5'), extended thinking, speed options
ai_sdk_google dart pub add ai_sdk_google google('gemini-2.0-flash'), embeddings
ai_sdk_azure dart pub add ai_sdk_azure AzureOpenAIProvider(endpoint, apiKey), language models, embeddings
ai_sdk_cohere dart pub add ai_sdk_cohere cohere('command-r-plus'), embeddings, reranking
ai_sdk_groq dart pub add ai_sdk_groq groq('llama3-8b-8192'), ultra-low latency inference
ai_sdk_mistral dart pub add ai_sdk_mistral mistral('mistral-large-latest'), embeddings
ai_sdk_ollama dart pub add ai_sdk_ollama ollama('llama3'), local inference, embeddings
ai_sdk_flutter_ui dart pub add ai_sdk_flutter_ui ChatController, CompletionController, ObjectStreamController + 19 prebuilt chat widgets
ai_sdk_mcp dart pub add ai_sdk_mcp MCPClient, StreamableHttpClientTransport, native-only StdioMCPTransport
ai_sdk_provider (transitive) Provider interfaces for building custom providers
ai_sdk_openai_compatible (transitive) Shared OpenAI Chat Completions base โ€” powers the OpenAI/Azure/Groq/Mistral language models
ai_sdk_json_schema dart pub add ai_sdk_json_schema Optional local JSON Schema validation before decoding tool inputs or final structured output
ai_sdk_conversation dart pub add ai_sdk_conversation Immutable typed conversation snapshots and a versioned persistence codec; no model or tool execution
ai_sdk_remote dart pub add ai_sdk_remote Optional transport for a trusted backend's Vercel UI-message stream, with cancellation and conversation reduction
ai_sdk_telemetry dart pub add ai_sdk_telemetry Optional native Dart OTLP/HTTP metrics exporter; no browser transport โ€” in qualification
ai_sdk_realtime Unpublished preview Realtime session and event transport; protocol and device qualification remain in progress

ai_sdk_provider and ai_sdk_openai_compatible are transitive dependencies โ€” you do not need to add them directly.


๐Ÿš€ Quick Start

Local development and trusted Dart servers

dart pub add ai_sdk_dart ai_sdk_openai
import 'dart:io';

import 'package:ai_sdk_dart/ai_sdk_dart.dart';
import 'package:ai_sdk_openai/ai_sdk_openai.dart';

Future<void> main() async {
  final apiKey = Platform.environment['OPENAI_API_KEY'];
  if (apiKey == null || apiKey.isEmpty) {
    throw StateError('Set OPENAI_API_KEY before running this example.');
  }

  final provider = OpenAIProvider(apiKey: apiKey);
  try {
    final result = await generateText(
      model: provider('gpt-4.1-mini'),
      prompt: 'Say hello from AI SDK Dart!',
    );
    print(result.text);
  } finally {
    provider.dispose();
  }
}

For server and CLI apps, prefer reading credentials from your runtime environment and passing apiKey: yourself, as shown above. The convenience factories like openai('...'), anthropic('...'), and google('...') read compile-time defines such as OPENAI_API_KEY, so they are best paired with dart run --define=... or Flutter --dart-define=....

Production Flutter through a trusted backend

The optional v3 remote package sends application messages to your backend. The backend owns provider credentials, authorization, and tool execution. Use an application session token to authenticate the client.

import 'package:ai_sdk_conversation/ai_sdk_conversation.dart';
import 'package:ai_sdk_remote/ai_sdk_remote.dart';

Stream<Conversation> sendChatTurn({
  required Uri endpoint,
  required Conversation conversation,
  required Future<String> Function() sessionToken,
}) async* {
  final transport = RemoteConversationTransport(
    endpoint: endpoint,
    authHeaders: () async => {
      'Authorization': 'Bearer ${await sessionToken()}',
    },
  );
  try {
    yield* transport.send(conversation);
  } finally {
    transport.dispose();
  }
}

A Flutter StreamBuilder<Conversation> can render these snapshots. Cancelling the subscription cancels its active request and runs the cleanup above. Store snapshots with ConversationCodec; decoding a snapshot does not execute tools.

The backend must implement the pinned UI-message stream protocol. The reference backend and runnable Dart client demonstrate the request and response flow without provider credentials. The adapter does not retry or resume a disconnected turn automatically.

Streaming

import 'dart:io';

final result = await streamText(
  model: openai('gpt-4.1-mini'),
  prompt: 'Count from 1 to 5.',
);
await for (final chunk in result.textStream) {
  stdout.write(chunk);
}

Structured Output

final result = await generateText<Map<String, dynamic>>(
  model: openai('gpt-4.1-mini'),
  prompt: 'Return the capital and currency of Japan as JSON.',
  output: Output.object(
    schema: Schema<Map<String, dynamic>>(
      jsonSchema: const {
        'type': 'object',
        'properties': {
          'capital': {'type': 'string'},
          'currency': {'type': 'string'},
        },
      },
      fromJson: (json) => json,
    ),
  ),
);
print(result.output); // {capital: Tokyo, currency: JPY}

Type-Safe Tools

final result = await generateText(
  model: openai('gpt-4.1-mini'),
  prompt: 'What is the weather in Paris?',
  maxSteps: 5,
  tools: {
    'getWeather': tool<Map<String, dynamic>, String>(
      description: 'Get current weather for a city.',
      inputSchema: Schema(
        jsonSchema: const {
          'type': 'object',
          'properties': {'city': {'type': 'string'}},
        },
        fromJson: (json) => json,
      ),
      execute: (input, _) async => 'Sunny, 18ยฐC',
    ),
  },
);
print(result.text);

Error handling

try {
  final result = await generateText(
    model: openai('gpt-4.1-mini'),
    prompt: 'Hello',
  );
} on AiApiCallError catch (e) {
  // Typed provider error โ€” message, status, and retryability are all available.
  print('${e.statusCode}: ${e.message} (retryable: ${e.isRetryable})');
}

Flutter Chat UI

dart pub add ai_sdk_dart ai_sdk_openai ai_sdk_flutter_ui
import 'package:ai_sdk_dart/ai_sdk_dart.dart';
import 'package:ai_sdk_openai/ai_sdk_openai.dart';
import 'package:ai_sdk_flutter_ui/ai_sdk_flutter_ui.dart';

final agent = ToolLoopAgent(
  model: openai('gpt-4.1-mini'),
  instructions: 'You are a helpful assistant.',
);
final chat = ChatController();

// In your widget โ€” a complete chat surface:
AiChatScaffold(controller: chat, agent: agent);

Do not ship long-lived provider API keys inside distributed browser, mobile, or desktop clients. Use a trusted proxy or backend-minted short-lived credentials instead. The Flutter examples below use --dart-define for local development and smoke testing, not as a production secret-distribution strategy.


๐Ÿค– Providers

Capability OpenAI Anthropic Google Azure Cohere Groq Mistral Ollama
Text generation โœ… โœ… โœ… โœ… โœ… โœ… โœ… โœ…
Streaming โœ… โœ… โœ… โœ… โœ… โœ… โœ… โœ…
Structured output โœ… โœ… โœ… โœ… โœ… โœ… โœ… โœ…
Native JSON schema output โœ… โ€” โ€” โœ… โ€” โœ… โœ… โ€”
Tool use โœ… โœ… โœ… โœ… โœ… โœ… โœ… โœ…
Embeddings โœ… โ€” โœ… โœ… โœ… โ€” โœ… โœ…
Reranking โ€” โ€” โ€” โ€” โœ… โ€” โ€” โ€”
Image generation โœ… โ€” โ€” โ€” โ€” โ€” โ€” โ€”
Speech synthesis โœ… โ€” โ€” โ€” โ€” โ€” โ€” โ€”
Transcription โœ… โ€” โ€” โ€” โ€” โ€” โ€” โ€”
Extended thinking โ€” โœ… โ€” โ€” โ€” โ€” โ€” โ€”
Reasoning options โœ… โ€” โœ… โ€” โ€” โ€” โ€” โ€”
Multimodal (image input) โœ… โœ… โœ… โœ… โœ… โœ… โœ… โœ…

๐Ÿ› ๏ธ Flutter UI

The ai_sdk_flutter_ui package provides three reactive controllers plus a library of 19 prebuilt, themeable Material widgets โ€” so you can wire up a full chat UI in a few lines, or drop down to the controllers and render everything yourself.

Drop-in chat UI

import 'package:ai_sdk_dart/ai_sdk_dart.dart';
import 'package:ai_sdk_flutter_ui/ai_sdk_flutter_ui.dart';
import 'package:ai_sdk_openai/ai_sdk_openai.dart';

final agent = ToolLoopAgent(model: openai('gpt-4.1-mini'));
final chat = ChatController();

// A complete message list + composer, wired to the controller + agent:
AiChatScaffold(controller: chat, agent: agent);

Other widgets โ€” ChatMessageList, ChatMessageBubble, ChatComposer, StreamingTextView, TypingIndicator, ToolCallCard, ToolApprovalCard, ReasoningView, SourceCitations, UsageView, PromptSuggestions, ObjectStreamView, and more โ€” can be composed ร  la carte. They read only the controllers' public state, so they work with any state-management approach.

ChatController โ€” Multi-turn streaming chat

final agent = ToolLoopAgent(model: openai('gpt-4.1-mini'));
final chat = ChatController();

// In your widget:
ListenableBuilder(
  listenable: chat,
  builder: (context, _) {
    return Column(
      children: [
        for (final msg in chat.messages)
          Text('${msg.role}: ${msg.content}'),
        if (chat.isLoading) const CircularProgressIndicator(),
      ],
    );
  },
);

// Send a message:
await chat.sendMessage(agent: agent, text: 'What is the capital of France?');

CompletionController โ€” Single-turn completion

final completion = CompletionController(
  agent: ToolLoopAgent(model: openai('gpt-4.1-mini')),
);
await completion.complete('Write a haiku about Dart.');
print(completion.completion);

ObjectStreamController โ€” Streaming typed JSON

final controller = ObjectStreamController<Map<String, dynamic>>(
  model: openai('gpt-4.1-mini'),
  schema: Schema<Map<String, dynamic>>(
    jsonSchema: const {'type': 'object'},
    fromJson: (json) => json,
  ),
);
await controller.submit('Describe Japan as a JSON object.');
print(controller.value); // Partial updates arrive in real-time

๐Ÿ”Œ MCP Support

Connect to any Model Context Protocol server and use its tools directly in your AI calls:

import 'package:ai_sdk_dart/ai_sdk_dart.dart';
import 'package:ai_sdk_mcp/ai_sdk_mcp.dart';
import 'package:ai_sdk_openai/ai_sdk_openai.dart';

final client = MCPClient(
  transport: StreamableHttpClientTransport(
    url: Uri.parse('http://localhost:3000/mcp'),
    headers: {'Authorization': 'Bearer <short-lived-token>'},
  ),
);

await client.initialize();
final tools = await client.tools(); // Returns a ToolSet

final result = await generateText(
  model: openai('gpt-4.1-mini'),
  prompt: 'What files are in the project?',
  tools: tools,
  maxSteps: 5,
);

For stdio-based MCP servers (local processes):

final client = MCPClient(
  transport: StdioMCPTransport(
    command: 'npx',
    args: ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/dir'],
  ),
);

StreamableHttpClientTransport speaks the MCP Streamable HTTP transport (2025-06-18) against a single endpoint. It negotiates the protocol version during initialize(), sends notifications/initialized, accepts JSON or SSE responses to each POST, starts the optional GET SSE listener for server-pushed notifications, reconnects that listener with Last-Event-ID, and sends DELETE on shutdown when the server assigned Mcp-Session-Id. Put required auth or routing headers in headers, but avoid embedding long-lived secrets in shipped browser or mobile clients. The HTTP transport is web-safe โ€” dart:io is only pulled in by StdioMCPTransport on native platforms, behind a conditional import โ€” so the client also runs on Flutter web.

The client also has an explicit MCPProtocolMode.modern strategy for protocol 2026-07-28, including per-request metadata, MRTR input-required results, typed progress, and subscriptions/listen. MCP Tasks, cache-hint interpretation, and arbitrary partial tool-output streams are outside the current package surface; progress notifications do not represent partial results.


๐Ÿ—บ๏ธ Roadmap

โœ… Implemented

  • โœ… generateText โ€” full result envelope (text, steps, usage, reasoning, sources, files)
  • โœ… streamText โ€” complete event taxonomy (20 typed event types), onAbort callback
  • โœ… generateObject / structured output (object, array, choice, json) with native JSON schema
  • โœ… embed / embedMany + cosineSimilarity, wrapEmbeddingModel
  • โœ… generateImage (OpenAI gpt-image-1 / DALLยทE)
  • โœ… generateSpeech (OpenAI TTS)
  • โœ… transcribe (OpenAI Whisper)
  • โœ… rerank
  • โœ… timeout parameter on all core functions
  • โœ… customProvider() for lightweight on-the-fly provider construction
  • โœ… Middleware system โ€” 5 built-in language-model middlewares, plus embedding & image model middleware
  • โœ… Provider registry (createProviderRegistry) โ€” 6 model categories
  • โœ… Multi-step agentic loops with tool approval
  • โœ… Flutter UI controllers (Chat, Completion, ObjectStream) + 19 prebuilt Material widgets
  • โœ… MCP client (Streamable HTTP + stdio transports, prompts, resources, web-safe)
  • โœ… Typed provider API errors (AiApiCallError with status / type / code / body) across all providers
  • โœ… OpenAI (with reasoning options), Anthropic (with thinking options), Google providers
  • โœ… Cohere, Mistral, Groq, Ollama, Azure OpenAI providers โ€” all with tools + multimodal
  • โœ… Comprehensive tests with a 99% line-coverage gate for published package libraries

๐Ÿ”œ Planned

  • ๐Ÿ”œ Versioned MCP Tasks/polling adapter and richer extension support
  • ๐Ÿ”œ Richer attachment widgets (file/image pickers, audio capture)
  • ๐Ÿ”œ Dart Edge / Cloudflare Workers support
  • ๐Ÿ”œ WebSocket transport for MCP

๐Ÿค Contributing

Contributions are welcome! Please open an issue first to discuss changes before submitting a PR.

Running tests

fvm flutter pub get
make test
make analyze

Run make benchmark for the structured-stream throughput benchmark.

Or run a smaller set of pinned toolchain smoke checks directly:

fvm dart analyze .
fvm dart test packages/ai_sdk_dart/test/
fvm dart test packages/ai_sdk_openai/test/
fvm dart test packages/ai_sdk_anthropic/test/
fvm dart test packages/ai_sdk_google/test/
fvm flutter test examples/flutter_chat/
fvm flutter test examples/advanced_app/

Runnable examples

CLI and server examples can read credentials from the process environment. The repo make targets forward those values to the provider factories as compile-time defines when needed:

OPENAI_API_KEY=sk-... make run-basic
OPENAI_API_KEY=sk-... make run-mcp

Equivalent direct Dart invocation:

OPENAI_API_KEY=sk-... \
  fvm dart run --define=OPENAI_API_KEY=sk-... examples/basic/lib/main.dart

Flutter example apps are different: they read compile-time defines from String.fromEnvironment, so pass keys with --dart-define:

cd examples/flutter_chat && fvm flutter run \
  --dart-define=OPENAI_API_KEY=sk-...

cd examples/advanced_app && fvm flutter run \
  --dart-define=OPENAI_API_KEY=sk-... \
  --dart-define=ANTHROPIC_API_KEY=sk-ant-... \
  --dart-define=GOOGLE_API_KEY=AIza...

The Flutter commands above compile the keys into the client app. Use them for local demos only. Production apps should call a trusted backend or fetch short-lived provider credentials instead of embedding long-lived secrets.

Example Command What it shows
Dart CLI (examples/basic) OPENAI_API_KEY=sk-... make run-basic generateText, streaming, structured output, tools, embeddings, middleware
Flutter chat (examples/flutter_chat) cd examples/flutter_chat && fvm flutter run --dart-define=OPENAI_API_KEY=sk-... Chat / Completion / Object stream tabs (ChatController, CompletionController, ObjectStreamController), plus Local and Remote conversation tabs backed by ConversationController (LocalConversationBackend / RemoteConversationBackend against examples/remote_backend)
Flutter chat (web) cd examples/flutter_chat && fvm flutter run -d chrome --dart-define=OPENAI_API_KEY=sk-... Same as above on Chrome
Advanced app (examples/advanced_app) cd examples/advanced_app && fvm flutter run --dart-define=OPENAI_API_KEY=sk-... --dart-define=ANTHROPIC_API_KEY=sk-ant-... --dart-define=GOOGLE_API_KEY=AIza... All providers, tools, image gen, TTS, STT, multimodal, embeddings, completion, object stream, widget gallery, plus a Conversation page (in-memory snapshot restore, interruption, approval turns) and a Responses page (OpenAI Responses API + hosted tools)
Advanced app (web) cd examples/advanced_app && fvm flutter run -d chrome --dart-define=OPENAI_API_KEY=sk-... --dart-define=ANTHROPIC_API_KEY=sk-ant-... --dart-define=GOOGLE_API_KEY=AIza... Same as above on Chrome
MCP demo make run-mcp MCP tool discovery + direct tool calls (works without an API key)
Remote backend (examples/remote_backend) dart run bin/server.dart The smallest trusted-backend shape for ai_sdk_remote: a scripted Vercel AI SDK UI-message-stream server with no provider keys, used by the Flutter chat app's Remote tab and packages/ai_sdk_remote/example/example.dart
MCP reference fixture (examples/mcp_reference) make test-mcp-reference Pins the TypeScript MCP SDK server as a local subprocess and qualifies the Dart legacy transport against a real, independent MCP implementation

Development

Managed with the Dart pub workspace and the repository Makefile:

fvm flutter pub get
make analyze
make test

See docs/v6-parity-matrix.md for a feature-by-feature parity matrix against Vercel AI SDK v6.


๐Ÿ“„ License

MIT

Libraries

ai_sdk_dart
test
Testing utilities for the AI SDK Dart.