Feature SDKs
How to add an AI chat screen to a Flutter app
Pro Reference for ai_chat_sdk: every variable, option and package it generates. Command: archipelago generate ai_chat_sdk
Generate the AI Chat SDK with OpenAI, Anthropic or both, set API keys without committing them, and drive the chat from your own code.
What you'll learn
- Generating the AI Chat SDK with OpenAI, Anthropic, or both
- Understanding the packages the brick creates
- Setting API keys without committing them
- Driving the chat from your own code
Prerequisites
- An existing Archipelago monorepo (see Monorepo Scaffolding)
- A Pro or Enterprise subscription
ai_chat_sdk needs storage_sdk for chat history. The brick generates storage_sdk for you if it is missing. You do not install it first.
Step 1: Generate the AI Chat SDK
archipelago generate ai_chat_sdkThe prompts are:
- aiChatProvider:
openai,anthropicorboth(defaultopenai) - defaultModel: the model ID sent to the provider (default
gpt-4o-mini) - uiKitPackageName: read from
archipelago.yaml
Or use a config file:
{
"aiChatProvider": "both",
"defaultModel": "gpt-4o-mini"
}archipelago generate ai_chat_sdk --config ai_chat_config.jsonStep 2: Understand the Generated Structure
The chat contract lives in ai_chat_api. Each provider is its own package. The post-generation hook deletes the providers you did not select.
features/ai_chat/
├── ai_chat_api/
│ └── lib/src/
│ ├── models/ # ChatMessage, ChatRequest, ChatStreamEvent, ...
│ ├── utils/ # AiChatInjectorKey
│ └── ai_chat_sdk.dart # AiChatSDK contract
├── ai_chat_impl/
│ └── lib/src/
│ ├── data/ # ChatHistoryStorage
│ ├── di/ # AiChatImplGlobalModule
│ ├── presentation/widgets/ # Chat screen, bubbles, input bar
│ ├── router/
│ └── ai_chat_sdk_impl.dart
├── ai_chat_openai_impl/ # If openai or both
└── ai_chat_anthropic_impl/ # If anthropic or bothStep 3: Check the Wiring
AiChatImplGlobalModule registers an AiChatManifest with the /ai-chat route. It registers AiChatSDK as a lazy singleton. Boot does not read the history or build the providers.
Both providers can be active at once. Each registers AiChatProvider under a distinct @Named key. The orchestrator finds them with getAll<AiChatProvider>() on first use.
Step 4: Configure Your API Key
Each provider package reads its key from String.fromEnvironment. A request fails while the placeholder key is in place. The dependency graph still resolves without a key.
// ai_chat_openai_impl/lib/src/di/register_module.dart
const key = String.fromEnvironment('OPENAI_API_KEY', defaultValue: 'YOUR_OPENAI_API_KEY');Pass the key at build time:
flutter run --dart-define=OPENAI_API_KEY=sk-...In GitHub Actions:
- name: Build
run: flutter build apk --dart-define=OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}You can also set OPENAI_API_KEY or ANTHROPIC_API_KEY in .env and run melos run env:generate. Then follow the TODO(user) in each register_module.dart to read the generated Env value.
Step 5: Open the Chat or Drive It from Code
final chat = getIt<AiChatSDK>();
await chat.launch(context); // opens /ai-chat
await chat.sendMessage('Hello!'); // returns the request id
chat.conversationStream.listen((messages) => setState(() => _messages = messages));
chat.cancelInflight();
await chat.clearConversation();
await chat.retryLastFailed();sendMessage streams the assistant reply into conversationStream. The stream holds the full message list each time.
Step 6: Switch Providers
chat.setProvider(AiChatProviderId.anthropic); // throws if not registeredRead chat.availableProviders to list what is registered.
Step 7: History
The SDK stores history with StorageProvider.forNamespace('ai_chat') at application scope. A logout does not clear it. Call clearConversation() on logout if you want an empty chat.
History loads in the background after the SDK is built. Send, clear and retry wait for the load.
Key Configuration Points
| Customization | Where to Change |
|---|---|
| Default model | The defaultModel variable, or AiChatConfig |
| Add a provider | A new package that implements AiChatProvider and registers under its own @Named key |
| Storage backend | The storage_sdk implementation you installed |
| Chat widgets | ai_chat_impl/lib/src/presentation/widgets/ |
Known Limitations
- The provider packages talk to
Diodirectly. Interceptors fromnetwork_sdkdo not apply. - No integration tests ship for the streaming parsers. Add a live-API test before you ship.
Next Steps
- Set up feature flags to gate the chat feature by subscription tier