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
  • 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-agent endpoint 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 when the SDK needs a fresh session token
  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 clientBrowsingHistory to 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=true uses 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 call launchAiAgent before initialise()
  • PipwaveException.contextNotMounted() if the provided BuildContext is not mounted
  • PipwaveException.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_AUDIO is 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:

  • NSMicrophoneUsageDescription is 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.