flutter_pipwave_ai_agent
Pipwave AI Agent SDK for Flutter. This package provides a predesigned chat UI that lets your users interact with a Pipwave AI Agent inside your app (presented as a bottom sheet).
Features
- Drop-in AI Agent UI presented as a modal bottom sheet
- Direct agent support for dedicated agent flows
- Token refresh hook via
onRefreshAccessToken— SDK guards all API calls and automatically invokes this callback when the session token is expired, preventing unauthorized errors - Link handling hook via
onLinkTap - Terms of Service hook via
termsOfService - Unread counter (stream + synchronous getter) with optional background monitoring
- Custom avatars via
AvatarBuilder - Localization support (via
flutter_pipwave_localization)
Getting started
Install
Add the dependency:
dependencies:
flutter_pipwave_ai_agent: ^1.1.0
Then run:
flutter pub get
Import
import 'package:flutter_pipwave_ai_agent/flutter_pipwave_ai_agent.dart';
Usage
1. Initialise the SDK (once)
Call initialise() near app startup.
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await FlutterPipwaveAiAgent.instance.initialise();
runApp(const MyApp());
}
2. Obtain a session token from your backend
The SDK requires a short-lived sessionToken (plus userId) to connect to Pipwave services.
A common flow is:
- Your app obtains an access token for your user (from your auth system)
- Your backend calls Pipwave to create an AI Agent session and returns a session token
- You pass that session token into this SDK
This repository contains a working sample under example/ that demonstrates:
- calling an
init-ai-agentendpoint to obtain a session token - caching the token
- refreshing the token when needed
3. Launch the AI Agent UI
final authParam = AuthParam(
sessionToken: sessionToken,
userId: userId,
locale: const Locale('en'),
supportedLocales: const [Locale('en')],
aiAgentName: 'AI Agent',
isBeta: false,
);
await FlutterPipwaveAiAgent.instance.launchAiAgent(
context,
authParam: authParam,
// Called automatically when the session token is expired (guards all API calls)
onRefreshAccessToken: () async {
final freshSessionToken = await fetchFreshSessionToken();
return freshSessionToken;
},
// Called when user taps a link inside the chat UI
onLinkTap: (uri) async {
// e.g. open with url_launcher
if (!await canLaunchUrl(uri)) return;
await launchUrl(uri);
},
// Called when user taps Terms of Service in the UI
termsOfService: () {
// e.g. navigate to your ToS page
},
// Optional: customize avatar rendering for each sender type
avatarBuilder: (context, senderType) {
switch (senderType) {
case SenderType.user:
return const CircleAvatar(child: Icon(Icons.person));
case SenderType.ai:
case SenderType.system:
return const CircleAvatar(child: Icon(Icons.smart_toy));
case SenderType.admin:
return const CircleAvatar(child: Icon(Icons.support_agent));
case SenderType.unknown:
return null;
}
},
);
4. Direct agent (optional)
To trigger direct agent access—giving users a direct path to a live agent on critical pages—pass ClientUrl when launching:
final clientUrl = ClientUrl(
clientCurrentPage: 'https://example.com/checkout', // Current page URL
clientBrowsingHistory: [
'https://example.com/',
'https://example.com/products',
'https://example.com/checkout', // Last entry = current page (whitelisted for direct agent)
],
);
await FlutterPipwaveAiAgent.instance.launchAiAgent(
context,
authParam: authParam,
clientUrl: clientUrl,
onRefreshAccessToken: () async => fetchFreshSessionToken(),
onLinkTap: (uri) async {
if (!await canLaunchUrl(uri)) return;
await launchUrl(uri);
},
termsOfService: () { /* navigate to ToS */ },
);
clientCurrentPage: The URL of the page the user is currently on.clientBrowsingHistory: List of URLs the user has visited. The last entry is treated as the current page.- Add whitelisted page URLs to
clientBrowsingHistoryto enable direct agent on those pages.
Unread count (optional)
If you want to show a badge while the chat UI is closed:
final initial = FlutterPipwaveAiAgent.instance.getUnreadCount();
final stream = FlutterPipwaveAiAgent.instance.getUnreadCountStream();
Use with StreamBuilder<int>.
Background monitoring
To keep unread counting active even when the chat bottom sheet is closed:
await FlutterPipwaveAiAgent.instance.startBackgroundMonitoring();
To stop:
await FlutterPipwaveAiAgent.instance.stopBackgroundMonitoring();
To reset unread count:
FlutterPipwaveAiAgent.instance.resetUnreadCount();
Environment / endpoints
This package chooses staging vs production endpoints using a compile-time define:
pw_ai_agent_is_prod=trueuses production- otherwise uses staging
Example:
flutter run --dart-define=pw_ai_agent_is_prod=true
Error handling
SDK methods may throw PipwaveException, for example:
PipwaveException.sessionNotInitialised()if you calllaunchAiAgentbeforeinitialise()PipwaveException.contextNotMounted()if the providedBuildContextis not mountedPipwaveException.wsError(...)for typed WebSocket errors
Wrap calls in try/catch if you want to handle these explicitly.
Screen orientation
This SDK manages orientation for the AI Agent experience:
- The AI Agent UI is locked to portrait by default.
- During video preview / fullscreen video playback, the SDK may temporarily allow rotation (landscape).
If your host app hard-locks portrait at the platform level, landscape video rotation will not be possible.
Android
Ensure your MainActivity is not hard-locked to portrait, for example do not set:
android:screenOrientation="portrait"
iOS
Ensure ios/Runner/Info.plist allows landscape orientations in UISupportedInterfaceOrientations if you want video rotation:
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
</array>
Host app permissions
This SDK supports camera capture, gallery/media picking, and file picking. Your host app must declare the required platform permissions.
Android
Add the following to your host app’s android/app/src/main/AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!-- For Android 12 and below -->
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<!-- For Android 13+ explicit media permissions -->
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
<application>
...
</application>
</manifest>
Notes:
android.permission.RECORD_AUDIOis only needed if your camera flow records video with audio.- Some file picking flows use Android’s Storage Access Framework (SAF) and may not require extra storage permissions, but media/gallery pickers commonly do.
iOS
Add the following keys to your host app’s ios/Runner/Info.plist:
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to capture photos/videos for AI Agent.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>This app needs photo library access to select images/videos for AI Agent.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>This app needs permission to save media to your photo library.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access for recording videos with sound.</string>
Notes:
NSMicrophoneUsageDescriptionis only required if recording video with audio.- Document picking via the iOS document picker typically does not require extra permissions.
Platform notes
This is a Flutter UI SDK and is intended for Flutter apps (mobile/web/desktop depending on your app setup). Some features such as file picking, camera/gallery access, and video playback depend on platform plugins and may require additional platform configuration in your host app.
Contributing
Internal SDK. If you need changes or additional capabilities, please contact Pipwave.
License
See LICENSE.