Flutter SDK reference
Every public class, function, property, stream and error of graine_inapp 0.10.3 for Flutter, grouped by what you are building: what each is for, its signature, parameters, what it returns, the errors it raises, and what to expect.
Every public declaration the Flutter package, graine_inapp 0.10.3, exports, read from its source and grouped by what you are doing: installing, identifying the customer, the chat, the voice bar, several agents, screen context and components, calls in both directions, booking, design, going live, events and errors. Each entry starts with what it is for, then its signature, its parameters, what it returns, the errors it can raise and an example; each type sits beside the functions that use it, field by field, with what to expect. The same API across every platform, topic by topic, is the SDK reference; installing and setting up is Flutter.
Requirements, install, permissions and initialisation
| Package | graine_inapp 0.10.3 on pub.dev (Android and iOS) |
|---|---|
| Requires | Flutter 3.19+ and Dart 3.3+; iOS 15+ (its pod, Swift 5.9); Android 7 / API 24+ (Java 17, compileSdk 36). Depends on http and webview_flutter (4.8+) only. |
| Native code | The package carries the native call engine (the iOS and Android SDKs' call code), so adding it or updating it needs a new store build |
YAML — pubspec.yaml
-
Calls that ring on Android: add Firebase Cloud Messaging to the Android app —
google-services.jsoninandroid/app, the Google services Gradle plugin, andcom.google.firebase:firebase-messaginginandroid/app/build.gradle.kts— and the SDK registers for pushes itself: its own messaging service rings Graine's calls natively, with no Dart. An app that usesfirebase_messaginghas its messaging service instead, which receives every message: it forwards them tohandlePush(below). -
Android: nothing to add to your manifest — the package's own merges into the app: the permissions (internet, microphone, notifications, the full-screen call notification and the microphone's foreground service), the call screen, the microphone service and the call receiver. Set
minSdk24 or higher, and ask for the notification permission on Android 13+ yourself (for examplePermission.notification.request()), so a ring can show. -
iOS: on the Runner target add
NSMicrophoneUsageDescriptiontoInfo.plist(for example "The assistant listens when you talk to it."), the Push Notifications capability, and Background Modes → Audio, AirPlay, and Picture in Picture and Voice over IP. CallKit and VoIP pushes need a real iPhone: the simulator cannot ring. -
Microphone: for the bar's voice, your app asks, in
GraineConfig.requestMicrophone, which the SDK calls before every call (left out, the SDK assumes you asked). For native calls, the SDK asks.
Flutter · Dart — lib/main.dart
WebRTC calls
Turn it on to carry the native calls' audio over WebRTC instead of the WebSocket — in both directions: the customer calling the agent (startCall, your "Call" button) and the customer answering a call Graine rang (a booked call, or "Ring now"). Off unless the app is built with it. New in 0.9.0.
iOS — at the top of ios/Podfile:
Android — in android/gradle.properties:
On a build server, GRAINE_WEBRTC=1 in the build's environment turns it on for both. Then rebuild — it is native code, so it reaches customers with your next store build. flutter build runs pod install when the Podfile changes; with only the environment variable, run pod install in ios/ too.
- Nothing else changes. No code to write, no
Info.plistentry, no capability: the same ring, the same call screen, the same "Connecting…", the sameoutcomes.GraineCallsOptions(callTransport:)chooses how calls carry their audio, andGraineCallTransport.auto, the default, takes WebRTC in a build that has it — see GraineCallTransport. - What the customer notices. On a weak or changing network the agent's voice holds up instead of stalling and catching up: a jitter buffer, loss concealment and the platform's echo canceller. The call is prepared at the tap — or while a ring is showing — so it connects as fast as before. The agent's voice arrives at telephone bandwidth over WebRTC today: steadier through a weak network, narrower than the WebSocket's on a perfect one.
- When WebRTC cannot set up a call — a network that blocks it, a server that turns it down, no answer within the time allowed (about 12 seconds in all) — the call continues on the WebSocket inside the same call: no second ring, no new call screen, no error; "Connecting…" shows a moment longer. A call the agent cannot take at all (no credit left, the agent switched off) ends with that reason, exactly as without WebRTC. Once audio flows, a call never moves: a network drop is retried once, then the call ends as dropped. The snapshot says which one carried each call, and why:
GraineCallSnapshot.transportandGraineCallSnapshot.transportFallbackReason. - The dashboard's switch. The agent's In-app call audio setting (agent → Calls & scheduling): WebRTC (recommended) or Standard. Standard moves every install's calls back to the WebSocket, whatever the app chose, from each app's next start — no app release. (The voice bar's own in-app call has its own setting:
GraineConfig.transportand the agent's Call audio.) - Size. A prebuilt WebRTC library — Google's WebRTC, its symbols renamed so it never clashes with another copy in the app (flutter_webrtc, a video-calling SDK). On an iPhone (arm64), about 12 MB more installed and about 6 MB more to download. On Android, per phone (an app bundle delivers one ABI): about 7.4 MB installed on 64-bit ARM (about 2.5–3.3 MB to download), 4.3 MB on 32-bit ARM, 8.2–8.4 MB on x86, and about 0.5 MB of classes.
- One version of the library. CocoaPods installs one version of this WebRTC build: if another plugin in the app pins it at a different version, the two cannot be installed together. Leave WebRTC off (calls stay on the WebSocket) or align the versions.
- Permissions. Android: the plugin adds
ACCESS_NETWORK_STATEto your manifest — a normal permission, granted at install: nothing is asked — and its R8 rules ship inside it. iOS: nothing new. - Licences. WebRTC is BSD 3-Clause, with Google's patent grant: list it in your app's open-source licences.
Which one carried a call, read once it is active:
Install and the first answer
Configure each agent once, at launch, with its publishable key; place GraineEngine once, above your navigator; the agent's settings (its session: design, identity, memory and booking rules) then arrive by themselves. Everything else on this page goes through the agent init returns. Readiness: loadSession() completes when the settings are in, and GraineConnectivity says whether the page that carries the voice call is there.
GraineInApp.init
Call it once at launch, before runApp, to configure an agent with its publishable key — every other call on this page goes through the agent it returns.
Configures an agent and starts fetching its configuration at once. Call it before runApp or in your first widget; it initialises the Flutter binding itself. Without a name it is the default agent. The name is trimmed, and an empty name is the default agent. A later call with a name already configured returns that agent unchanged (the new config is not applied).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
config | GraineConfig | required | The configuration (see its type). |
name | String | defaultName | The agent's name in your app — the one it was configured under; the default agent when it is left out or empty. |
Returns — a new GraineInApp.
Errors — none.
GraineInApp
Use it to reach an agent you configured — its call, chat, components, session and design — and to make every request your app sends Graine on the customer's behalf.
The in-app agent: one instance per publishable key, configured with GraineInApp.init(config) before runApp and reached afterwards as GraineInApp.instance (or GraineInApp.named('support') for an agent configured under a name). Accessing instance before init throws StateError. It is a WidgetsBindingObserver. Use it on the main (UI) isolate only.
What to expect — The SDK's entry point, configured once at launch; everything else goes through it, or through the agent you name. A request to Graine made before the agent's settings have loaded waits for them.
| Property | Type | Meaning |
|---|---|---|
static const String defaultName = 'default' | String | The name of the default agent: the one init configures when given no name, which instance returns and every view draws unless handed another. |
static Map<String, GraineInApp> get all | Map<String, GraineInApp> | All the agents you have configured, keyed by name and listed in configuration order. Unmodifiable. |
static GraineInApp get instance | GraineInApp | The default agent: the one configured without a name, or, in an app that named every agent, the first one configured. |
static GraineInApp? get maybeInstance | GraineInApp? | The default agent, or null before init. Use it to ask whether the SDK has been configured. |
@visibleForTesting static GraineInApp forTesting(GraineConfig config, {http.Client? httpClient, int Function()? clock, bool install = false, String name = defaultName, Directory? fontCacheDir, Future<void> Function(String name, Uint8List bytes)? fontRegistrar, GraineChatConnector? chatConnector}) | GraineInApp | For tests only: an instance with an injected HTTP client, clock, font cache directory, font registrar and chat connector, and no lifecycle observer. With install: true it joins the app's agents under name; otherwise it shares nothing with them. |
@visibleForTesting static void resetForTesting() | nothing | For tests only: forgets every agent and what they share, disposing each. |
final GraineConfig config | GraineConfig | The configuration this agent was initialised with. |
final String name | String | The name this agent was configured under; defaultName for the default agent. |
late final GraineVoice voice | GraineVoice | This agent's voice call. GraineEngine attaches it; voice.start() places a call. |
late final GraineComponents components | GraineComponents | The components the agent draws (from the call or the chat), as state a GraineWidgetView renders. |
GraineChatSession get chat | GraineChatSession | This agent's text chat, on its own connection; created on first use. GraineAgentBar and GraineChat open it while the customer is in it and close it when they leave; an app drawing its own chat calls open() and close() itself. Opening it also ends a call with any other agent and closes that agent's chat. |
Future<String> get installId | Future<String> | This install's id: a UUID made on the app's first launch and kept by the platform (the Keychain on iOS, surviving reinstalls; storage excluded from backups on Android). The native call engine sends this same id, and every agent shares it. Graine uses it to count a user's devices, and it is never shown to the agent. Where there is no platform side (a test, a desktop build) it is a random UUID kept in memory for the run. |
bool get bookingAvailable | bool | Whether this customer can book a call from here — show your own "Call me" button only then. See bookingAvailable. |
GraineErrorCode? get bookingBlocker | GraineErrorCode? | Why booking is not available (schedulingOff or identityRequired), or null when it is. |
String? get deviceTimezone | String? | The device's time zone (IANA, "Asia/Kolkata") once the SDK has read it; null before then. |
ValueListenable<bool> get bookingListenable | ValueListenable<bool> | Exposes bookingAvailable as a listenable, so a widget can redraw whenever it changes. |
GraineSchedulingRules get schedulingRules | GraineSchedulingRules | What the agent lets users book, and how Graine rings, from the agent's configuration. No request. Before the configuration loads, and from a server that says nothing, the defaults — which allow no booking. |
FrictionRules get frictionRules | FrictionRules | The friction rules in force now: the defaults, the dashboard's, then the app's. |
Map<String, Object?>? get pendingWidget | Map<String, Object?>? | The component the agent drew that is still waiting to be answered, as Graine sent it, so a view mounted later can still draw it. Answering or dismissing it clears it, and so does the start of a new call. |
SessionConfig? get session | SessionConfig? | What the dashboard says about this agent; null until it has loaded. |
ValueListenable<SessionConfig?> get sessionListenable | ValueListenable<SessionConfig?> | The session, for a widget that rebuilds when it arrives. |
ResolvedDesign? get design | ResolvedDesign? | The design the brand chose in the dashboard, with both token sets. It is null before the session has loaded, and also when the server is too old to send designs. |
ThemeTokens? get tokens | ThemeTokens? | The tokens to use at this moment: the brand's fixed scheme if it has one, otherwise the device's light or dark set, chosen again whenever the device switches between them. Null without a design. For an app drawing its own UI; the SDK's widgets pick for themselves. |
ValueListenable<ThemeTokens?> get tokensListenable | ValueListenable<ThemeTokens?> | The tokens, for a widget that rebuilds when they change. |
@override void didChangePlatformBrightness() | nothing | Lifecycle callback: the device switched between light and dark, so the tokens are picked again. Called by Flutter; apps do not call it. |
ValueListenable<Map<String, String>> get fontFaces | ValueListenable<Map<String, String>> | The design's typefaces the SDK has loaded: family|weight (the design's family at the weight it really has) → the family name the face is registered under, for example "DM Sans|700" → "Graine-DMSans-700". Empty until one loads, and for "system", which is never fetched. To draw your own UI in the brand's typeface, set fontFamily to the registered name with FontWeight.normal: a loaded face is its weight. |
bool get foreground | bool | True when the app's most recent lifecycle report put it in the foreground. |
@override void didChangeAppLifecycleState(AppLifecycleState state) | nothing | Lifecycle callback: resumed is the foreground; inactive is ignored (iOS reports it for the app switcher, a pulled-down notification and the microphone permission dialog); anything else is the background. Called by Flutter; apps do not call it. |
@visibleForTesting void setForegroundForTesting(bool foreground) | nothing | For tests only: what the lifecycle callback calls. |
@visibleForTesting void dispose() | nothing | For tests only: stops every timer, detaches the engine, closes the chat and removes the agent from the app's agents. An app keeps its agents for its lifetime. |
Its functions: init, loadSession, identify, installId, setMemory, memoryEnabled, memories, forgetMemory, named, all, instance, maybeInstance, defaultName, name, setVariables, currentVariables, setScreen, updateField, removeField, clearScreen, track, tap, captureTap, noteInteraction, registerAction, checkActions, executeAction, configureFriction, clearPendingWidget, bookingAvailable, bookingBlocker, bookingListenable, deviceTimezone, schedulingRules, scheduleCall, scheduledCalls, cancelScheduledCall, loadDesignFonts, addListener, removeListener — each with its parameters, what it returns, the errors it raises and an example.
GraineInApp.loadSession
Call it when you need the agent's settings (design, identity, memory, booking rules) before the SDK has fetched them on its own, or to try again after a fetch failed.
Fetches the agent's configuration once; concurrent callers share one request, and a failure is retried by the next caller. Completes with null on failure, which is also reported through GraineListener.onError. init calls it.
Parameters — none.
Returns — Future<SessionConfig?> — its fields: SessionConfig. Example value: null.
Errors — none.
GraineConfig
Use it to say, once, which agent the app talks to and how: the publishable key, your build's prompt variables, fonts, timing and switches.
Everything the SDK needs up front, passed to GraineInApp.init. Immutable.
What to expect — Made once, at launch, before anything else. Optional fields have the defaults shown; nothing in it is sent to Graine except what the descriptions say.
| Field | Type | Default | Meaning |
|---|---|---|---|
final String baseUrl | String | required | "https://www.graine.ai" unless self-hosted. |
final String publishableKey | String | required | From Agent → Embed & Widgets. Selects the agent. It is not a secret and cannot place a call on its own: add app:// to that agent's Allowed domains, or every request is refused. |
final Map<String, Object?> variables | Map<String, Object?> | empty | Prompt variables known at build time. The dashboard's defaults sit under them; setVariables and identify win over them. Unlike runtime variables and traits, the SDK does not mask these. |
final Transport? transport | Transport? | null | Forces a transport. Null lets the dashboard's Call audio setting decide. |
final String? appVersion | String? | null | Lands on the call record and in the screen context, to tell builds apart. |
final bool endOnBackground | bool | true | Ends a live call, and hangs up a connected chat, once the app has been in the background for two seconds (a moment away, such as a permission dialog, does not count). The chat reconnects when the app returns, if the customer is still in it. You want it on. |
final GraineTiming timing | GraineTiming | GraineTiming() | The page-load watchdog, retry ladder, end-call watchdog and "Still connecting…" threshold. |
final bool debug | bool | false | Logs, prefixed "[Graine]", every message across the engine bridge both ways, the chat's frames and the engine page's console. Outgoing variables and screen context are logged by key names and screen id only; incoming messages are logged as received, cut to 600 characters. Turn it on in debug builds. |
final FrictionConfig? friction | FrictionConfig? | null | This app's layer of friction rules, over the dashboard's. Most apps set nothing here. |
final Future<bool> Function()? requestMicrophone | Future<bool> Function()? | null | Makes sure the app holds the microphone before a call opens; this package has no permission plugin of its own, so pass the one the app already uses (for example () async => (await Permission.microphone.request()).isGranted). Called by GraineVoice.start() — and so by the bar's microphone button and GraineLauncher — before the call is placed. false: no call is opened and onMicDenied("NotAllowedError") is reported. If it throws, the error is logged and the call is attempted anyway. Null: the SDK assumes the app asked already; if it did not, the engine reports the refusal. |
final List<String> fonts | List<String> | empty | The font families the app bundles itself, by the family name its pubspec declares. The SDK fetches the brand's typeface by itself; a family listed here is the app's own copy, wins over the download and is never fetched. Empty: the SDK fetches every family the design uses, drawing the platform font until each arrives. |
final bool captureTaps | bool | true | Tells the agent what the customer taps while a screen is set: a tap on a control with an accessibility label (Semantics(label: …)) as "tap:<label>", anywhere else as "tap:screen" with the position — in the recent events, at most two a second, masked like everything else. GraineEngine (given a child) sees the taps. |
final GraineChatSize? chatSize | GraineChatSize? | null | How big the chat window opens, over the dashboard's Window size: compact above the bar, large a sheet over most of a phone (a panel on a tablet), full the whole screen. Null follows the dashboard; a size passed to GraineChat.open wins for that open. |
Its functions: GraineConfig — each with its parameters, what it returns, the errors it raises and an example.
GraineConfig.GraineConfig
Use it to build the configuration you pass to GraineInApp.init.
The constructor.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
baseUrl | String | required | "https://www.graine.ai" unless self-hosted. |
publishableKey | String | required | From Agent → Embed & Widgets. Selects the agent. It is not a secret and cannot place a call on its own: add app:// to that agent's Allowed domains, or every request is refused. |
variables | Map<String, Object?> | const <String, Object?>{} | Prompt variables known at build time. The dashboard's defaults sit under them; setVariables and identify win over them. Unlike runtime variables and traits, the SDK does not mask these. |
transport | Transport? | optional | Forces a transport. Null lets the dashboard's Call audio setting decide. |
appVersion | String? | optional | Lands on the call record and in the screen context, to tell builds apart. |
endOnBackground | bool | true | Ends a live call, and hangs up a connected chat, once the app has been in the background for two seconds (a moment away, such as a permission dialog, does not count). The chat reconnects when the app returns, if the customer is still in it. You want it on. |
timing | GraineTiming | const GraineTiming() | The page-load watchdog, retry ladder, end-call watchdog and "Still connecting…" threshold. |
debug | bool | false | Logs, prefixed "[Graine]", every message across the engine bridge both ways, the chat's frames and the engine page's console. Outgoing variables and screen context are logged by key names and screen id only; incoming messages are logged as received, cut to 600 characters. Turn it on in debug builds. |
friction | FrictionConfig? | optional | This app's layer of friction rules, over the dashboard's. Most apps set nothing here. |
requestMicrophone | Future<bool> Function()? | optional | Asks for the microphone before a call opens and answers whether the app holds it — pass the permission call your app already uses, for example () async => (await Permission.microphone.request()).isGranted. Null: the SDK assumes you asked. |
fonts | List<String> | const <String>[] | The font families the app bundles itself, by the family name its pubspec declares. The SDK fetches the brand's typeface by itself; a family listed here is the app's own copy, wins over the download and is never fetched. Empty: the SDK fetches every family the design uses, drawing the platform font until each arrives. |
captureTaps | bool | true | Tells the agent what the customer taps while a screen is set: a tap on a control with an accessibility label (Semantics(label: …)) as "tap:<label>", anywhere else as "tap:screen" with the position — in the recent events, at most two a second, masked like everything else. GraineEngine (given a child) sees the taps. |
chatSize | GraineChatSize? | optional | How big the chat window opens, over the dashboard's Window size: compact above the bar, large a sheet over most of a phone (a panel on a tablet), full the whole screen. Null follows the dashboard; a size passed to GraineChat.open wins for that open. |
Returns — a new GraineConfig.
Errors — none.
GraineTiming
Use it to change how long the SDK waits for the voice engine and a connect before it retries or says so — only for an app used on very slow networks.
Load and connect timing, for an app used on very slow networks. Passed as GraineConfig.timing; all values in milliseconds.
What to expect — Made once, at launch, before anything else. Optional fields have the defaults shown; nothing in it is sent to Graine except what the descriptions say.
| Field | Type | Default | Meaning |
|---|---|---|---|
final int stallMs | int | 15000 | Silence — nothing downloaded — before a page load is given up on and retried. |
final int bootMs | int | 15000 | Downloaded but still not ready after this long: the page is broken, not slow. |
final int hardCapMs | int | 120000 | The ceiling on one load attempt, however steadily it is arriving. |
final List<int> retryDelaysMs | List<int> | 1, 2, 4, 8, 15, 15 s | The whole retry ladder, each delay jittered by ±25%. The SDK reloads once per entry in the list; after the last one it stops trying and reports GraineConnectivity.failed. The chat's reconnect backoff uses the same ladder. |
final int endWatchdogMs | int | 4000 | The time the SDK waits for an end-call to be confirmed before it tears the call down on the device itself. |
final int slowConnectMs | int | 4000 | How long a connect the customer is waiting on runs before slowConnect turns true ("Still connecting…"). |
Its functions: GraineTiming — each with its parameters, what it returns, the errors it raises and an example.
GraineTiming.GraineTiming
Use it to build the timing you pass as GraineConfig(timing:).
The constructor.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
stallMs | int | 15000 | Silence — nothing downloaded — before a page load is given up on and retried. |
bootMs | int | 15000 | Downloaded but still not ready after this long: the page is broken, not slow. |
hardCapMs | int | 120000 | The ceiling on one load attempt, however steadily it is arriving. |
retryDelaysMs | List<int> | const <int>[1000, 2000, 4000, 8000, 15000, 15000] | The whole retry ladder, each delay jittered by ±25%. The SDK reloads once per entry in the list; after the last one it stops trying and reports GraineConnectivity.failed. The chat's reconnect backoff uses the same ladder. |
endWatchdogMs | int | 4000 | The time the SDK waits for an end-call to be confirmed before it tears the call down on the device itself. |
slowConnectMs | int | 4000 | How long a connect the customer is waiting on runs before slowConnect turns true ("Still connecting…"). |
Returns — a new GraineTiming.
Errors — none.
GraineEngine
Use it to carry an agent's voice call: place it once near the root, above your navigator, so a call outlives every screen and starts at once.
class GraineEngine extends StatefulWidget
What to expect — Place it once, near the root, above your navigator — one per agent the customer can call. It is one invisible pixel; it loads the agent's page idle at mount, so a tap starts a call at once, and it tells the agent what the customer taps while a screen is set (GraineConfig.captureTaps).
| Property | Type | Meaning |
|---|---|---|
final Widget? child | Widget? | Your app — usually the navigator's child in MaterialApp.builder. The engine itself is one invisible pixel beside it. |
final GraineVoice? voice | GraineVoice? | The call to attach. |
final GraineInApp? app | GraineInApp? | The agent whose calls this engine carries. |
Its functions: GraineEngine — each with its parameters, what it returns, the errors it raises and an example.
GraineEngine.GraineEngine
Use it to place the engine for the default agent — or, with app:, for another agent the customer can call.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
child | Widget? | optional | Your app — usually the navigator's child in MaterialApp.builder. The engine itself is one invisible pixel beside it. |
voice | GraineVoice? | optional | The call to attach. |
app | GraineInApp? | optional | The agent whose calls this engine carries. |
Returns — a new GraineEngine.
Errors — none.
SessionConfig
Read it to see what the dashboard says about this agent — its appearance, design, actions, identity, memory and call settings — once the session has arrived.
class SessionConfig
What to expect — Fetched once per launch when the agent is configured, and kept for the run; null until it arrives (GraineInApp.session). A setting the server does not send is null, and the SDK then behaves as before that setting existed.
| Property | Type | Meaning |
|---|---|---|
final String agentId | String | The agent's id in Graine — the one the publishable key selects. |
final String webcallAgentId | String | The id calls are placed and filed under. Place calls with it, not agentId — or their transcripts land under an agent nobody watches. |
final Map<String, Object?> appearance | Map<String, Object?> | The settings from Embed & Widgets → Appearance, unchanged from how they are stored. |
final Map<String, Object?> variables | Map<String, Object?> | The dashboard's variable defaults. |
final String? pageVersion | String? | The id of the deployment, which the engine page is cached under. |
final Set<String> declaredActions | Set<String> | The in-app actions the dashboard declares. |
final Map<String, Object?>? friction | Map<String, Object?>? | The dashboard's friction rules, as served. |
final ResolvedDesign? design | ResolvedDesign? | The design the brand chose, already resolved into light and dark tokens. Null for an agent with no design: every surface then draws from appearance. |
final String? wsHost | String? | The host the chat socket connects to when it has no ticket. |
final IdentitySetting? identity | IdentitySetting? | Which trait identifies a customer. Null when the settings do not say, which means user_id (see identitySetting). |
final MemorySetting? memory | MemorySetting? | The agent's memory setting, or null when an older server leaves it out. |
final CallsSetting? calls | CallsSetting? | Hosted ringing and the booking rules for users, or null when an older server leaves it out. |
IdentitySetting get identitySetting | IdentitySetting | The identity setting, or the one that applies when the server does not send it. |
Transport get preferredTransport | Transport | The dashboard's Call audio setting. |
String? get accent | String? | The accent colour saved in the dashboard, unchanged — the leading "#" may be missing. |
Its functions: SessionConfig, fromJson, errorFor — each with its parameters, what it returns, the errors it raises and an example.
SessionConfig.SessionConfig
Use it to build a session by hand for a test or a preview; the SDK fetches the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
agentId | String | required | The agent's id in Graine — the one the publishable key selects. |
webcallAgentId | String | required | The id calls are placed and filed under. Place calls with it, not agentId — or their transcripts land under an agent nobody watches. |
appearance | Map<String, Object?> | const <String, Object?>{} | The settings from Embed & Widgets → Appearance, unchanged from how they are stored. |
variables | Map<String, Object?> | const <String, Object?>{} | The dashboard's variable defaults. |
pageVersion | String? | optional | The id of the deployment, which the engine page is cached under. |
declaredActions | Set<String> | const <String>{} | The in-app actions the dashboard declares. |
friction | Map<String, Object?>? | optional | The dashboard's friction rules, as served. |
design | ResolvedDesign? | optional | The design the brand chose, already resolved into light and dark tokens. Null for an agent with no design: every surface then draws from appearance. |
wsHost | String? | optional | The host the chat socket connects to when it has no ticket. |
identity | IdentitySetting? | optional | Which trait identifies a customer. Null when the settings do not say, which means user_id (see identitySetting). |
memory | MemorySetting? | optional | The agent's memory setting, or null when an older server leaves it out. |
calls | CallsSetting? | optional | Hosted ringing and the booking rules for users, or null when an older server leaves it out. |
Returns — a new SessionConfig.
Errors — none.
SessionConfig.fromJson
Use it to read a session from the JSON Graine sends — for a session you stored, or a test; the SDK does this itself when it loads.
Reads the session as Graine sends it, the same way every Graine SDK reads it; anything missing takes its default.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | Map<String, Object?> | required | The session as Graine sent it, decoded from JSON. |
Returns — SessionConfig.
Errors — none.
SessionConfig.errorFor
Use it to turn a refused session request into the sentence that tells whoever has to fix it what to change.
For a refused session request, a sentence aimed at the person who has to fix it; for a 2xx response, null.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
status | int | required | The HTTP status of the session request. |
body | Map<String, Object?> | required | Its body, decoded from JSON ({} when it was not JSON). |
Returns — String?. Example value: 'Publishable key was rejected. Check it against Embed & Widgets in the dashboard.'.
Errors — none.
GraineConnectivity
Read it to know whether the page that carries the voice call is there — loading, ready, retrying or failed — and to offer a retry when it failed.
enum GraineConnectivity { loading, ready, retrying, failed }
What to expect — loading at launch and after retry(); ready once the page has loaded; retrying while a failed load waits for its next attempt (the bar says "Reconnecting…"); failed once every attempt in GraineTiming.retryDelaysMs is spent, or the agent's settings could not be loaded (the bar says "Couldn't load · tap to retry"). onConnectivity reports every change. A page that is carrying a call is never reloaded.
| Case | Meaning |
|---|---|
loading | The page that carries the call is loading. |
ready | It has loaded: a call can start at once. |
retrying | A load failed; the next attempt is scheduled. |
failed | Every attempt failed. Offer "Try again" (retry()). |
Identity, memory and conversations that continue
Tell the agent who the customer is, let them choose whether they are remembered, show them what is remembered and delete it, and start a conversation over. An identified customer who comes back — later today, or on their other phone — finds the chat where they left it, and the agent picks up from there. Nothing here is needed for an anonymous customer: they simply start fresh every time.
GraineInApp.identify
Call it when the customer signs in — and with null when they sign out — so the agent knows who it is talking to and can remember them between conversations.
Who is signed in. Traits become prompt variables, masked on the device, and land on the call record — except the one trait the agent's Identity setting names (user_id unless it names email, phone or a custom trait), which is kept raw and sent only where Graine needs it to recognise the user, never as a prompt variable or in the screen context. A placeholder (such as "guest", "null" or an already-masked "[EMAIL]"), null, a boolean or a fraction identifies nobody: that conversation is anonymous, with no memory. memory: false: this user's conversations are neither remembered nor recalled; the choice is kept on the device for this user, and when left out their last choice stands (on until they make one). A conversation keeps the identity it started with; a change applies from the next conversation. null signs out: Graine is told this device is no longer the user's, a chat open for them ends and its transcript is cleared, and later conversations are anonymous. A different user signing in without a sign-out first signs the previous one out the same way. One user for the whole app: every agent the app configured hears it (each keeps the trait its own Identity setting names), and the native call engine receives it too.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
traits | Map<String, Object?>? | required | Who the customer is. The trait your agent's Who is the user? field names (user_id unless you chose email, phone or a custom field) identifies them; every other trait becomes a prompt variable, masked on the device. nil / null signs out. |
memory | bool? | optional | false: this customer's conversations are neither remembered nor recalled (kept on the device for them). Left out: their last choice stands — on until they make one. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.installId
Read it when you need this install's id — the one the SDK and the native call engine send Graine for this device, the same for every agent.
This install's id: a UUID made on the app's first launch and kept by the platform — in the Keychain on iOS, where it survives a reinstall, and in storage excluded from backups on Android. The native call engine sends the same id, and every agent shares it. Graine counts a customer's devices by it (Devices per user in the dashboard); identify ties it to the customer, and identify(null) lets it go.
Parameters — none.
Returns — Future<String> — a lower-case UUID. Example value: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44'.
Errors — none.
GraineInApp.setMemory
Call it when the customer turns "remember me" on or off in your app's settings.
Turns remembering on or off for the current user's conversations; it does what identify(currentTraits, memory: enabled) does. Kept on the device for that user (for an anonymous user, for this run only). Applies to every agent and reaches the native call engine.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | required | true to remember this customer's conversations; false to stop. Kept on the device for them. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.memoryEnabled
Call it to read the customer's memory choice — to show your settings switch in the right position.
The current user's memory choice: true unless they turned it off. Waits for the agent's configuration and the choices kept on the device.
Parameters — none.
Returns — Future<bool>. Example value: true.
Errors — none.
GraineInApp.memories
Call it to show the signed-in customer what the agent remembers about them.
What this agent remembers about the identified user, already redacted, in Graine's order: newest first, at most 100. For a "what you remember about me" screen. Only from a device that is theirs.
Parameters — none.
Returns — Future<List<GraineMemory>> — its fields: GraineMemory. Example value: [GraineMemory(id: 'm_41', text: 'Prefers a call after 6 pm', createdAt: 2026-10-02 09:14:00.000Z, updatedAt: 2026-10-12 17:40:00.000Z)].
Errors — GraineException: identityRequired (checked on the device first), deviceLimit, rateLimited, unavailable, invalidKey, originRefused, network, unknown
GraineInApp.forgetMemory
Call it when the customer asks the agent to forget them: it deletes everything the agent remembers about the signed-in customer.
Deletes everything this agent's memory holds about the identified user. Allowed only from a device that is theirs. Completes with the number deleted (0 when Graine does not say).
Parameters — none.
Returns — Future<int> — how many memories were deleted. Example value: 3.
Errors — GraineException: identityRequired (checked on the device first), deviceLimit, rateLimited, unavailable, invalidKey, originRefused, network, unknown
GraineChatSession.newConversation
Call it when the customer wants to start over: a fresh conversation with the welcome and the starters, while what the agent remembers about them stays.
Starts a new conversation — a fresh thread, as a support chat offers one.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineMemory
Read it to show one thing the agent remembers about the signed-in customer.
class GraineMemory
What to expect — From memories(): newest first, at most 100, already redacted. Only for the identified customer, from one of their devices. The dates are null when Graine did not say; they are moments in UTC — show them in the device's time zone.
| Property | Type | Meaning |
|---|---|---|
final String id | String | Graine's id for this memory. Use it as the key of a list row. |
final String text | String | What is remembered, in a sentence. |
final DateTime? createdAt | DateTime? | The UTC time the memory was first stored, or null if the server leaves it out. |
final DateTime? updatedAt | DateTime? | The UTC time of its latest change, or null if the server leaves it out. |
Its functions: GraineMemory, fromJson, listFrom, toJson — each with its parameters, what it returns, the errors it raises and an example.
GraineMemory.GraineMemory
Use it to build a memory by hand for a test or a preview; memories() returns the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | Graine's id for this memory. Use it as the key of a list row. |
text | String | required | What is remembered, in a sentence. |
createdAt | DateTime? | optional | The UTC time the memory was first stored, or null if the server leaves it out. |
updatedAt | DateTime? | optional | The UTC time of its latest change, or null if the server leaves it out. |
Returns — a new GraineMemory.
Errors — none.
GraineMemory.fromJson
Use it to read one memory from JSON you stored; memories() already returns them read.
Returns null for anything other than a memory that has an id and some text.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The value as decoded from JSON; anything that is not the expected object reads as null. |
Returns — GraineMemory?. Example value: GraineMemory(id: 'm_41', text: 'Prefers a call after 6 pm', createdAt: 2026-10-02 09:14:00.000Z, updatedAt: 2026-10-12 17:40:00.000Z).
Errors — none.
GraineMemory.listFrom
Use it to read a list of memories from an answer you stored or forwarded, newest first.
{memories: [...]} (or a bare list), in Graine's order — newest first. Entries that are not memories are skipped.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | Object? | required | The answer's body as decoded: {memories: [...]} or a bare list. |
Returns — List<GraineMemory>. Example value: [GraineMemory(id: 'm_41', text: 'Prefers a call after 6 pm', createdAt: 2026-10-02 09:14:00.000Z, updatedAt: 2026-10-12 17:40:00.000Z)].
Errors — none.
GraineMemory.toJson
Use it to turn a memory into JSON — to cache it or hand it to your own server.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
IdentitySetting
Read it to know which trait identifies a customer for this agent (user_id unless the dashboard names another) and how many devices each customer may use.
class IdentitySetting
What to expect — Part of the session; null until it arrives, and from an agent that does not say — which means user_id and 2 devices.
| Property | Type | Meaning |
|---|---|---|
final String field | String | The trait Graine uses to recognise a user: user_id, email, phone, or the name of a custom trait. |
final int devicesPerUser | int | The most devices a single user can have at once, from 1 to 5. |
static const IdentitySetting standard | IdentitySetting | The setting assumed when an older server sends none: identify by the user_id trait. |
Its functions: IdentitySetting, fromJson — each with its parameters, what it returns, the errors it raises and an example.
IdentitySetting.IdentitySetting
Use it to build the identity setting by hand for a test; the session carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
field | String | Identity.defaultField | The trait Graine uses to recognise a user: user_id, email, phone, or the name of a custom trait. |
devicesPerUser | int | 2 | The most devices a single user can have at once, from 1 to 5. |
Returns — a new IdentitySetting.
Errors — none.
IdentitySetting.fromJson
Use it to read the identity setting from the session's JSON.
Null when raw is not an object — the settings did not say.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The value as decoded from JSON; anything that is not the expected object reads as null. |
Returns — IdentitySetting?. Example value: null.
Errors — none.
MemorySetting
Read it to know whether the agent remembers identified customers between conversations.
class MemorySetting
What to expect — Part of the session; null until it arrives, and from an agent that does not say — which means memory off.
| Property | Type | Meaning |
|---|---|---|
final bool enabled | bool | True when the agent carries its memory of identified users from one conversation into the next. |
Its functions: MemorySetting, fromJson — each with its parameters, what it returns, the errors it raises and an example.
MemorySetting.MemorySetting
Use it to build the memory setting by hand for a test; the session carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | false | True when the agent carries its memory of identified users from one conversation into the next. |
Returns — a new MemorySetting.
Errors — none.
MemorySetting.fromJson
Use it to read the memory setting from the session's JSON.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The value as decoded from JSON; anything that is not the expected object reads as null. |
Returns — MemorySetting?. Example value: null.
Errors — none.
Identity
Use it to check on the device what the SDK treats as a customer's identity: which trait, which values identify nobody, and what is sent with a request.
abstract final class Identity
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
static const String defaultField | String | The trait that identifies a customer when the agent's setting names none: 'user_id'. |
static const Set<String> placeholders | Set<String> | Values that identify nobody, compared case-insensitively after trimming: empty, null, undefined, none, nil, nan, unknown, anonymous, anon, guest, 0, -, n/a, na, test, and the SDK's own masks ([phone], [email], [card] and the other ID masks). An app that hands over an already-masked value has identified no one. |
static const int maxValueLength | int | The longest an identifier the servers key on can be (a user id or custom trait has at most 256 characters); a longer value is never sent. |
Its functions: normaliseField, valueOf, pick, normaliseInstallId, normaliseTimezone, uuidV4, serverLowercase, serverTrim, normaliseValue, memoryKey, withoutIdentity, requestFields — each with its parameters, what it returns, the errors it raises and an example.
Identity.normaliseField
Use it to turn a trait name into the form the identity setting stores — or to learn that it is not a valid trait name.
A trait name as the setting stores it: trimmed, lower case, and matching ^[a-z][a-z0-9_]{0,39}$ — else null.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
field | Object? | required | A trait name as the dashboard may hold it. |
Returns — String?. Example value: 'customer_id'.
Errors — none.
Identity.valueOf
Use it to read one trait's value the way the SDK sends it as an identity — or learn that it identifies nobody.
Returns one trait in the raw form the identity channel sends, or null for a value that identifies nobody: null, a boolean, a fraction, an object or a list, a placeholder, or anything longer than maxValueLength.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
v | Object? | required | One trait's value, as the app passed it to identify. |
Returns — String?. Example value: null (a placeholder identifies nobody).
Errors — none.
Identity.pick
Use it to find the identity among a customer's traits for the agent's identity trait.
The identity in traits for the setting's field: the trait under exactly that name, else one whose name normalises to it (Customer_ID for customer_id).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
traits | Map<String, Object?>? | required | The customer's traits, as passed to identify. |
field | String | required | The trait that identifies a customer — IdentitySetting.field. |
Returns — String?. Example value: 'u_8812'.
Errors — none.
Identity.normaliseInstallId
Use it to check that an install id is in the shape the SDK sends.
An install id this SDK will send: lower case and matching ^[0-9a-f-]{16,64}$ — else null.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | Object? | required | An install id, as stored. |
Returns — String?. Example value: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44'.
Errors — none.
Identity.normaliseTimezone
Use it to check that a time zone name is one the SDK sends (an IANA name such as Asia/Kolkata).
Returns an IANA zone name that Graine's servers accept, such as Asia/Kolkata or UTC, or null.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
zone | Object? | required | A time zone name, as the device reports it. |
Returns — String?. Example value: 'Asia/Kolkata'.
Errors — none.
Identity.uuidV4
Use it to make a random version-4 UUID, the shape of an install id.
Makes a random lower-case UUIDv4, used as the install id where the platform cannot supply one (a test or a desktop build).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
random | math.Random? | optional | The randomness to use; a secure random generator when left out. A test passes a seeded one. |
Returns — String. Example value: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44'.
Errors — none.
Identity.serverLowercase
Use it to lower-case text exactly as Graine does when it compares identities.
Lower-cases text exactly as Graine does when it compares identities — including the full mapping of U+0130 ("İ" → "i̇") and the final sigma ("ΟΔΟΣ" → "οδος"), which Dart's toLowerCase() does not apply.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String | required | The text to lower-case. |
Returns — String. Example value: 'asha@example.com'.
Errors — none.
Identity.serverTrim
Use it to trim whitespace exactly as Graine does when it compares identities.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String | required | The text to trim. |
Returns — String. Example value: 'u_8812'.
Errors — none.
Identity.normaliseValue
Use it to see how Graine reads an identity value for a trait — trimmed, and lower case for an email — before it compares it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
field | String | required | The identity trait the value belongs to (user_id, email, phone or a custom trait). |
value | Object? | required | The trait's value, as the app passed it. |
Returns — String?. Example value: 'asha@example.com'.
Errors — none.
Identity.memoryKey
Use it to compute the key the customer's memory choice is kept under on this device.
The key one customer's memory choice is kept under on the device, the same on every Graine SDK: the first 16 bytes of the SHA-256 of graine:memory:v1, a newline, the trait, a newline and the normalised value, as hex. Nothing about the customer can be read back from it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
field | String | required | The identity trait. |
value | String | required | The customer's identity value for that trait. |
Returns — String. Example value: 32 hex characters, e.g. '3f2a…'.
Errors — none.
Identity.withoutIdentity
Use it to take the identity trait out of a set of traits — what the SDK does before traits become prompt variables.
traits without the trait that identifies the customer — that one travels only with the identity, never as a prompt variable or in the screen context.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
traits | Map<String, Object?>? | required | The customer's traits, as passed to identify. |
field | String? | required | The identity trait to take out; null takes nothing out. |
Returns — Map<String, Object?>?. Example value: {'plan': 'gold'}.
Errors — none.
Identity.requestFields
Use it to build the identity fields the SDK adds to a request to Graine.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
value | String? | optional | The customer's identity value; null for an anonymous customer. |
installId | String | required | This install's id (GraineInApp.installId). |
memory | bool? | optional | The customer's memory choice; null when they made none. |
timezone | String? | optional | The device's IANA time zone; null when unknown. |
callId | String? | optional | The call this request belongs to; null outside a call. |
Returns — Map<String, Object?>.
Errors — none.
Chat
The agent's typed conversation: the same agent, screen context and actions as the call, in writing. GraineAgentBar offers and opens it for you; GraineChat places it yourself; for a chat of your own design, draw from GraineInApp.instance.chat (a GraineChatSession) and lay its rows out with ChatRows and ChatPieces. One conversation at a time: opening the chat ends a call the bar holds.
GraineChat
Use it to place the chat window yourself — a screen, a tab or a sheet of your own — in the agent's design.
class GraineChat extends StatefulWidget
What to expect — The agent's typed conversation. It connects while the customer is in the chat (open) and hangs up when they leave (close); a message typed while it is not connected is shown at once and sent when it is. Its state changes as the conversation moves: draw from it. Opening the chat ends a call the bar holds.
| Property | Type | Meaning |
|---|---|---|
final GraineChatState? chat | GraineChatState? | The chat to draw — your own GraineChatState; the agent's own chat (GraineInApp.chat) when null. |
final GraineComponents? components | GraineComponents? | The components to draw above the composer. |
final GraineInApp? app | GraineInApp? | The agent on the other side of this chat; the view uses that agent's chat, components, session and design. When left out: the agent that chat belongs to, or failing that the default agent. |
final ResolvedDesign? design | ResolvedDesign? | The design to draw. |
final String? scheme | String? | "light", "dark" or "auto". |
final String? accent | String? | #RRGGBB over the design's accent. |
final String? name | String? | The header's title; the design's chat title, else the dashboard's heading, when null. |
final VoidCallback? onClose | VoidCallback? | The chevron in the header — usually a pop. |
final bool showComponents | bool | Draw the components the agent shows. |
static const Key screenKey | Key | The whole screen. |
Its functions: GraineChat, open — each with its parameters, what it returns, the errors it raises and an example.
GraineChat.GraineChat
Use it to place the chat window where you want it; it opens the chat while it is on screen and closes it when it leaves.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
chat | GraineChatState? | optional | The chat to draw — your own GraineChatState; the agent's own chat (GraineInApp.chat) when null. |
components | GraineComponents? | optional | The components to draw above the composer. |
design | ResolvedDesign? | optional | The design to draw. |
scheme | String? | optional | "light", "dark" or "auto". |
accent | String? | optional | #RRGGBB over the design's accent. |
name | String? | optional | The header's title; the design's chat title, else the dashboard's heading, when null. |
onClose | VoidCallback? | optional | The chevron in the header — usually a pop. |
showComponents | bool | true | Draw the components the agent shows. |
app | GraineInApp? | optional | The agent on the other side of this chat; the view uses that agent's chat, components, session and design. When left out: the agent that chat belongs to, or failing that the default agent. |
Returns — a new GraineChat.
Errors — none.
GraineChat.open
Call it to open the chat now, at a size you choose for this once — on the agent's bar when one is on screen, else over your navigator.
Opens the chat at size for this open — over the app's size (GraineConfig.chatSize) and the dashboard's (Embed & Widgets → Appearance → Chat window → Window size). With the agent's bar on screen, the bar moves to the chat and draws it; with no bar, the chat shows over your navigator — a sheet, a tablet's panel or a screen of its own — and compact, which rides on the bar, opens as large.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
context | BuildContext | required | Where to open it: the agent's bar when one is on screen, else this context's navigator. |
app | GraineInApp? | optional | The configured agent to use — the default agent when left out. |
size | GraineChatSize? | optional | How big the chat opens this time: compact, large or full. Left out: the app's chatSize, then the agent's Window size. |
Returns — Future<void>, which completes when the chat closes.
Errors — none.
GraineChatSession
Use it to draw a chat of your own: the conversation, the connection and the customer's booked calls, as a ChangeNotifier you listen to.
class GraineChatSession extends ChangeNotifier implements GraineChatState, GraineChatConnection, GraineChatTyping
What to expect — GraineInApp.instance.chat (each agent has its own, created on first use). It connects while the customer is in the chat (open()) and hangs up when they leave (close()); a message typed while it is not connected is shown at once and sent when it is, and a dropped connection is made again with backoff (the GraineTiming.retryDelaysMs ladder) — reconnecting is true meanwhile — then, every try spent, stays offline (failed) until the customer sends something. An identified customer who comes back finds the conversation restored when it opens. It is a ChangeNotifier: listen to it and redraw. Opening the chat ends a call the bar holds. A conversation that starts with a ticket carries the prompt variables on its ticket — since 0.8.0 they are no longer added to that connection's address — and one without a ticket carries them in its address.
Everything it has — its own members, and those of the three interfaces it implements:
| Member | Type | What it is for |
|---|---|---|
void open() | void | Call it when the customer enters your chat screen: connect, and stay connected. |
void close() | void | Call it when they leave: hang up (the conversation stays). |
void send(String text) | void | Send the customer's message: shown at once, sent now or the moment the chat connects (and the chat connects for it). |
List<Caption> get messages | List<Caption> | The conversation as captions, oldest first — for a window that draws captions; turns says more. |
bool get connected | bool | True while the chat is connected; the header then reads "Online". |
bool get connecting | bool | True while the chat is connecting, either for the first time or again after losing its connection. |
bool get reconnecting | bool | The chat dropped — or a try to open it failed — while the customer is in it, and it is being made again: true from then until it connects, gives up (failed) or is closed, with connecting true too. Say "Reconnecting…", not "Offline", while it is. New in 0.9.0. |
bool get agentTyping | bool | The agent owes an answer and has not said a word of it yet: draw a typing bubble. |
GraineInApp get app | GraineInApp | The agent this chat is with. |
List<GraineChatTurn> get turns | List<GraineChatTurn> | The conversation so far, oldest first: one per message, with who, what, when, the customer's delivery, whether the agent volunteered it, and the component it drew. |
bool get failed | bool | Every reconnect was spent: the chat stays offline until the customer sends something, or open() is called again. |
String? get error | String? | The reason the most recent connection attempt failed, meant for logs; it becomes null once the chat connects. |
bool get isOpen | bool | The customer is in the chat (open() was called and close() was not). |
List<GraineScheduledCall> get upcomingCalls | List<GraineScheduledCall> | The customer's booked calls still to ring, soonest first — what the Upcoming calls card shows (it draws the first three). Read when the chat connects, after a booking or a cancel through the SDK, back in the foreground, and after the agent speaks (at most every 30 s). |
Its functions: newConversation, answerWidget, clear, refreshUpcoming, cancelUpcoming, cancelStateOf — each with its parameters, what it returns, the errors it raises and an example.
GraineChatSession.answerWidget
Call it when the customer answers a component the agent drew in the chat, if you draw components yourself.
Answers a component the agent drew in the chat: the structured answer, then summary as the customer's turn — without it the conversation does not move.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widgetId | String | required | The id of the component the customer answered (GraineWidget.id). |
data | Map<String, Object?> | required | The structured answer (WidgetAnswer.data). |
summary | String | required | The sentence that is the customer's turn (WidgetAnswer.summary); without it the conversation does not move. |
Returns — nothing; it returns when done.
Errors — none.
GraineChatSession.clear
Call it to empty the chat on screen without ending the conversation Graine keeps.
Empties the chat on screen — only the screen. The connection stays as it is, and nothing Graine keeps is touched: an identified customer's conversation comes back with the history the next connection brings, and the agent's memories stay. A message still waiting to be sent is cleared with the rest. newConversation() starts over; forgetMemory() forgets.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineChatState
Implement it to hand the bar a chat your app runs itself; GraineChatSession is the SDK's own.
abstract class GraineChatState implements Listenable
What to expect — The agent's typed conversation. It connects while the customer is in the chat (open) and hangs up when they leave (close); a message typed while it is not connected is shown at once and sent when it is. Its state changes as the conversation moves: draw from it. Opening the chat ends a call the bar holds.
| Property | Type | Meaning |
|---|---|---|
List<Caption> get messages | List<Caption> | The conversation up to now, oldest message first; a line still arriving is marked live. |
bool get connected | bool | True while the chat is connected; the header then reads "Online". |
Its functions: send — each with its parameters, what it returns, the errors it raises and an example.
GraineChatState.send
Call it to send the customer's typed message.
The customer typed text and sent it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String | required | What the customer typed. Blank text is ignored. |
Returns — nothing; it returns when done.
Errors — none.
GraineChatConnection
Use it to connect the chat while the customer is in it and hang it up when they leave.
abstract interface class GraineChatConnection
What to expect — The agent's typed conversation. It connects while the customer is in the chat (open) and hangs up when they leave (close); a message typed while it is not connected is shown at once and sent when it is. Its state changes as the conversation moves: draw from it. Opening the chat ends a call the bar holds.
| Property | Type | Meaning |
|---|---|---|
bool get connecting | bool | True while the chat is connecting, either for the first time or again after losing its connection. |
Its functions: open, close — each with its parameters, what it returns, the errors it raises and an example.
GraineChatConnection.open
Call it when the customer enters your chat screen: the chat connects, and the agent greets a new customer.
Call it when the customer is in the chat; it connects and keeps the connection up.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineChatConnection.close
Call it when the customer leaves your chat screen: the chat hangs up; the conversation stays.
The customer left the chat: hang up.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineChatTyping
Read it to show a typing bubble while the agent composes its answer.
abstract interface class GraineChatTyping
What to expect — The agent's typed conversation. It connects while the customer is in the chat (open) and hangs up when they leave (close); a message typed while it is not connected is shown at once and sent when it is. Its state changes as the conversation moves: draw from it. Opening the chat ends a call the bar holds.
| Property | Type | Meaning |
|---|---|---|
bool get agentTyping | bool | True when the agent has an answer to give but has not started saying it. |
GraineChatTurn
Read it to draw one message of the chat — who said it, what, when, and whether it was delivered.
class GraineChatTurn
What to expect — One per message, oldest first. The agent's turn updates in place (same id) while live, then stops. A customer's message typed while the chat is not connected is sending and goes as soon as it is; failed means every reconnect was spent — the next message or a retry sends it. Restored turns arrive once when the chat opens, for an identified customer on an agent with memory on, on one of their devices: at most 50, oldest first, delivered, never live, with their original times; the welcome is not sent then. Consecutive voice turns show as one "Voice call · time" row. The list empties on sign-out, when another customer signs in, after a successful forgetMemory() and on newConversation().
| Property | Type | Meaning |
|---|---|---|
final String id | String | The turn's id within this chat — t1, t2, … — or, for a restored turn, the id Graine gave it. |
final GraineChatRole role | GraineChatRole | Who said it: GraineChatRole.user (the customer) or GraineChatRole.agent. Draw the bubble on the right side from it. |
final String text | String | What was said. |
final DateTime at | DateTime | The time the turn was said; for an agent turn, the time of its first words. |
final GraineChatDelivery? delivery | GraineChatDelivery? | A user's turn only: sending, sent or failed. |
final bool proactive | bool | True for an unprompted agent turn, such as its welcome or a comment on something it noticed. |
final GraineComponent? component | GraineComponent? | The component drawn by the agent alongside this turn, or null when there is none. |
final bool live | bool | An agent turn still arriving. |
final bool restored | bool | True for a turn from an earlier conversation that came back when the chat opened (the user returned): it is shown as delivered, with the time it was originally said, rather than as something just said. |
final GraineChatChannel channel | GraineChatChannel | Where it was said: typed (chat) or on an earlier call (voice). A chat window draws a run of voice messages as one "Voice call" row, never their words. |
Caption get caption | Caption | The turn in Caption form, which is what a window that draws captions displays. |
Its functions: GraineChatTurn, copyWith — each with its parameters, what it returns, the errors it raises and an example.
GraineChatTurn.GraineChatTurn
Use it to build a message by hand for a test or a preview; the chat makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The turn's id within this chat — t1, t2, … — or, for a restored turn, the id Graine gave it. |
role | GraineChatRole | required | Who said it: GraineChatRole.user (the customer) or GraineChatRole.agent. Draw the bubble on the right side from it. |
text | String | required | What was said. |
at | DateTime | required | The time the turn was said; for an agent turn, the time of its first words. |
delivery | GraineChatDelivery? | optional | A user's turn only: sending, sent or failed. |
proactive | bool | false | True for an unprompted agent turn, such as its welcome or a comment on something it noticed. |
component | GraineComponent? | optional | The component drawn by the agent alongside this turn, or null when there is none. |
live | bool | false | An agent turn still arriving. |
restored | bool | false | True for a turn from an earlier conversation that came back when the chat opened (the user returned): it is shown as delivered, with the time it was originally said, rather than as something just said. |
channel | GraineChatChannel | GraineChatChannel.chat | Where it was said: typed (chat) or on an earlier call (voice). A chat window draws a run of voice messages as one "Voice call" row, never their words. |
Returns — a new GraineChatTurn.
Errors — none.
GraineChatTurn.copyWith
Use it to make a changed copy of a message — its text, whether it is still arriving, its delivery or its component.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String? | optional | What was said. |
live | bool? | optional | The words are still arriving. |
delivery | GraineChatDelivery? | optional | Where the customer's message is. |
component | GraineComponent? | optional | The component the agent drew. |
Returns — GraineChatTurn.
Errors — none.
GraineChatRole
Read it to tell the customer's messages from the agent's.
enum GraineChatRole { user, agent }
What to expect — Every message has one. Draw the customer's on one side and the agent's on the other.
| Case | Meaning |
|---|---|
user | The customer typed it (or said it, on an earlier call). |
agent | The agent said it. |
GraineChatDelivery
Read it to show whether the customer's message is sending, sent or failed — and offer a retry when it failed.
enum GraineChatDelivery { sending, sent, failed }
What to expect — Only on the customer's messages; null on the agent's. A message typed while the chat is not connected is shown at once as sending and goes the moment it connects.
| Case | Meaning |
|---|---|
sending | Typed and waiting to go out. |
sent | On its way to the agent. Restored messages are sent. |
failed | Not sent: every reconnect was spent. The next message, or open(), sends it — offer "tap to retry". |
GraineChatChannel
Read it to tell a typed message from one said on a call, so an earlier call is drawn as one "Voice call" row.
enum GraineChatChannel { chat, voice }
What to expect — chat for every message typed now. Only a restored message — from an earlier conversation — can be voice; the SDK's chat window draws a run of them as one "Voice call · 6:05 PM" row, never their words.
| Case | Meaning |
|---|---|
chat | Typed in the chat. |
voice | Said on an earlier call. |
GraineChatSize
Use it to choose how big the chat window opens: compact above the bar, a large sheet or panel, or the full screen.
enum GraineChatSize
What to expect — Which size wins: the size passed to the open call, then the app's chatSize, then the agent's Window size in the Garage, else compact. An open's size lasts until the chat closes. On a phone, large is a sheet over about 92% of the screen and full the whole screen inside the safe areas; on a tablet or computer both open a panel 420 wide and up to 760 tall. A word from a newer design that the SDK does not know is passed over.
| Case | Meaning |
|---|---|
compact | The usual window above the bar, the same as in earlier versions. |
large | On a phone, a sheet covering most of the screen; on a tablet, a panel in a corner. |
full | The whole screen. |
| Property | Type | Meaning |
|---|---|---|
String get wire | String | The design's word for it. |
Its functions: fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineChatSize.fromWire
Use it to read a window size from its word (compact, large, full).
Maps the design's size word to a value; returns null for anything else, whether the word is missing or one only a newer server uses.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The size's word: compact, large or full; anything else reads as null. |
Returns — GraineChatSize?. Example value: GraineChatSize.compact.
Errors — none.
ChatRows
Use it to lay out a chat of your own exactly as the SDK's chat window does: bubbles, one row per earlier call, and day lines.
abstract final class ChatRows
What to expect — The rows a chat window draws for a list of turns: a bubble per chat turn, one "Voice call · time" row per call, and day separators (Today, Yesterday, a date) in the device's time zone.
Its functions: build, dayLabel, callLabel, callSpoken, offersNewConversation, offersStarters — each with its parameters, what it returns, the errors it raises and an example.
ChatRows.build
Use it to turn the chat's messages into the rows to draw, in order.
The rows for turns (oldest first), in order: a day line before the first row when it is not from today and wherever the day changes, one row per earlier call, and a bubble per typed message.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turns | List<GraineChatTurn> | required | The chat's messages, oldest first (GraineChatSession.turns). |
now | DateTime | required | The time now — pass DateTime.now(); it decides which day is today. |
local | DateTime Function(DateTime)? | optional | Reads a time as the device's wall clock; the device's own zone when left out. A test passes its own. |
Returns — List<ChatRow> — its fields: ChatRow. Example value: [].
Errors — none.
ChatRows.dayLabel
Use it to get the words for a day line: "Today", "Yesterday" or the date.
Gives "Today" or "Yesterday", and otherwise the date in the form ChatTime.booked uses for a day: "Sat 10 Oct", plus the year when it is not the current one ("Wed 31 Dec 2025").
| Parameter | Type | Default | Meaning |
|---|---|---|---|
row | ChatDayRow | required | The day line to write. |
now | DateTime | required | The time now — pass DateTime.now(). |
local | DateTime Function(DateTime)? | optional | Reads a time as the device's wall clock; the device's own zone when left out. |
Returns — String. Example value: 'Yesterday'.
Errors — none.
ChatRows.callLabel
Use it to get the words for an earlier call's row.
"Voice call · 6:05 PM" — with clock, the call's first message's time in the device's short form.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
clock | String | required | The call's first message's time, as ChatTime.clock writes it ("6:05 PM"). |
Returns — String. Example value: 'Voice call · 6:05 PM'.
Errors — none.
ChatRows.callSpoken
Use it to get what a screen reader says for an earlier call's row.
The text a screen reader reads out for the row, such as "Voice call at 6:05 PM".
| Parameter | Type | Default | Meaning |
|---|---|---|---|
clock | String | required | The call's first message's time, as ChatTime.clock writes it. |
Returns — String. Example value: 'Voice call at 6:05 PM'.
Errors — none.
ChatRows.offersNewConversation
Use it to decide whether to offer "New conversation" in your chat's header.
The header offers "New conversation" only for a continuing conversation, that is, while restored turns are on screen.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turns | List<GraineChatTurn> | required | The chat's messages, oldest first. |
Returns — bool. Example value: true.
Errors — none.
ChatRows.offersStarters
Use it to decide whether to show the brand's conversation starters.
The brand's starters are for a fresh chat only: they are not offered after the user has said anything, or on a continuing conversation.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turns | List<GraineChatTurn> | required | The chat's messages, oldest first. |
Returns — bool. Example value: true.
Errors — none.
ChatRow
Read it as one row of the chat to draw: a day line, an earlier call, or a message.
sealed class ChatRow
What to expect — The rows a chat window draws for a list of turns: a bubble per chat turn, one "Voice call · time" row per call, and day separators (Today, Yesterday, a date) in the device's time zone.
| Property | Type | Meaning |
|---|---|---|
String get key | String | It stays the same as the conversation grows: a separator is keyed on its date, a call on its first turn, and a bubble on its turn. |
Its functions: ChatRow — each with its parameters, what it returns, the errors it raises and an example.
ChatRow.ChatRow
The base constructor of the three row types; you never call it directly.
Parameters — none.
Returns — nothing you call directly: ChatRow is sealed: its three kinds come from ChatRows.build.
Errors — none.
ChatDayRow
Read it to draw a day line between messages.
final class ChatDayRow extends ChatRow
What to expect — The rows a chat window draws for a list of turns: a bubble per chat turn, one "Voice call · time" row per call, and day separators (Today, Yesterday, a date) in the device's time zone.
| Property | Type | Meaning |
|---|---|---|
final ChatDay day | ChatDay | Which words the line takes: today, yesterday or date. |
final String date | String | The day on the device, YYYY-MM-DD — also the row's key. |
final DateTime at | DateTime | When the day's first message was said — ChatRows.dayLabel writes a date from it. |
String get contractKey | String | The day in one word, the same on every platform: 'today', 'yesterday' or the date — for comparing rows in a test. |
Its functions: ChatDayRow — each with its parameters, what it returns, the errors it raises and an example.
ChatDayRow.ChatDayRow
Use it to build a day line by hand for a test; ChatRows.build makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
day | ChatDay | required | Which words the line takes: today, yesterday or date. |
date | String | required | The day on the device, YYYY-MM-DD — also the row's key. |
at | DateTime | required | When the day's first message was said — ChatRows.dayLabel writes a date from it. |
Returns — a new ChatDayRow.
Errors — none.
ChatVoiceRow
Read it to draw an earlier call as one "Voice call · 6:05 PM" row — that a call happened and when, never its words.
final class ChatVoiceRow extends ChatRow
What to expect — The rows a chat window draws for a list of turns: a bubble per chat turn, one "Voice call · time" row per call, and day separators (Today, Yesterday, a date) in the device's time zone.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The row's key: voice- and the call's first message's id. |
final DateTime at | DateTime | When the call's first message was said — the row shows it ("Voice call · 6:05 PM"). |
final int first | int | The index, in the chat's messages, of the call's first message. |
final int last | int | The index of the call's last message. |
Its functions: ChatVoiceRow — each with its parameters, what it returns, the errors it raises and an example.
ChatVoiceRow.ChatVoiceRow
Use it to build an earlier call's row by hand for a test; ChatRows.build makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The row's key: voice- and the call's first message's id. |
at | DateTime | required | When the call's first message was said — the row shows it ("Voice call · 6:05 PM"). |
first | int | required | The index, in the chat's messages, of the call's first message. |
last | int | required | The index of the call's last message. |
Returns — a new ChatVoiceRow.
Errors — none.
ChatTurnRow
Read it to draw one message bubble.
final class ChatTurnRow extends ChatRow
What to expect — The rows a chat window draws for a list of turns: a bubble per chat turn, one "Voice call · time" row per call, and day separators (Today, Yesterday, a date) in the device's time zone.
| Property | Type | Meaning |
|---|---|---|
final GraineChatTurn turn | GraineChatTurn | The message to draw as a bubble. |
final int index | int | Its index in the chat's messages. |
Its functions: ChatTurnRow — each with its parameters, what it returns, the errors it raises and an example.
ChatTurnRow.ChatTurnRow
Use it to build a bubble row by hand for a test; ChatRows.build makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turn | GraineChatTurn | required | The message to draw as a bubble. |
index | int | required | Its index in the chat's messages. |
Returns — a new ChatTurnRow.
Errors — none.
ChatDay
Read it to know which words a day line takes: today, yesterday or a date.
enum ChatDay { today, yesterday, date }
What to expect — Decided on the device's clock: a conversation that runs past midnight gets a new day line.
| Case | Meaning |
|---|---|
today | The line says "Today". |
yesterday | The line says "Yesterday". |
date | The line says the date — "Sat 10 Oct", with the year when it is not this one ("Wed 31 Dec 2025"). |
ChatPieces
Use it to decide which optional pieces your own chat window draws, as the agent's design sets them: earlier messages, the starters, New conversation, the booked-calls card and Book a call.
final class ChatPieces
What to expect — Work them out again whenever the messages, the booked calls or booking's availability change. The SDK's chat window draws exactly these.
| Property | Type | Meaning |
|---|---|---|
final List<GraineChatTurn> turns | List<GraineChatTurn> | The messages to draw, oldest first — without the restored ones when earlier messages are hidden. |
final bool starters | bool | Show the brand's conversation starters: nothing restored on screen, and the customer has said nothing yet. |
final bool newConversation | bool | Offer New conversation in the header: the design keeps it, and earlier messages are on screen. |
final bool upcoming | bool | Draw the booked-calls card: the design keeps it, and at least one call is booked. |
final String upcomingTitle | String | The title of the card — the brand's own words when it set some, otherwise "Upcoming call" / "Upcoming calls". |
final bool book | bool | Offer Book a call — in the card, or as a compact row in its place while nothing is booked: the design keeps the booked-calls card, and booking is available here. New in 0.8.0. |
Its functions: of, ofChat, book — each with its parameters, what it returns, the errors it raises and an example.
ChatPieces.of
Use it to work out the pieces from your own settings.
The pieces for turns and upcomingCount booked calls, as the design sets them. With earlier messages hidden, the window opens like a new chat: the restored messages are not drawn (the agent still has them), the starters may show, and New conversation — which belongs to earlier messages on screen — does not.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turns | List<GraineChatTurn> | required | The chat's messages, oldest first. |
showHistory | bool | true | Draw earlier messages (the design's Earlier messages); false leaves restored messages off the screen. |
newConversation | bool | true | Offer New conversation in the header (the design's New conversation button). |
showUpcomingCalls | bool | true | Draw the booked-calls card (the design's Booked calls) — and so Book a call. |
upcomingTitle | String | '' | The card's title in the brand's words; empty: "Upcoming call" or "Upcoming calls". |
upcomingCount | int | 0 | How many booked calls the customer has (chat.upcomingCalls.length). |
bookingAvailable | bool | false | Whether booking is available here (GraineInApp.bookingAvailable). |
Returns — ChatPieces — its fields: ChatPieces.
Errors — none.
ChatPieces.ofChat
Use it to work out the pieces from the agent's design (tokens?.chat), as the SDK's chat window does.
The same, under the design's chat tokens — what the SDK's chat window does. Null tokens (an agent with no design) turn every piece on.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turns | List<GraineChatTurn> | required | The chat's messages, oldest first. |
chat | ThemeChat? | required | The design's chat tokens (GraineInApp.instance.tokens?.chat); null, from an agent with no design, turns every piece on. |
upcomingCount | int | 0 | How many booked calls the customer has. |
bookingAvailable | bool | false | Whether booking is available here (GraineInApp.bookingAvailable). |
Returns — ChatPieces — its fields: ChatPieces.
Errors — none.
ChatTime
Use it to write a chat's times the way the SDK does, in the device's own time zone.
abstract final class ChatTime
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
Its functions: clock, booked, day — each with its parameters, what it returns, the errors it raises and an example.
ChatTime.clock
Use it to write the short time under a message.
Formats a time in the device's short style: "9:41 PM", or "21:41" where the device uses a 24-hour clock.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
time | DateTime | required | The moment to write, in any zone; it is shown on the device's clock. |
h24 | bool | required | true on a device set to the 24-hour clock — MediaQuery.alwaysUse24HourFormatOf(context). |
Returns — String. Example value: '9:41 PM' ('21:41' with h24: true).
Errors — none.
ChatTime.booked
Use it to write when a booked call rings: "Today, 5:30 PM", "Tomorrow, 9:00 AM" or the date.
Writes when a booked call is due: "Today, 5:30 PM" or "Tomorrow, 9:00 AM", and otherwise the weekday with the date, as in "Wed 14 Oct, 10:00 AM".
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | When the call rings, in any zone; it is shown on the device's clock. |
now | DateTime | required | The time now — pass DateTime.now(); it decides "Today" and "Tomorrow". |
h24 | bool | required | true on a device set to the 24-hour clock — MediaQuery.alwaysUse24HourFormatOf(context). |
Returns — String. Example value: 'Tomorrow, 9:00 AM'.
Errors — none.
ChatTime.day
Use it to write a day in short words — the weekday and the date, as the booking sheet's chips and lines do.
A day in short words on the device's clock: the weekday and the date. New in 0.8.0; the booking sheet's chips, its time zone line and its "Booked — …" line use it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | A time on the day, in any zone. |
Returns — String. Example value: 'Wed 14 Oct'.
Errors — none.
The voice bar
The assistant bar: the agent's voice call, its captions and components, and the switch to the chat, in one bar the SDK draws in your agent's design. Place GraineEngine once and GraineAgentBar where the bar should sit — or draw your own controls from GraineInApp.instance.voice with the words, phases and meters below, so every surface says the same thing at the same moment.
GraineVoice
Use it to start and end the agent's voice call from your own controls, and to draw its state; GraineAgentBar already does both.
class GraineVoice extends ChangeNotifier implements GraineCallState, GraineCallFault, GraineConnectProgress, GraineCaptionsSwitch
What to expect — GraineInApp.instance.voice (each agent has its own). GraineEngine attaches it once, above the navigator, and GraineAgentBar starts and ends calls itself; use it directly only for controls of your own. It is a ChangeNotifier: listen to it and redraw. One conversation at a time: starting it closes an open chat and ends another agent's call, and it waits while a native call is live.
Everything it has — its own members, and those of the four interfaces it implements:
| Member | Type | What it is for |
|---|---|---|
Future<void> start() | Future<void> | Start the call (see GraineCallState.start). |
void end() | void | Hang up (see GraineCallState.end). |
void setMuted(bool muted) | void | Stop or resume sending the customer's voice. |
void retry() | void | Reload the page that carries the call and start its retry ladder over — for "Try again". |
bool get connected | bool | The call is connected. |
bool get connecting | bool | A call is being placed. |
bool get muted | bool | The customer is muted. |
bool get ready | bool | The page is ready: a start connects at once. |
bool get reconnecting | bool | True while the call is being brought back after a network interruption. |
bool? get online | bool? | Whether the device is online; null before the first report. |
ConnectionQuality get quality | ConnectionQuality | The connection in one word. |
GraineConnectivity get connectivity | GraineConnectivity | Whether the page that carries the call is there. |
List<Caption> get captions | List<Caption> | What has been said so far, oldest first. |
Caption? get caption | Caption? | The line being said now, or the last one. |
bool get agentSpeaking | bool | The agent is mid-sentence. |
bool get micDenied | bool | The last start was refused the microphone. |
Map<String, Object?> get appearance | Map<String, Object?> | The dashboard's Appearance for this agent. |
String? get error | String? | What is permanently wrong with this agent's setup (a way of carrying the audio that is not configured), or null; the bar says "Unavailable" while it is set, and a new call clears it. |
ConnectStage? get connectStage | ConnectStage? | Where the call being placed is; null outside a connect. |
bool get slowConnect | bool | A connect the customer is waiting on has run past timing.slowConnectMs: say "Still connecting…". |
bool get callFailed | bool | The last start could not be connected at all; a new start simply tries again. |
bool get captionsOn | bool | The captions switch: the bar draws the line being said only while it is on. On by default; what is said stays in captions either way (see GraineCaptionsSwitch). New in 0.9.0. |
void setCaptionsOn(bool on) | void | Turn the captions on or off, for your own CC button; the call goes on. New in 0.9.0. |
void clearCaptions() | void | Forget what has been said (captions) without ending the call. New in 0.9.0. |
GraineConfig get config | GraineConfig | The configuration this call was set up with. |
GraineInApp get app | GraineInApp | The agent this call belongs to. |
CallPhase get phase | CallPhase | Where the call stands in one word: idle, connecting, reconnecting, thinking, speaking or listening. |
Transport? get transport | Transport? | The way the audio really travels, once the page has said. |
bool get attached | bool | Whether a page is attached (GraineEngine is mounted). |
Its functions: attach, detachPage, detach, viewOpened, viewClosed, answerWidget, reportEvent — each with its parameters, what it returns, the errors it raises and an example.
GraineVoice.attach
Called by GraineEngine to give the call the page that carries it; call it yourself only with an engine page of your own.
Attaches the engine. GraineEngine calls it with its WebView page, and a test can pass a fake instead.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
page | GraineEnginePage | required | The page that carries the call — GraineEngine passes its own. |
Returns — nothing; it returns when done.
Errors — none.
GraineVoice.detachPage
Called by GraineEngine when its page goes away; call it yourself only with an engine page of your own.
Detaches page if it is the one attached — what GraineEngine does when it leaves the screen.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
page | GraineEnginePage | required | The page that is going away; nothing happens when another page is attached by now. |
Returns — nothing; it returns when done.
Errors — none.
GraineVoice.detach
Call it to let go of the engine page entirely — when you tear down your own engine.
Remove the engine.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineVoice.viewOpened
Call it when your own call UI comes on screen, so the engine page loads and a tap starts the call at once.
Reports that a UI for this call has appeared on screen. GraineAgentBar reports this on its own; an app that draws its own bar can report it too, matched with a viewClosed call.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineVoice.viewClosed
Call it when your own call UI leaves the screen.
A UI from viewOpened left the screen.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineVoice.answerWidget
Call it when the customer answers a component the agent drew during the call, if you draw components yourself.
The customer answered a component.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widgetId | String | required | The id of the component the customer answered. |
data | Map<String, Object?> | required | The structured answer (WidgetAnswer.data). |
summary | String | required | The sentence that is the customer's turn (WidgetAnswer.summary); without it the conversation does not move. |
Returns — nothing; it returns when done.
Errors — none.
GraineAgentBar
Use it to give the customer the agent's voice bar — call, captions, components and the chat — drawn in your agent's design, with no UI work.
class GraineAgentBar extends StatefulWidget
What to expect — Place it once, over your app — in a Stack inside GraineEngine. It follows the call, the captions and the components by itself, offers the chat as the dashboard allows, and draws in the agent's design. The customer can drag it up and down; save onPlacementChange's offset and hand it back as initialOffset — the SDK stores nothing. Hide it from onClose and bring it back with a GraineLauncher.
| Property | Type | Meaning |
|---|---|---|
final GraineCallState? call | GraineCallState? | The call to draw. |
final GraineComponents? components | GraineComponents? | The components to draw above the bar. |
final GraineInApp? app | GraineInApp? | In an app with more than one agent, the agent the bar speaks to, for example GraineAgentBar(app: GraineInApp.named('support')); the bar uses its call, chat, components, session and design. |
final String? accent | String? | The colour, as #RRGGBB, of the avatar, the microphone, the meter and the components. |
final String? name | String? | The name beside the status. |
final String? avatarUrl | String? | An image of a face to show in the avatar, taking priority over the design's glyph. Without it, the avatar falls back to the design's glyph, then the dashboard's logo, then the first letter of the name. |
final String? scheme | String? | "light", "dark" or "auto" (the device). |
final double? radius | double? | How rounded the corners of the caption and components are. |
final ResolvedDesign? design | ResolvedDesign? | The design to draw. When left out, the session's design (GraineInApp.design) is used; if there is none either, the bar keeps its pre-design colours, corners and depth. |
final double bottomInset | double | The bar's resting position when it has no offset, which is above your tab bar. |
final double horizontalInset | double | Space between the bar and the screen's left and right edges, in logical pixels (default 12). |
final bool draggable | bool | Let the customer drag it up and down. |
final int? initialOffset | int? | A saved position from your app, in logical pixels measured up from the anchor. |
final ValueChanged<int>? onPlacementChange | ValueChanged<int>? | The customer let go somewhere new. |
final bool keyboardAware | bool | Rise above the soft keyboard. |
final bool showComponents | bool | Mount a GraineWidgetView above the bar. |
final double? topMargin | double? | Space to keep clear at the top. |
final bool showCaptions | bool | During a call, display the line currently being spoken above the bar — while the call's captions switch is on too (GraineCaptionsSwitch.captionsOn, on by default). |
final VoidCallback? onClose | VoidCallback? | Called when the end button is pressed — after hanging up, or, when no call is in progress, to close the bar. |
final GraineChatState? chat | GraineChatState? | The chat, for an agent the dashboard offers as a chat or as both (Embed & Widgets → What visitors get). Default: the agent's own (GraineInApp.chat): the bar offers the switch as the dashboard allows, draws the chat window above itself, opens the chat while the customer is in it (ending the call first) and closes it when they leave. If your app runs the chat on its own, pass that chat here. |
final bool builtInChat | bool | Use the SDK's own chat when chat is null (default true). Off: without a chat, the bar is the call alone, whatever the dashboard offers. |
final AgentSurface? surface | AgentSurface? | The surface to open first when both are offered; left out, the dashboard's starting choice applies. |
final ValueChanged<AgentSurface>? onSurfaceChange | ValueChanged<AgentSurface>? | Fires whenever the customer goes from the call to the chat or back, whether they chose to or the dashboard's setting moved them. |
static const Key barKey | Key | Key of the bar proper: the 60-point frame that holds the avatar and the buttons. |
static const Key callButtonKey | Key | Key of the button that starts a call, retries a failed load or ends the call — shown as the microphone when no call is on, and as the end button during one. |
static const Key muteButtonKey | Key | Key of the microphone button shown in a call, which mutes. |
static const Key closeButtonKey | Key | The end button off a call, where it closes. |
static const Key switchButtonKey | Key | Key of the switch between call and chat, present only when both are offered. |
static const Key statusKey | Key | The status line. |
static const Key meterKey | Key | Key of the four-bar level meter shown next to "Listening" and "Speaking". |
static const Key avatarKey | Key | The avatar's key, for a widget test to find it. |
static const Key captionKey | Key | The live caption above the bar. |
static const Key chatKey | Key | The chat window above the bar. |
Its functions: GraineAgentBar — each with its parameters, what it returns, the errors it raises and an example.
GraineAgentBar.GraineAgentBar
Use it to place the bar, usually in a Stack over your app inside GraineEngine.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
call | GraineCallState? | optional | The call to draw. |
components | GraineComponents? | optional | The components to draw above the bar. |
accent | String? | optional | The colour, as #RRGGBB, of the avatar, the microphone, the meter and the components. |
name | String? | optional | The name beside the status. |
avatarUrl | String? | optional | An image of a face to show in the avatar, taking priority over the design's glyph. Without it, the avatar falls back to the design's glyph, then the dashboard's logo, then the first letter of the name. |
scheme | String? | optional | "light", "dark" or "auto" (the device). |
radius | double? | optional | How rounded the corners of the caption and components are. |
design | ResolvedDesign? | optional | The design to draw. When left out, the session's design (GraineInApp.design) is used; if there is none either, the bar keeps its pre-design colours, corners and depth. |
bottomInset | double | 96 | The bar's resting position when it has no offset, which is above your tab bar. |
horizontalInset | double | 12 | Space between the bar and the screen's left and right edges, in logical pixels (default 12). |
draggable | bool | true | Let the customer drag it up and down. |
initialOffset | int? | optional | A saved position from your app, in logical pixels measured up from the anchor. |
onPlacementChange | ValueChanged<int>? | optional | The customer let go somewhere new. |
keyboardAware | bool | true | Rise above the soft keyboard. |
showComponents | bool | true | Mount a GraineWidgetView above the bar. |
topMargin | double? | optional | Space to keep clear at the top. |
showCaptions | bool | true | During a call, display the line currently being spoken above the bar — while the call's captions switch is on too (GraineCaptionsSwitch.captionsOn, on by default). |
onClose | VoidCallback? | optional | Called when the end button is pressed — after hanging up, or, when no call is in progress, to close the bar. |
chat | GraineChatState? | optional | The chat, for an agent the dashboard offers as a chat or as both (Embed & Widgets → What visitors get). Default: the agent's own (GraineInApp.chat): the bar offers the switch as the dashboard allows, draws the chat window above itself, opens the chat while the customer is in it (ending the call first) and closes it when they leave. If your app runs the chat on its own, pass that chat here. |
builtInChat | bool | true | Use the SDK's own chat when chat is null (default true). Off: without a chat, the bar is the call alone, whatever the dashboard offers. |
surface | AgentSurface? | optional | The surface to open first when both are offered; left out, the dashboard's starting choice applies. |
onSurfaceChange | ValueChanged<AgentSurface>? | optional | Fires whenever the customer goes from the call to the chat or back, whether they chose to or the dashboard's setting moved them. |
app | GraineInApp? | optional | In an app with more than one agent, the agent the bar speaks to, for example GraineAgentBar(app: GraineInApp.named('support')); the bar uses its call, chat, components, session and design. |
Returns — a new GraineAgentBar.
Errors — none.
AgentSurface
Use it to say which way the customer is with the agent: the voice call or the chat.
enum AgentSurface { voice, chat }
What to expect — The dashboard decides which exist (Embed & Widgets → What visitors get); your preference wins only when it allows it.
| Case | Meaning |
|---|---|
voice | The voice call. |
chat | The typed chat. |
SurfacePolicy
Read it to know which of the call and the chat the dashboard allows, which opens first, and whether to offer a switch.
class SurfacePolicy
What to expect — Worked out from the dashboard's Appearance (what visitors get, and which opens first) when the session loads; a preference counts only when the dashboard allows it.
| Property | Type | Meaning |
|---|---|---|
final List<AgentSurface> allowed | List<AgentSurface> | In the order to offer them. |
final AgentSurface start | AgentSurface | Which opens first: your preference when the dashboard allows it, else the dashboard's choice, else the first allowed. |
final bool canSwitch | bool | Whether to show a switch at all; false when the agent offers only one of the two. |
Its functions: SurfacePolicy — each with its parameters, what it returns, the errors it raises and an example.
SurfacePolicy.SurfacePolicy
Use it to build a policy by hand for a test; Surfaces.resolve gives the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
allowed | List<AgentSurface> | required | In the order to offer them. |
start | AgentSurface | required | Which opens first: your preference when the dashboard allows it, else the dashboard's choice, else the first allowed. |
canSwitch | bool | required | Whether to show a switch at all; false when the agent offers only one of the two. |
Returns — a new SurfacePolicy.
Errors — none.
Surfaces
Use it to work out, from the dashboard's settings, whether the customer gets the call, the chat or both — as the bar does.
abstract final class Surfaces
What to expect — Worked out from the dashboard's Appearance when the session loads; a preference counts only when the dashboard allows it. The SDK's bar applies it for you.
Its functions: resolve — each with its parameters, what it returns, the errors it raises and an example.
Surfaces.resolve
Use it to get the policy for this agent's Appearance, with your preference when the dashboard allows it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
appearance | Map<String, Object?>? | required | The dashboard's Appearance for the agent (session.appearance). |
prefer | AgentSurface? | optional | Your preference, or the customer's last switch; it wins only when the dashboard allows it. |
Returns — SurfacePolicy — its fields: SurfacePolicy.
Errors — none.
GraineLauncher
Use it for a floating button that stands for the agent, in its design: a tap starts the call, or does what onPressed says — bring the bar back, open a screen of yours.
class GraineLauncher extends StatelessWidget
What to expect — Place it yourself — in a Stack, or a Scaffold's floating action button slot; it sizes itself (56 × 56, a pill as wide as its label). It draws in the agent's design: the launcher glyph or the brand's logo on the accent, the design's shape and shadow. A tap starts the call, or does what onPressed says.
| Property | Type | Meaning |
|---|---|---|
final GraineCallState? call | GraineCallState? | The call a tap starts. |
final GraineInApp? app | GraineInApp? | Which agent a tap calls; the launcher uses that agent's call, session and design. When left out: the agent that call belongs to, or failing that the default agent. |
final VoidCallback? onPressed | VoidCallback? | An action to run on tap in place of starting the call. |
final String? label | String? | The text on a pill, also read out by screen readers. Without it, the dashboard's heading is used, or "Talk to us" when there is no heading. |
final ResolvedDesign? design | ResolvedDesign? | The design to draw. |
final String? scheme | String? | "light", "dark" or "auto" (the device). |
static const Key launcherKey | Key | The button, for a test to find. |
Its functions: GraineLauncher — each with its parameters, what it returns, the errors it raises and an example.
GraineLauncher.GraineLauncher
Use it to place the launcher — in a Stack, or as a Scaffold's floating action button.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
call | GraineCallState? | optional | The call a tap starts. |
onPressed | VoidCallback? | optional | An action to run on tap in place of starting the call. |
label | String? | optional | The text on a pill, also read out by screen readers. Without it, the dashboard's heading is used, or "Talk to us" when there is no heading. |
design | ResolvedDesign? | optional | The design to draw. |
scheme | String? | optional | "light", "dark" or "auto" (the device). |
app | GraineInApp? | optional | Which agent a tap calls; the launcher uses that agent's call, session and design. When left out: the agent that call belongs to, or failing that the default agent. |
Returns — a new GraineLauncher.
Errors — none.
GraineLoaderView
Use it to draw a wait — connecting, reconnecting, thinking, a component loading — the way the dashboard's loader setting says.
class GraineLoaderView extends StatefulWidget
What to expect — Place it where the customer waits. It animates at the dashboard's speed, in the accent unless a colour was chosen, and stands still when the device asks for reduced motion.
| Property | Type | Meaning |
|---|---|---|
final LoaderLook look | LoaderLook | From Loaders.resolve. |
final Color color | Color | The loader's colour — usually the accent. |
final Color trackColor | Color | The ring's unlit part. |
final double? size | double? | Replaces the look's own size; the bar's status line, for one, needs a small loader. |
final String? label | String? | Text describing the current moment; leave it null to show only the mark. |
final Color labelColor | Color | The colour of the loader's words, when labelStyle does not set one. |
final TextStyle? labelStyle | TextStyle? | The complete text style for the label; the voice bar, for instance, uses the design's typeface. |
final bool stacked | bool | Place the label below the mark instead of next to it. |
final String? logoUrl | String? | The brand's logo, drawn breathing for the mark kind; without one, mark draws the pulse. |
Its functions: GraineLoaderView — each with its parameters, what it returns, the errors it raises and an example.
GraineLoaderView.GraineLoaderView
Use it to place a loader in your own UI.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
look | LoaderLook | required | From Loaders.resolve. |
color | Color | required | The loader's colour — usually the accent. |
trackColor | Color | const Color(0x332C2E33) | The ring's unlit part. |
size | double? | optional | Replaces the look's own size; the bar's status line, for one, needs a small loader. |
label | String? | optional | Text describing the current moment; leave it null to show only the mark. |
labelColor | Color | const Color(0xFF5F6672) | The colour of the loader's words, when labelStyle does not set one. |
labelStyle | TextStyle? | optional | The complete text style for the label; the voice bar, for instance, uses the design's typeface. |
stacked | bool | false | Place the label below the mark instead of next to it. |
logoUrl | String? | optional | The brand's logo, drawn breathing for the mark kind; without one, mark draws the pulse. |
Returns — a new GraineLoaderView.
Errors — none.
Loaders
Use it to read the dashboard's loader setting into a look you can draw.
abstract final class Loaders
What to expect — From the dashboard's Appearance → Loading. Anything unreadable gives the default: dots, medium size, normal speed, the default words.
| Property | Type | Meaning |
|---|---|---|
static const List<String> kinds | List<String> | dots, pulse, ring, bars, mark. |
static const List<String> sizes | List<String> | small (14), medium (20), large (28) — logical pixels. |
static const List<String> speeds | List<String> | calm (1600 ms a cycle), normal (1100), quick (700). |
static const List<String> moments | List<String> | connecting, reconnecting, thinking, component. |
static const String defaultKind | String | The loader when the dashboard sets none: 'dots'. |
static const int textMax | int | The most characters a moment's words keep: 40. |
static const LoaderText defaultText | LoaderText | "Connecting…", "Reconnecting…", "Thinking…", "Loading…". |
Its functions: normalise, resolve, resolveStyle — each with its parameters, what it returns, the errors it raises and an example.
Loaders.normalise
Use it to read the dashboard's loader setting, keeping only the values the SDK knows.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The dashboard's loader setting (appearance['loader']), as decoded. |
Returns — LoaderStyle — its fields: LoaderStyle.
Errors — none.
Loaders.resolve
Use it to turn the dashboard's loader setting into the look to draw — with every default filled in.
The look for the dashboard's loader setting (appearance['loader']); anything unreadable gives the default.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The dashboard's loader setting (appearance['loader']); anything unreadable gives the default. |
Returns — LoaderLook — its fields: LoaderLook.
Errors — none.
Loaders.resolveStyle
Use it to turn an already-read loader setting into the look to draw.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | LoaderStyle | required | A loader setting already read with Loaders.normalise. |
Returns — LoaderLook — its fields: LoaderLook.
Errors — none.
LoaderLook
Read it to draw a loader: its kind, colour, size, speed and words.
class LoaderLook
What to expect — Every value filled in, ready to draw — from Loaders.resolve.
| Property | Type | Meaning |
|---|---|---|
final String kind | String | The loader to draw: dots, pulse, ring, bars or mark. |
final String? color | String? | Null means "use the accent". |
final int px | int | The mark's size, in logical pixels. |
final int periodMs | int | One animation cycle. |
final LoaderText text | LoaderText | Every moment filled in. |
final bool skeleton | bool | Draw placeholder shapes where a component will appear. |
Its functions: LoaderLook — each with its parameters, what it returns, the errors it raises and an example.
LoaderLook.LoaderLook
Use it to build a loader look by hand for a preview; Loaders.resolve gives the dashboard's.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
kind | String | required | The loader to draw: dots, pulse, ring, bars or mark. |
color | String? | optional | Null means "use the accent". |
px | int | required | The mark's size, in logical pixels. |
periodMs | int | required | One animation cycle. |
text | LoaderText | required | Every moment filled in. |
skeleton | bool | required | Draw placeholder shapes where a component will appear. |
Returns — a new LoaderLook.
Errors — none.
LoaderStyle
Read it as the dashboard's loader setting, before defaults are filled in.
class LoaderStyle
What to expect — Only the values the SDK knows survive; anything else is left null, which means the default.
| Property | Type | Meaning |
|---|---|---|
final String? kind | String? | dots, pulse, ring, bars or mark (the logo breathing); null: dots. |
final String? color | String? | "accent" or #RRGGBB. |
final String? size | String? | small, medium or large; null: medium. |
final String? speed | String? | calm, normal or quick; null: normal. |
final LoaderText? text | LoaderText? | The brand's words for each moment; null: the defaults. |
final bool? skeleton | bool? | Draw grey placeholder shapes where a component will appear; null: no. |
Its functions: LoaderStyle, toMap — each with its parameters, what it returns, the errors it raises and an example.
LoaderStyle.LoaderStyle
Use it to build a loader setting by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
kind | String? | optional | dots, pulse, ring, bars or mark (the logo breathing); null: dots. |
color | String? | optional | "accent" or #RRGGBB. |
size | String? | optional | small, medium or large; null: medium. |
speed | String? | optional | calm, normal or quick; null: normal. |
text | LoaderText? | optional | The brand's words for each moment; null: the defaults. |
skeleton | bool? | optional | Draw grey placeholder shapes where a component will appear; null: no. |
Returns — a new LoaderStyle.
Errors — none.
LoaderStyle.toMap
Use it to turn a loader setting back into the dashboard's JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
LoaderText
Use it to hold the words a loader says at each moment the customer waits.
class LoaderText
What to expect — A moment's words are at most 40 characters; null means the default words.
| Property | Type | Meaning |
|---|---|---|
final String? connecting | String? | While a call connects; null: "Connecting…". |
final String? reconnecting | String? | While a call reconnects; null: "Reconnecting…". |
final String? thinking | String? | While the agent prepares its answer; null: "Thinking…". |
final String? component | String? | While a component loads; null: "Loading…". |
bool get isEmpty | bool | True when no moment has words of its own. |
Its functions: LoaderText, forMoment, toMap — each with its parameters, what it returns, the errors it raises and an example.
LoaderText.LoaderText
Use it to build the loader's words by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
connecting | String? | optional | While a call connects; null: "Connecting…". |
reconnecting | String? | optional | While a call reconnects; null: "Reconnecting…". |
thinking | String? | optional | While the agent prepares its answer; null: "Thinking…". |
component | String? | optional | While a component loads; null: "Loading…". |
Returns — a new LoaderText.
Errors — none.
LoaderText.forMoment
Use it to get the words for one moment: connecting, reconnecting, thinking or component.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
moment | String | required | Which moment of the call screen to draw. |
Returns — String?. Example value: 'Thinking…'.
Errors — none.
LoaderText.toMap
Use it to turn the loader's words back into the dashboard's JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
GraineTranscriptView
Use it to show the conversation so far — the call's captions as chat bubbles — in the agent's design.
class GraineTranscriptView extends StatelessWidget
What to expect — Place it where the conversation should show; it redraws as the call's captions arrive, each line as a bubble, and scrolls inside maxHeight.
| Property | Type | Meaning |
|---|---|---|
final GraineCallState? call | GraineCallState? | The call whose words to show. |
final GraineInApp? app | GraineInApp? | The agent the call belongs to; the view uses its call, session and design. When left out: the agent that call belongs to, or failing that the default agent. |
final String? title | String? | The header's words. Without it, the dashboard's heading is used, or "Assistant" when there is no heading. |
final bool showHeader | bool | Draw the header with the title (default true). False for a transcript inside a screen that has its own title. |
final ResolvedDesign? design | ResolvedDesign? | The design to draw. |
final String? scheme | String? | "light", "dark" or "auto" (the device). |
final double maxHeight | double | The tallest the view grows; beyond that, the conversation scrolls within it. |
static const Key headerKey | Key | The header's key, for a widget test. |
Its functions: GraineTranscriptView, bubbleKey — each with its parameters, what it returns, the errors it raises and an example.
GraineTranscriptView.GraineTranscriptView
Use it to place the transcript in your own UI.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
call | GraineCallState? | optional | The call whose words to show. |
title | String? | optional | The header's words. Without it, the dashboard's heading is used, or "Assistant" when there is no heading. |
showHeader | bool | true | Draw the header with the title (default true). False for a transcript inside a screen that has its own title. |
design | ResolvedDesign? | optional | The design to draw. |
scheme | String? | optional | "light", "dark" or "auto" (the device). |
maxHeight | double | 320 | The tallest the view grows; beyond that, the conversation scrolls within it. |
app | GraineInApp? | optional | The agent the call belongs to; the view uses its call, session and design. When left out: the agent that call belongs to, or failing that the default agent. |
Returns — a new GraineTranscriptView.
Errors — none.
GraineTranscriptView.bubbleKey
Use it in a widget test to find one bubble of the transcript.
The indexth turn's bubble (oldest is 0).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
index | int | required | The position. |
Returns — Key.
Errors — none.
Caption
Read it to draw one line of the call's captions: who said it, what, and whether it is still being said.
class Caption
What to expect — The line being said right now, by either side; live while it is still being recognised or spoken. Replaced as the conversation moves on: draw the latest.
| Property | Type | Meaning |
|---|---|---|
final Role role | Role | Who said it: Role.agent or Role.customer. |
final String text | String | The words, as far as they have been said or recognised. |
final bool live | bool | True while the text is still being recognised or streamed, so show it as provisional. |
Its functions: Caption, settled — each with its parameters, what it returns, the errors it raises and an example.
Caption.Caption
Use it to build a caption by hand for a test or a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
role | Role | required | Who said it: Role.agent or Role.customer. |
text | String | required | The words, as far as they have been said or recognised. |
live | bool | false | True while the text is still being recognised or streamed, so show it as provisional. |
Returns — a new Caption.
Errors — none.
Caption.settled
Use it to mark a caption as finished.
Parameters — none.
Returns — Caption.
Errors — none.
Captions
Use it to keep a list of captions the way the bar does, so a sentence growing word by word stays one line.
abstract final class Captions
What to expect — The line being said right now, by either side; live while it is still being recognised or spoken. Replaced as the conversation moves on: draw the latest.
| Property | Type | Meaning |
|---|---|---|
static const int history | int | How many turns are kept. |
Its functions: fold — each with its parameters, what it returns, the errors it raises and an example.
Captions.fold
Use it to add a new caption to the list.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
prev | List<Caption> | required | The captions so far, oldest first. |
next | Caption | required | The newest caption: a live one replaces the open line of the same speaker; an empty one ends it. |
max | int | history | How many lines to keep (12 by default). |
Returns — List<Caption> — its fields: Caption. Example value: [].
Errors — none.
GraineCaptionsSwitch
Use it to give the customer a CC button: hide or show the line being said on the bar, and forget what was said, without ending the call.
abstract interface class GraineCaptionsSwitch
What to expect — GraineInApp.instance.voice implements it; each agent's voice has its own switch. It sits beside GraineCallState, as GraineCallFault does, so a call state of your own keeps compiling — implement it too to give the bar a switch. On by default (a caption nobody asked to hide is an accessibility default), and it holds for the rest of the app's run, from one call to the next. While it is off, GraineAgentBar hides its caption, as showCaptions: false does; what is said is still kept in captions. A change notifies the voice's listeners. New in 0.9.0.
| Property | Type | Meaning |
|---|---|---|
bool get captionsOn | bool | The CC switch: the bar draws the line being said only while it is on. On by default. What is said is kept (GraineCallState.captions) either way. |
Its functions: setCaptionsOn, clearCaptions — each with its parameters, what it returns, the errors it raises and an example.
GraineCaptionsSwitch.setCaptionsOn
Call it from your own CC button to hide or show the bar's caption.
Turns the captions on or off: the bar shows or hides the line being said. The call goes on, what is said is kept either way, and captionsOn follows at once.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
on | bool | required | true to show the caption; false to hide it. |
Returns — nothing; it returns when done.
Errors — none.
GraineCaptionsSwitch.clearCaptions
Call it to forget what has been said so far, without ending the call.
Empties captions — and so caption — without ending the call; a new call forgets them too. The switch stays as it is.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
Role
Read it to tell the agent's lines from the customer's.
enum Role { agent, customer }
What to expect — On every caption, on a call in the voice bar and on a native call alike.
| Case | Meaning |
|---|---|
agent | The agent's words, as they are said. |
customer | The customer's words, as they are recognised. |
Transport
Use it to choose how a call's audio travels: the standard path, or high quality (WebRTC) with the device's echo canceller.
enum Transport
What to expect — The dashboard's Call audio setting decides, unless you force one with GraineConfig(transport:). A call on webrtc that cannot connect falls back to websocket by itself; onTransport says which one carries it.
| Case | Meaning |
|---|---|
websocket('ws') | Raw PCM on the conversation socket. |
webrtc('rtc') | Audio in Opus, carried over WebRTC, with a jitter buffer and the device's echo cancellation. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The word on the wire and in the URL. |
Its functions: Transport, from — each with its parameters, what it returns, the errors it raises and an example.
Transport.Transport
The enum's constructor; use the values (Transport.websocket, Transport.webrtc).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The word on the wire and in the URL. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
Transport.from
Use it to read a transport from its word (ws, rtc).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String? | required | The transport's word: rtc is webrtc, anything else websocket. |
Returns — Transport. Example value: Transport.websocket.
Errors — none.
ConnectionQuality
Read it to tell the customer when their connection is the problem, not the agent.
enum ConnectionQuality
What to expect — How the connection is doing, reported as it changes. Draw it so the customer can tell when the network is the problem.
| Case | Meaning |
|---|---|
excellent | Round trip under 150 ms, jitter under 30 ms and loss under 2%: nothing to say. |
good | Worse than excellent but below every "poor" line: the call works. |
poor | Round trip of 400 ms or more, jitter of 80 ms or more, or loss of 8% or more — any one is enough. Say "Weak connection". |
lost | The device went offline during the call. |
unknown | No measurement yet — before the first one, and between calls. |
Its functions: classify — each with its parameters, what it returns, the errors it raises and an example.
ConnectionQuality.classify
Use it to turn one network measurement into the same word every Graine surface uses.
One sample → one word.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
rttMs | num? | required | The round-trip time, in ms. |
jitterMs | num? | required | The jitter, in ms. |
loss | num? | required | The packet loss, from 0 to 1. |
Returns — ConnectionQuality. Example value: ConnectionQuality.poor.
Errors — none.
CallPhase
Read it to know where the call stands in one word — to draw your own bar.
enum CallPhase
What to expect — How the connection is doing, reported as it changes. Draw it so the customer can tell when the network is the problem.
| Case | Meaning |
|---|---|
idle | No call; ready to start one. |
connecting | The page loading, or a call being placed. |
reconnecting | Either the page failed and is reloading, or the network cut the call off. |
thinking | The customer has finished speaking a sentence, and the agent's answer has not begun. |
speaking | The agent is talking. |
listening | The agent is waiting for the customer. |
ConnectStage
Read it to say where a call being placed is, so the customer waits instead of giving up.
enum ConnectStage
What to expect — How the connection is doing, reported as it changes. Draw it so the customer can tell when the network is the problem.
| Case | Meaning |
|---|---|
registering | Setting up a credential and a line — what happens on a cold start. |
dialling | The call is on its way to the agent. |
retrying | No answer came to the first attempt, so a new connection is being opened; on mobile data the cause is usually a connection the phone let go of while idle. |
switching | The call is moving to the other transport. |
| Property | Type | Meaning |
|---|---|---|
String get wire | String | The word on the wire. |
Its functions: from — each with its parameters, what it returns, the errors it raises and an example.
ConnectStage.from
Use it to read a connect stage from its word.
Maps a wire word to its stage. Returns null for a word this SDK does not recognise, and also for "failed", since that ends a connect instead of being one of its stages.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String? | required | The word on the wire. |
Returns — ConnectStage?. Example value: ConnectStage.registering.
Errors — none.
ConnectProgress
Use its numbers and words to say "Still connecting…" and "Couldn't connect" exactly as the SDK's bar does.
abstract final class ConnectProgress
What to expect — How the connection is doing, reported as it changes. Draw it so the customer can tell when the network is the problem.
| Property | Type | Meaning |
|---|---|---|
static const int slowConnectMs | int | The moment the status changes from "Connecting…" to "Still connecting…". It is later than a healthy connect takes (0.2–0.9 s warm, 1.5–2.5 s cold, on a good network) and comfortably short of the ten seconds after which people, given no explanation, decide it is broken. |
static const String stillConnecting | String | Shown for a slow connect, as long as the brand has kept the default connecting words. |
static const String couldNotConnect | String | Shown when the call could not be carried by either transport; the text uses a curly apostrophe. |
GraineConnectProgress
Read it to say where a call being placed is, when a connect is slow, and when one failed — for your own bar.
abstract interface class GraineConnectProgress
What to expect — How the connection is doing, reported as it changes. Draw it so the customer can tell when the network is the problem.
| Property | Type | Meaning |
|---|---|---|
ConnectStage? get connectStage | ConnectStage? | Where the call being placed is — registering, dialling, retrying or switching; null outside a connect. Say it: a bar that says "Reconnecting…" across a retry is one the customer waits for; "Connecting…" for eight seconds is one they close. |
bool get slowConnect | bool | Becomes true when the customer has been kept waiting on a connect — the bar showing while the page loads, or a call being placed — for longer than timing.slowConnectMs. |
bool get callFailed | bool | The last start could not be connected at all — neither way of carrying the audio worked. Unlike error (a setting someone must change), the network may be better in a moment, so a start simply tries again. A new start, a call that connects, or the bar closing all clear it. |
GraineCallFault
Read it to know when the agent's call cannot work until someone changes a setting, so your bar says "Unavailable".
abstract interface class GraineCallFault
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
String? get error | String? | A permanent problem with this agent's setup that the page reported, such as a transport that has not been configured; null when there is none. |
BarStatus
Read it to draw the bar's status line: its words, a loader, or the meter.
class BarStatus
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final String text | String | The status words, in sentence case, exactly as the SDK's bar shows them ("Listening", "Weak connection"). |
final String? waiting | String? | Set for a loader moment (connecting, reconnecting or thinking), which is drawn in place of text using the dashboard's loader and the words it has for that moment. |
final bool meter | bool | Show the four-bar meter (VoiceMeter) ahead of the words. |
final String? label | String? | Text the loader shows instead of the brand's waiting words. Only "Still connecting…" sets it, and only while the brand's words are still the defaults (connectingLook). |
Its functions: BarStatus — each with its parameters, what it returns, the errors it raises and an example.
BarStatus.BarStatus
Use it to build a status line by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String | required | The status words, in sentence case, exactly as the SDK's bar shows them ("Listening", "Weak connection"). |
waiting | String? | optional | Set for a loader moment (connecting, reconnecting or thinking), which is drawn in place of text using the dashboard's loader and the words it has for that moment. |
meter | bool | false | Show the four-bar meter (VoiceMeter) ahead of the words. |
label | String? | optional | Text the loader shows instead of the brand's waiting words. Only "Still connecting…" sets it, and only while the brand's words are still the defaults (connectingLook). |
Returns — a new BarStatus.
Errors — none.
agentBarStatus
Use it only to keep printing the older lower-case status words; new UIs use voiceBarStatus.
The bar's one word in lower case, as the bar said it before 0.3 — the network named before the agent takes the blame for it. Kept for apps that print these words; the bar now says voiceBarStatus.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
connectivity | GraineConnectivity | required | Whether the page that carries the call is there (GraineCallState.connectivity). |
online | bool? | required | Whether the device is online, as last reported; null when not reported yet. |
reconnecting | bool | required | The call is being re-established. |
connecting | bool | required | A call is being placed. |
ready | bool | required | The page is ready to start a call. |
muted | bool | required | The customer is muted. |
connected | bool | required | The call is connected. |
quality | ConnectionQuality | required | The connection's quality. |
agentSpeaking | bool | required | The agent is speaking. |
micDenied | bool | false | The last start was refused the microphone. |
Returns — String. Example value: 'speaking'.
Errors — none.
callPhase (function)
Use it to work out the call's phase from its state, exactly as the SDK does.
The call's phase, derived from its state as every Graine SDK derives it: thinking is the gap between the customer's last settled line and the agent's first words.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
reconnecting | bool | required | The call is being re-established. |
connectivity | GraineConnectivity | required | Whether the page that carries the call is there. |
connecting | bool | required | A call is being placed. |
ready | bool | required | The page is ready to start a call. |
connected | bool | required | The call is connected. |
caption | Caption? | required | The latest caption (GraineCallState.caption); a settled line from the customer means the agent is thinking. |
agentSpeaking | bool | false | The agent is speaking. |
Returns — CallPhase — its fields: CallPhase. Example value: CallPhase.idle.
Errors — none.
connectingLook
Use it to get what the bar says while a call is being placed.
What a call being placed says while it connects: a retry, or a switch to the other way of carrying the audio, says "Reconnecting…"; a slow connect says "Still connecting…" — but only while the brand's words for connecting are the default "Connecting…", so a wording someone chose is never replaced.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
stage | ConnectStage? | optional | Where the connect is (connectStage); null before the first word from the engine. |
slow | bool | false | The connect has run past GraineTiming.slowConnectMs. |
connectingText | String? | optional | The brand's words for connecting (the loader's), so a chosen wording is never replaced; "Connecting…" when left out. |
Returns — BarStatus — its fields: BarStatus. Example value: BarStatus('Reconnecting…', waiting: 'reconnecting').
Errors — none.
voiceBarStatus
Use it to get the bar's status line for the call's state, exactly as the SDK's bar says it.
The voice bar's status line
| Parameter | Type | Default | Meaning |
|---|---|---|---|
error | bool | false | The agent's setup is wrong (GraineCallFault.error is set): "Unavailable". |
inChat | bool | false | The bar shows the chat, not the call. |
chatOnline | bool | false | The chat is connected (with inChat). |
online | bool? | required | Whether the device is online; null when not reported yet. |
reconnecting | bool | required | The call is being re-established. |
connectivity | GraineConnectivity | required | Whether the page that carries the call is there. |
micDenied | bool | required | The last start was refused the microphone. |
ready | bool | required | The page is ready to start a call. |
connecting | bool | required | A call is being placed. |
muted | bool | required | The customer is muted. |
connected | bool | required | The call is connected. |
thinking | bool | false | The customer finished speaking and the agent has not answered yet. |
speaking | bool | required | The agent is speaking. |
quality | ConnectionQuality | required | The connection's quality. |
callFailed | bool | false | The last start could not be connected at all (GraineConnectProgress.callFailed). |
connectStage | ConnectStage? | optional | Where a connect is (GraineConnectProgress.connectStage). |
slowConnect | bool | false | The connect has run past GraineTiming.slowConnectMs. |
connectingText | String? | optional | The brand's words for connecting (the loader's); "Connecting…" when left out. |
Returns — BarStatus — its fields: BarStatus.
Errors — none.
VoiceMeter
Use it to draw the four-bar meter beside "Listening" and "Speaking" at the design's own pace.
abstract final class VoiceMeter
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
static const List<double> heights | List<double> | Each bar's height, as a fraction of height. |
static const double height | double | The meter's full height, in logical pixels: 12. |
static const double barWidth | double | Each bar's width, in logical pixels: 2.5. |
static const double gap | double | The space between two bars, in logical pixels: 2. |
static const double low | double | The bottom of the swing; each bar scales up from its base between this value and 1. |
static const int staggerMs | int | Bar i starts i × this late. |
Its functions: legMs, still, scale — each with its parameters, what it returns, the errors it raises and an example.
VoiceMeter.legMs
Use it to get how long one rise or fall of a meter bar takes.
How long one leg of the swing takes (from low to full, or from full back to low): max(420, durationMs × 3.2) ms.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
durationMs | int | required | The design's motion duration (tokens.motion.durationMs). |
Returns — double. Example value: 640.0.
Errors — none.
VoiceMeter.still
Use it to know whether the meter should stand still (no motion in the design, or the device asks for less).
True when the bars should stay still at full height: the design has no motion, or the OS has asked for less motion.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
durationMs | int | required | The design's motion duration; 0 when the device asks for less motion. |
Returns — bool. Example value: true.
Errors — none.
VoiceMeter.scale
Use it to get one meter bar's height at a moment.
Bar bar's height, as a fraction of VoiceMeter.height, elapsedMs after the meter appeared. Before its stagger a bar waits at its low point; then it rises for one leg and falls for the next, forever. ease shapes each leg; with no motion every bar is 1.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
bar | int | required | Which bar, 0–3. |
elapsedMs | double | required | How long since the meter appeared, in ms. |
durationMs | int | required | The design's motion duration. |
ease | double Function(double t)? | optional | The easing for each rise and fall (the SDK passes ease-in-out); linear when left out. |
Returns — double. Example value: 3.
Errors — none.
Placement
Use it to keep a dragged bar on screen the way the SDK does.
abstract final class Placement
What to expect — Arithmetic in logical pixels, the same on every Graine SDK, so an offset you persist means the same everywhere. The bar can never leave the screen.
| Property | Type | Meaning |
|---|---|---|
static const double dragSlop | double | A drag shorter than this on both axes counts as a tap, and that tap still has to work. |
Its functions: clampOffset, offsetDuringDrag, isTap — each with its parameters, what it returns, the errors it raises and an example.
Placement.clampOffset
Use it to keep a bar's offset inside the screen.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
offset | double | required | The wanted offset above the bar's resting place, in logical pixels. |
b | PlacementBounds | required | Where the bar may go. |
Returns — int. Example value: 3.
Errors — none.
Placement.offsetDuringDrag
Use it to move a bar while the customer drags it.
Computes the offset mid-drag as the starting offset plus the distance the finger has moved UP; because dy increases downward, it is subtracted.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
startOffset | double | required | The offset when the drag began. |
dy | double | required | How far the finger moved down since then, in logical pixels (negative is up). |
b | PlacementBounds | required | Where the bar may go. |
Returns — int. Example value: 3.
Errors — none.
Placement.isTap
Use it to tell a tap from the start of a drag.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
dx | double | required | How far the finger moved across, in logical pixels. |
dy | double | required | How far the finger moved down. |
Returns — bool. Example value: true.
Errors — none.
PlacementBounds
Use it to describe where a dragged bar may go.
class PlacementBounds
What to expect — Measured from the screen and the bar as last laid out; build new bounds when either changes.
| Property | Type | Meaning |
|---|---|---|
final double windowHeight | double | The screen's height. |
final double baseBottom | double | Where the bar sits with no offset. |
final double barHeight | double | The bar's rendered height, as last measured. |
final double topMargin | double | How much room to leave free at the top, for the status bar and the notch. |
Its functions: PlacementBounds — each with its parameters, what it returns, the errors it raises and an example.
PlacementBounds.PlacementBounds
Use it to build the bounds for Placement.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
windowHeight | double | required | The screen's height. |
baseBottom | double | required | Where the bar sits with no offset. |
barHeight | double | required | The bar's rendered height, as last measured. |
topMargin | double | 48 | How much room to leave free at the top, for the status bar and the notch. |
Returns — a new PlacementBounds.
Errors — none.
KeyboardLift
Use it to lift a bottom bar above the keyboard by exactly as much as it needs.
abstract final class KeyboardLift
What to expect — Public so a custom UI can reuse it; an integration does not need it.
Its functions: liftFor — each with its parameters, what it returns, the errors it raises and an example.
KeyboardLift.liftFor
Use it to get how far to lift the bar for the keyboard on screen now.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
keyboardHeight | double | required | The keyboard's height on screen — MediaQuery.viewInsetsOf(context).bottom. |
windowShrink | double | required | How much the window already shrank for the keyboard; 0 in Flutter, where the inset already accounts for it. |
Returns — int. Example value: 3.
Errors — none.
Several agents in one app
One app can run several agents, each with its own publishable key — a support agent in Help, a sales agent on Plans — and choose per screen which one the customer talks to. Configure each with GraineInApp.init(config, name: 'support') (see GraineInApp.init) and hand it to the views with app:.
- Each agent has its own session and design, chat, call, components, actions, prompt variables, and scheduling and memory requests.
- Shared by every agent: the install id; who is signed in (
identifyon any agent identifies the customer for all of them, andidentify(null)signs out everywhere); the memory choice; and the screen (setScreen,track,tap). - One conversation at a time: starting a call or a chat with one agent ends a live one with another.
- Engines: each agent the customer can call needs its own
GraineEnginenear the root; an agent you only chat with needs none. - Native calls:
GraineCalls.instance.startCall(agent: 'support')calls a named agent; a ring Graine sends for one rings as that agent.
An app with one agent changes nothing: GraineInApp.init(config) is the default agent, and every view draws it.
GraineInApp.named
Use it to reach an agent you configured under a name — in a screen that talks to that agent.
The agent configured under name (trimmed; empty means the default agent), or null.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The name the agent was configured under. |
Returns — GraineInApp? — the agent, or null when none was configured under that name.
Errors — none.
GraineInApp.all
Use it to go through every agent the app configured — to register an action with each, say, or to check one exists.
Every configured agent, by the name it was configured under, in the order they were configured — the default agent under 'default'. Unmodifiable; empty before the first init.
Parameters — none.
Returns — Map<String, GraineInApp>. Example value: {'default': GraineInApp, 'support': GraineInApp}.
Errors — none.
GraineInApp.instance
Use it to reach the default agent anywhere in your app after init.
The default agent: the one init configured without a name — or, in an app that named every agent, the first one configured. Every view draws it unless you hand it another with app:.
Parameters — none.
Returns — GraineInApp.
Errors — StateError ("GraineInApp.init(config) has not been called.") before init; ask maybeInstance when you are not sure.
GraineInApp.maybeInstance
Use it to ask whether the SDK has been configured yet, without the error instance throws before init.
The default agent, or null before init.
Parameters — none.
Returns — GraineInApp?. Example value: null before init.
Errors — none.
GraineInApp.defaultName
Use it to name the default agent explicitly — for example in startCall(agent:) or when comparing a call's agent.
The name of the default agent: the one init configures when given no name (or an empty one), which instance returns, and which a native call's agent names.
Parameters — none.
Returns — String. Example value: 'default'.
Errors — none.
GraineInApp.name
Read it to know which agent an instance is — the name it was configured under.
The name this agent was configured under — trimmed; defaultName for the default agent.
Parameters — none.
Returns — String. Example value: 'support'.
Errors — none.
Screen context, actions and components
Tell the agent what the customer is looking at — the screen, its fields and how each is doing — so it can help with exactly that; let it act in your app through the actions you register; and draw the components it shows (product lists, choices, time slots, information cards) in your design. Everything that leaves the device is masked first; the friction rules let the agent speak up when a customer looks stuck.
GraineInApp.setVariables
Call it when something the agent's prompt uses changes at runtime — a plan, a cart total, a language.
Prompt variables from the app's own data, for this agent. Merged into what is there: null under a key removes it; null for the whole map clears them all. Values become strings (an integer never gains ".0"; maps and lists are dropped) and are masked on the device. They reach the next conversation, and a ready engine page receives them at once. A conversation that starts with a ticket carries them on its ticket — since 0.8.0 the chat's are no longer added to that connection's address — and one without a ticket carries them in its address. A conversation carries up to 12 variables, about 1 KB: past that, the biggest are left off first, who_called and call_reason last.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
values | Map<String, Object?>? | required | The variables by name. Merged over what is there: a null value removes its variable; null for the whole map clears them all. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.currentVariables
Call it to see exactly which prompt variables the agent gets now, after masking.
Every variable the agent will receive, merged in precedence order: the dashboard's defaults, then GraineConfig.variables, then setVariables, then the traits from identify (without the identifying trait once the configuration has loaded).
Parameters — none.
Returns — Map<String, String>.
Errors — none.
GraineInApp.setScreen
Call it whenever the customer reaches a screen, so the agent knows what they are looking at and which fields need them.
What the customer is looking at; null forgets it. Call it on every meaningful change. Values are masked on the device before they leave, and an unchanged screen is not resent. The first change goes out at once; a burst after it is coalesced into one more update at the end of a 400 ms window, so the agent's opening line is never a screen behind. The screen is the app's: every agent hears it and tells its own conversation while one is live. A new screen id starts a new visit for friction detection.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
next | GraineScreen? | required | What the customer can see now; nil clears it. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.updateField
Call it when one field on the current screen changes — typed, validated, cleared — without describing the whole screen again.
Replaces the current screen's field of the same name, or adds it after the others. Does nothing before a screen is set (the next setScreen carries the field itself) or for a field with an empty name.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
field | GraineField | required | The field: its name, label, value (masked on the device) and status. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.removeField
Call it when a field leaves the current screen.
Removes a field from the current screen. Does nothing if no screen is set or the field was never reported.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The field's name. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.clearScreen
Call it when the customer leaves a screen you described and the next one has nothing to say.
Forgets the screen, but only if screenId (when given) is still the current screen's id. Call it from a screen's cleanup: a navigator keeps the old screen through its exit transition, and an unconditional setScreen(null) there would wipe the screen that has just replaced it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
screenId | String? | optional | The screen's name. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.track
Call it to tell the agent something the customer did — added to cart, opened help — so it can mention it.
A product event the agent is told about without being interrupted. It rides the next context update; the last ten events are kept. Every agent records it. An empty name is ignored.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The product event's name, for example "plan_viewed". |
data | Map<String, Object?> | const <String, Object?>{} | Details of the event, by name; masked on the device. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.tap
Call it to tell the agent the customer tapped a control you name yourself.
The customer tapped a control you name: recorded as "tap:<name>" in the recent events (the name cut to one line of at most 40 characters), so the agent knows what they just did. Context, not news: it goes out at the end of the 400 ms window. Every agent records it. An empty name is ignored.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The control's name, as the agent sees it: tap:<name>. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.captureTap
Called by GraineEngine for every tap it sees; call it yourself only if you capture taps another way.
A tap anywhere in the app. GraineEngine reports every tap it sees; an app with its own gesture layer may call it too. On a control with an accessibility label it is recorded as "tap:<label>" (one line, at most 40 characters); elsewhere as "tap:screen" with x and y in logical pixels. Recorded only by agents with GraineConfig.captureTaps on that have a screen set, and at most two taps a second across the app. Context, not news: it rides the next update.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
x | double | required | The horizontal position, in points. |
y | double | required | The vertical position, in points. |
label | String? | optional | The tapped control's accessibility label; null for a tap anywhere else. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.noteInteraction
Call it when the customer does something on the screen that setScreen does not show, so the stuck-customer timer restarts.
Tells the SDK the customer did something other than editing a field, such as scrolling a list or opening a picker. Restarts every agent's idle clock. Field edits do not count.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.registerAction
Call it to let the agent do something in your app — open a screen, apply a coupon — by name, with your handler.
Something the agent can do in the app, for this agent. Declare the same action on the agent in the dashboard: a handler with no declaration is never offered, and a declaration with no handler is refused. The handler may answer synchronously or with a Future and must answer within six seconds, or the agent is told it was not done; returning null means ok, and a throw is answered as error. Registering a name again replaces its handler. The returned function unregisters it, if it is still the one registered.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name, exactly as it is declared on the agent in the dashboard (Embed & Widgets → Actions). |
handler | GraineActionHandler | required | The function that runs it. It receives the agent's arguments and returns a result: ok, refused or error. |
Returns — void Function() — unregisters it.
Errors — none.
GraineInApp.checkActions
Call it once while you build, to compare the actions your app registers with the ones the dashboard declares.
Compares what this build registered with what the agent declares: usable (both), undeclared (registered, not declared on the agent), unhandled (declared, not registered). Declarations come from the agent's configuration, so read it after the session has loaded; log it once at startup.
Parameters — none.
Returns — Map<String, List<String>>.
Errors — none.
GraineInApp.executeAction
Call it to run one of your registered actions as the agent would — from a component's button, or in a test.
Runs one registered action exactly as the agent would, against the six-second deadline, and reports onActionRequested and onActionCompleted to listeners. Always completes: an unknown name answers refused; a throw or a timeout answers error.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name, as registered. |
args | Map<String, Object?> | required | Its arguments, as the agent would pass them. |
Returns — Future<ActionResult> — its fields: ActionResult.
Errors — none.
GraineInApp.configureFriction
Call it to change, for this app, when the agent speaks up for a customer who looks stuck.
Replaces the app's layer of friction rules (the layer GraineConfig.friction set). Safe at any time. The rules in force become the defaults, then the dashboard's, then override.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
override | FrictionConfig? | required | A value to use instead. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.clearPendingWidget
Call it when your own UI has dealt with the component the agent drew, so no view draws it again.
Forgets the retained component.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineVoice.reportEvent
Call it to tell the agent, during a call, about something it may want to speak up about.
Reports something that has happened which the agent may choose to comment on.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | What happened, in a word — the agent may speak up about it. |
detail | String? | optional | A sentence about it, or nothing. |
data | Map<String, Object?> | const <String, Object?>{} | Facts about it, as JSON values (masked before they leave the device). |
Returns — nothing; it returns when done.
Errors — none.
GraineScreen
Use it to describe what the customer is looking at: the screen, where it sits in a flow, its fields and what the agent may do there.
class GraineScreen
What to expect — What you tell the agent the customer can see. Values are masked on the device before they leave it; an unchanged screen is not sent again; the first change goes at once and later ones at most every 400 ms.
| Property | Type | Meaning |
|---|---|---|
final String screen | String | An id for the screen that never changes; analytics rely on it, so do not vary it. |
final String? title | String? | The screen's title as the customer sees it ("Delivery address"); the agent names the screen by it. Null: the screen id is used. |
final GraineJourney? journey | GraineJourney? | Where the screen sits in a flow (step 2 of 4) and what comes next; null for a screen in no flow. |
final List<GraineField> fields | List<GraineField> | The inputs on the screen and how each is doing — what lets the agent name the field that needs the customer. Empty for a screen with no inputs. |
final String? error | String? | An error banner for the whole screen, separate from any field's own error. |
final Map<String, Object?> data | Map<String, Object?> | Anything else the agent should know. |
final List<String>? availableActions | List<String>? | Which of your registered actions the agent may use on this screen. Null allows every registered action; [] allows none. |
Its functions: GraineScreen, copyWith, withField, withoutField — each with its parameters, what it returns, the errors it raises and an example.
GraineScreen.GraineScreen
Use it to describe a screen for setScreen.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
screen | String | required | An id for the screen that never changes; analytics rely on it, so do not vary it. |
title | String? | optional | The screen's title as the customer sees it ("Delivery address"); the agent names the screen by it. Null: the screen id is used. |
journey | GraineJourney? | optional | Where the screen sits in a flow (step 2 of 4) and what comes next; null for a screen in no flow. |
fields | List<GraineField> | const <GraineField>[] | The inputs on the screen and how each is doing — what lets the agent name the field that needs the customer. Empty for a screen with no inputs. |
error | String? | optional | An error banner for the whole screen, separate from any field's own error. |
data | Map<String, Object?> | const <String, Object?>{} | Anything else the agent should know. |
availableActions | List<String>? | optional | Which of your registered actions the agent may use on this screen. Null allows every registered action; [] allows none. |
Returns — a new GraineScreen.
Errors — none.
GraineScreen.copyWith
Use it to make the same screen with new fields.
This screen with fields in place of its own.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
fields | List<GraineField>? | optional | The inputs on the screen and how each is doing — what lets the agent name the field that needs the customer. Empty for a screen with no inputs. |
Returns — GraineScreen.
Errors — none.
GraineScreen.withField
Use it to make the same screen with one field replaced or added.
Returns a copy of this screen where field replaces the field with the same name, or is appended after the existing fields if no field has that name.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
field | GraineField | required | The field to put in place of the one with its name — or add after the others. |
Returns — GraineScreen.
Errors — none.
GraineScreen.withoutField
Use it to make the same screen without one field.
Returns this screen minus the field called name; if no field has that name, the same screen is returned.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The name of the field to leave out. |
Returns — GraineScreen.
Errors — none.
GraineField
Use it to describe one input on a screen — its label, value and status — so the agent can name the field that needs the customer.
class GraineField
What to expect — One input on the screen. Its status — empty, filled, invalid, pending or locked — is what lets the agent name the field that is wrong.
| Property | Type | Meaning |
|---|---|---|
final String name | String | The field's stable id ("email"). updateField and removeField find a field by it. |
final String? label | String? | The field's label as the customer sees it ("Email address"); the agent names the field by it. Null: the name is used. |
final String? value | String? | The real value. |
final FieldStatus? status | FieldStatus? | How the field is doing — empty, filled, invalid, pending or locked. What makes the agent proactive: after a pause it names a field that is invalid or empty. |
final String? error | String? | The validation message that is really on screen, which the agent can offer to help fix. |
final bool optional | bool | This field may be left empty: it stays in the frame but is not counted. |
Its functions: GraineField — each with its parameters, what it returns, the errors it raises and an example.
GraineField.GraineField
Use it to describe one field for GraineScreen or updateField.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The field's stable id ("email"). updateField and removeField find a field by it. |
label | String? | optional | The field's label as the customer sees it ("Email address"); the agent names the field by it. Null: the name is used. |
value | String? | optional | The real value. |
status | FieldStatus? | optional | How the field is doing — empty, filled, invalid, pending or locked. What makes the agent proactive: after a pause it names a field that is invalid or empty. |
error | String? | optional | The validation message that is really on screen, which the agent can offer to help fix. |
optional | bool | false | This field may be left empty: it stays in the frame but is not counted. |
Returns — a new GraineField.
Errors — none.
FieldStatus
Use it to say how a field is doing, so the agent can point at the one that is empty or wrong.
enum FieldStatus
What to expect — One input on the screen. Its status — empty, filled, invalid, pending or locked — is what lets the agent name the field that is wrong.
| Case | Meaning |
|---|---|
empty('empty') | Nothing entered yet. Counts as outstanding unless the field is optional. |
filled('filled') | Entered, and nothing is wrong with it. |
invalid('invalid') | Entered, but wrong — put the message you show in GraineField.error, so the agent can offer to fix it. |
pending('pending') | Being checked or loaded (an address lookup, a code being verified). Not outstanding. |
locked('locked') | Shown but not the customer's to change. Never outstanding. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The status as it is sent — the same word as the value's name. |
Its functions: FieldStatus, fromWire — each with its parameters, what it returns, the errors it raises and an example.
FieldStatus.FieldStatus
The enum's constructor; use the values (FieldStatus.empty, FieldStatus.invalid, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The status as it is sent — the same word as the value's name. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
FieldStatus.fromWire
Use it to read a field status from its word.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String? | required | The status's word; anything else reads as null. |
Returns — FieldStatus?. Example value: FieldStatus.empty.
Errors — none.
GraineJourney
Use it to say where a screen sits in a flow (step 2 of 4) and what comes next, so the agent can answer "what happens after this?".
class GraineJourney
What to expect — What you tell the agent the customer can see. Values are masked on the device before they leave it; an unchanged screen is not sent again; the first change goes at once and later ones at most every 400 ms.
| Property | Type | Meaning |
|---|---|---|
final String name | String | The flow's name as the customer would say it ("Checkout"). |
final int? step | int? | Which step of the flow this screen is, counting from 1; null when you do not number the steps. |
final int? of | int? | How many steps the flow has; null when it varies or you do not say. |
final String? next | String? | What comes after this step; if asked, the agent repeats this instead of making something up. |
Its functions: GraineJourney — each with its parameters, what it returns, the errors it raises and an example.
GraineJourney.GraineJourney
Use it to describe a screen's place in a flow.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The flow's name as the customer would say it ("Checkout"). |
step | int? | optional | Which step of the flow this screen is, counting from 1; null when you do not number the steps. |
of | int? | optional | How many steps the flow has; null when it varies or you do not say. |
next | String? | optional | What comes after this step; if asked, the agent repeats this instead of making something up. |
Returns — a new GraineJourney.
Errors — none.
GraineActionHandler
Implement it to run one action the agent asks for, and answer what happened.
typedef GraineActionHandler = FutureOr<ActionResult?> Function( Map<String, Object?> args);
What to expect — What your app answers an agent's action with: ok (with an optional sentence and data), refused (the customer declined) or error.
ActionResult
Return it from an action handler to tell the agent what happened — it speaks about exactly this.
class ActionResult
What to expect — What your app answers an agent's action with: ok (with an optional sentence and data), refused (the customer declined) or error.
| Property | Type | Meaning |
|---|---|---|
final ActionStatus status | ActionStatus | What happened: ok (the agent says it is done), refused (not done, with a reason) or error (it failed). |
final String message | String | What the agent is told, in a sentence — the reason for a refusal, what failed, or a detail of what was done. Empty: the status alone. |
final Map<String, Object?> data | Map<String, Object?> | Anything the agent should know about the result (an order number, a new total), as JSON values. Empty by default. |
Its functions: ActionResult, ok, refused, error — each with its parameters, what it returns, the errors it raises and an example.
ActionResult.ActionResult
Use it to answer with a status, a message and data of your choosing.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
status | ActionStatus | required | What happened: ok (the agent says it is done), refused (not done, with a reason) or error (it failed). |
message | String | '' | What the agent is told, in a sentence — the reason for a refusal, what failed, or a detail of what was done. Empty: the status alone. |
data | Map<String, Object?> | const <String, Object?>{} | Anything the agent should know about the result (an order number, a new total), as JSON values. Empty by default. |
Returns — a new ActionResult.
Errors — none.
ActionResult.ok
Use it to answer that the action was done.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | String | '' | What the agent may add about it; empty by default. |
data | Map<String, Object?> | const <String, Object?>{} | Anything the agent should know about the result; empty by default. |
Returns — a new ActionResult with status ActionStatus.ok.
Errors — none.
ActionResult.refused
Use it to answer that the action was not done, and why — the agent passes the reason on.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | String | required | Why it was not done — the agent passes it on. |
Returns — a new ActionResult with status ActionStatus.refused and no data.
Errors — none.
ActionResult.error
Use it to answer that the action failed.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | String | required | What went wrong, in a sentence. |
Returns — a new ActionResult with status ActionStatus.error and no data.
Errors — none.
ActionStatus
Read it to know what an action's answer told the agent: done, refused or failed.
enum ActionStatus
What to expect — What your app answers an agent's action with: ok (with an optional sentence and data), refused (the customer declined) or error.
| Case | Meaning |
|---|---|
ok('ok') | Done: the agent tells the customer it is done. |
refused('refused') | Not done, on purpose: the agent passes on the reason in ActionResult.message. |
error('error') | Failed: the agent says it could not do it. A handler that throws, or does not answer in time, answers this. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The status as it is sent — the same word as the value's name. |
Its functions: ActionStatus — each with its parameters, what it returns, the errors it raises and an example.
ActionStatus.ActionStatus
The enum's constructor; use the values (ActionStatus.ok, refused, error).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The status as it is sent — the same word as the value's name. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
Masking
Use it to see — and extend — what the SDK masks before anything leaves the device.
abstract final class Masking
What to expect — Applied on the device, before anything leaves it: card and account numbers, government ID numbers, phone numbers and email addresses are replaced; rules you add apply as well.
Its functions: mask, addRule, clearCustomRules, deep, expandReplacement — each with its parameters, what it returns, the errors it raises and an example.
Masking.mask
Use it to see how a piece of text leaves the device.
Masks identifiers in a single string, applying the five built-in rules first and then the rules the app added (addRule).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
input | String | required | The text to mask. |
Returns — String. Example value: 'Mail me at [EMAIL]'.
Errors — none.
Masking.addRule
Call it at launch to mask a value shape only your app knows, such as an account number.
A rule for a value shape only your app knows — an account number, an order reference.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
pattern | RegExp | required | What to mask: every match is replaced. |
token | String | '[REDACTED]' | What replaces it; [REDACTED] by default. It may use $1, $&, $$ and $<name> as a JavaScript replacement does. |
Returns — nothing; it returns when done.
Errors — none.
Masking.clearCustomRules
Call it to remove the rules you added (the built-in ones stay).
Meant for tests alone; in production, register rules a single time when the app starts.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
Masking.deep
Use it to mask every text inside a map or a list, as the SDK masks the screen context.
Applies masking to all strings inside a JSON value, however deeply nested.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
value | Object? | required | A JSON value: every text inside it is masked; keys, numbers and booleans are left as they are. |
Returns — Object?. Example value: null.
Errors — none.
Masking.expandReplacement
Use it to see how a rule's replacement is written for one match.
Writes a rule's replacement for one match, reading its $ patterns ($1, $&, $$, $<name>) exactly as a JavaScript replacement string does — so a rule written for the website or React Native means the same here.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
token | String | required | A rule's replacement, with its $ patterns. |
m | Match | required | One match of the rule. |
Returns — String. Example value: 'ORD-[1234]'.
Errors — none.
FrictionConfig
Use it to set, for this app, when the agent speaks up for a customer who looks stuck — over the dashboard's rules.
class FrictionConfig
What to expect — Friction is the SDK noticing a customer who is stuck — stalled on a step, a field error repeated, looping between screens, rage taps, an incomplete submit, an error on the screen. The dashboard's rules apply unless the app overrides them; a signal lets the agent offer help.
| Property | Type | Meaning |
|---|---|---|
final bool? enabled | bool? | Turns the stuck-customer rule on or off for this app; null inherits the dashboard's (on by default). |
final int? idleAfterMs | int? | Staying on one screen for this long raises stalled_on_step. |
final int? cooldownMs | int? | The shortest time allowed between two signals on one screen. |
final int? cooldownSeconds | int? | The pacing Graine applies to interventions the agent makes without being asked. |
final int? maxPerSession | int? | At most this many unasked interventions from the agent in one conversation; null inherits (default 3). |
final bool? openLauncher | bool? | Passed through to GraineListener.onFriction, for an app that opens its own launcher. |
final String? message | String? | What the agent is told instead of the built-in sentence, with the placeholders {title}, {screen}, {seconds}, {field} and {error}. |
final bool? requireOutstandingField | bool? | Count the customer as stuck only while a field still needs them (invalid, or empty and not optional), with the clock running from when it started needing them. Default true; false counts any idle time on the screen. |
final Map<String, FrictionScreenRule> screens | Map<String, FrictionScreenRule> | Per-screen rules, keyed by the screen id you pass to setScreen — to switch the rule off, or change it, on one screen. |
Its functions: FrictionConfig, fromJson — each with its parameters, what it returns, the errors it raises and an example.
FrictionConfig.FrictionConfig
Use it to build the app's friction rules for GraineConfig(friction:) or configureFriction.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
enabled | bool? | optional | Turns the stuck-customer rule on or off for this app; null inherits the dashboard's (on by default). |
idleAfterMs | int? | optional | Staying on one screen for this long raises stalled_on_step. |
cooldownMs | int? | optional | The shortest time allowed between two signals on one screen. |
cooldownSeconds | int? | optional | The pacing Graine applies to interventions the agent makes without being asked. |
maxPerSession | int? | optional | At most this many unasked interventions from the agent in one conversation; null inherits (default 3). |
openLauncher | bool? | optional | Passed through to GraineListener.onFriction, for an app that opens its own launcher. |
message | String? | optional | What the agent is told instead of the built-in sentence, with the placeholders {title}, {screen}, {seconds}, {field} and {error}. |
requireOutstandingField | bool? | optional | Count the customer as stuck only while a field still needs them (invalid, or empty and not optional), with the clock running from when it started needing them. Default true; false counts any idle time on the screen. |
screens | Map<String, FrictionScreenRule> | const <String, FrictionScreenRule>{} | Per-screen rules, keyed by the screen id you pass to setScreen — to switch the rule off, or change it, on one screen. |
Returns — a new FrictionConfig.
Errors — none.
FrictionConfig.fromJson
Use it to read friction rules from the dashboard's JSON.
Builds the dashboard's layer out of the friction object in the session.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
o | Map<String, Object?>? | required | The object. |
Returns — FrictionConfig?. Example value: null.
Errors — none.
FrictionScreenRule
Use it to change the friction rules on one screen — or switch them off there.
class FrictionScreenRule
What to expect — Friction is the SDK noticing a customer who is stuck — stalled on a step, a field error repeated, looping between screens, rage taps, an incomplete submit, an error on the screen. The dashboard's rules apply unless the app overrides them; a signal lets the agent offer help.
| Property | Type | Meaning |
|---|---|---|
final bool? ignore | bool? | Turns friction detection off entirely for this screen; a person reading terms, for example, is not stuck. |
final int? idleAfterMs | int? | How long the customer may stay idle on this screen before they count as stuck, in ms; 0 or less switches the rule off here; null inherits. |
final String? message | String? | What the agent is told on this screen instead of the built-in sentence, with the same placeholders as FrictionConfig.message; null inherits. |
Its functions: FrictionScreenRule — each with its parameters, what it returns, the errors it raises and an example.
FrictionScreenRule.FrictionScreenRule
Use it to build one screen's rule for FrictionConfig.screens.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
ignore | bool? | optional | Turns friction detection off entirely for this screen; a person reading terms, for example, is not stuck. |
idleAfterMs | int? | optional | How long the customer may stay idle on this screen before they count as stuck, in ms; 0 or less switches the rule off here; null inherits. |
message | String? | optional | What the agent is told on this screen instead of the built-in sentence, with the same placeholders as FrictionConfig.message; null inherits. |
Returns — a new FrictionScreenRule.
Errors — none.
FrictionSignal
Read it in onFriction to know that a customer looks stuck, where, and what the agent was told.
class FrictionSignal
What to expect — Friction is the SDK noticing a customer who is stuck — stalled on a step, a field error repeated, looping between screens, rage taps, an incomplete submit, an error on the screen. The dashboard's rules apply unless the app overrides them; a signal lets the agent offer help.
| Property | Type | Meaning |
|---|---|---|
final String name | String | What kind of friction it is: stalled_on_step (the customer stayed idle on a step). |
final String screen | String | The id of the screen the customer is stuck on, as you passed it to setScreen. |
final String detail | String | The sentence the agent is told, in plain words (your message with its placeholders filled, or the built-in one). |
final Map<String, Object?> data | Map<String, Object?> | The facts behind it: seconds idle, the field that needs the customer and its error (empty when there is none). |
final int cooldownSeconds | int | The least time between two unasked interventions from the agent, in seconds. |
final int maxPerSession | int | The most unasked interventions the agent makes in one conversation. |
final bool openLauncher | bool | True when the rules ask your app to open its own launcher or bar for the customer. |
Its functions: FrictionSignal — each with its parameters, what it returns, the errors it raises and an example.
FrictionSignal.FrictionSignal
Use it to build a signal by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | What kind of friction it is: stalled_on_step (the customer stayed idle on a step). |
screen | String | required | The id of the screen the customer is stuck on, as you passed it to setScreen. |
detail | String | required | The sentence the agent is told, in plain words (your message with its placeholders filled, or the built-in one). |
data | Map<String, Object?> | required | The facts behind it: seconds idle, the field that needs the customer and its error (empty when there is none). |
cooldownSeconds | int | required | The least time between two unasked interventions from the agent, in seconds. |
maxPerSession | int | required | The most unasked interventions the agent makes in one conversation. |
openLauncher | bool | required | True when the rules ask your app to open its own launcher or bar for the customer. |
Returns — a new FrictionSignal.
Errors — none.
FrictionRules
Read it to see the friction rules in force: the defaults, the dashboard's and the app's, applied in that order.
class FrictionRules
What to expect — Friction is the SDK noticing a customer who is stuck — stalled on a step, a field error repeated, looping between screens, rage taps, an incomplete submit, an error on the screen. The dashboard's rules apply unless the app overrides them; a signal lets the agent offer help.
| Property | Type | Meaning |
|---|---|---|
final bool enabled | bool | Whether the stuck-customer rule runs at all (default true). |
final int? idleAfterMs | int? | Null: the idle rule is off. |
final int cooldownMs | int | The least time between two signals on the same screen, in ms (default 60 000). |
final int cooldownSeconds | int | The least time between two unasked interventions from the agent, in seconds (default 20). |
final int maxPerSession | int | The most unasked interventions in one conversation (default 3). |
final bool openLauncher | bool | Ask your app to open its own launcher or bar on a signal (default false). |
final String message | String | The sentence the agent is told; empty: the built-in one. |
final bool requireOutstandingField | bool | Count a customer as stuck only while a field still needs them (default true). |
final Map<String, FrictionScreenRule> screens | Map<String, FrictionScreenRule> | Per-screen rules, keyed by screen id. |
Its functions: FrictionRules, forScreen — each with its parameters, what it returns, the errors it raises and an example.
FrictionRules.FrictionRules
Use it to build rules by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
enabled | bool | true | Whether the stuck-customer rule runs at all (default true). |
idleAfterMs | int? | 45000 | Null: the idle rule is off. |
cooldownMs | int | 60000 | The least time between two signals on the same screen, in ms (default 60 000). |
cooldownSeconds | int | 20 | The least time between two unasked interventions from the agent, in seconds (default 20). |
maxPerSession | int | 3 | The most unasked interventions in one conversation (default 3). |
openLauncher | bool | false | Ask your app to open its own launcher or bar on a signal (default false). |
message | String | '' | The sentence the agent is told; empty: the built-in one. |
requireOutstandingField | bool | true | Count a customer as stuck only while a field still needs them (default true). |
screens | Map<String, FrictionScreenRule> | const <String, FrictionScreenRule>{} | Per-screen rules, keyed by screen id. |
Returns — a new FrictionRules.
Errors — none.
FrictionRules.forScreen
Use it to see the rules in force on one screen.
The rules that apply to one screen: the top-level rules, with that screen's overrides applied.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String? | required | The screen id, as passed to setScreen; null for no screen. |
Returns — FrictionForScreen — its fields: FrictionForScreen.
Errors — none.
FrictionForScreen
Read it as the friction rules in force on one screen.
class FrictionForScreen
What to expect — Worked out by FrictionRules.forScreen for the screen in view; it changes when the screen or the rules do.
| Property | Type | Meaning |
|---|---|---|
final bool ignore | bool | True when the rule is off on this screen. |
final int? idleAfterMs | int? | How long the customer may stay idle here before they count as stuck, in ms; null: the rule is off here. |
final String message | String | The sentence the agent is told here; empty: the built-in one. |
Its functions: FrictionForScreen — each with its parameters, what it returns, the errors it raises and an example.
FrictionForScreen.FrictionForScreen
Use it to build one screen's rules by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
ignore | bool | required | True when the rule is off on this screen. |
idleAfterMs | int? | required | How long the customer may stay idle here before they count as stuck, in ms; null: the rule is off here. |
message | String | required | The sentence the agent is told here; empty: the built-in one. |
Returns — a new FrictionForScreen.
Errors — none.
Friction
Use it to apply layers of friction rules the way the SDK does.
abstract final class Friction
What to expect — Public so a custom UI can reuse it; an integration does not need it.
Its functions: resolve — each with its parameters, what it returns, the errors it raises and an example.
Friction.resolve
Use it to get the rules in force from the defaults and your layers.
Starts from the defaults and applies each layer in turn; a layer changes only the settings it names.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
layers | List<FrictionConfig?> | required | The layers in order — usually the dashboard's, then the app's; a null layer is skipped. |
Returns — FrictionRules — its fields: FrictionRules.
Errors — none.
FrictionDetector
Use it to run the stuck-customer rule yourself — the SDK runs one for every agent.
class FrictionDetector
What to expect — Friction is the SDK noticing a customer who is stuck — stalled on a step, a field error repeated, looping between screens, rage taps, an incomplete submit, an error on the screen. The dashboard's rules apply unless the app overrides them; a signal lets the agent offer help.
| Property | Type | Meaning |
|---|---|---|
FrictionRules get rules | FrictionRules | The rules it applies now. |
Its functions: FrictionDetector, configure, onScreen, onInteraction, onCall, idleDueIn, onIdle, outstanding, fill — each with its parameters, what it returns, the errors it raises and an example.
FrictionDetector.FrictionDetector
Use it to make a detector with the rules to apply.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
rules | FrictionRules | const FrictionRules() | The rules it applies now. |
gateOnCall | bool | false | Run the idle clock only while a call is live (the SDK passes true). |
Returns — a new FrictionDetector.
Errors — none.
FrictionDetector.configure
Use it to change the rules a detector applies.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
next | FrictionRules | required | The rules to apply from now on. |
Returns — nothing; it returns when done.
Errors — none.
FrictionDetector.onScreen
Call it when the screen changes.
The app reported a screen.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
next | GraineScreen? | required | The screen now; null when none is set. |
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
FrictionDetector.onInteraction
Call it when the customer does something, so the idle clock restarts.
Records that the customer acted, which restarts the idle clock.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
FrictionDetector.onCall
Call it when a call connects or ends.
A call connected or ended.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
live | bool | required | true when a call connected, false when it ended. |
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
FrictionDetector.idleDueIn
Use it to know when to check again.
The time left before the idle rule fires, or null when it should not fire.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — int?. Example value: 3.
Errors — none.
FrictionDetector.onIdle
Call it when the idle timer goes off, to get the signal to send, if any.
The idle timer went off.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — FrictionSignal? — its fields: FrictionSignal. Example value: null.
Errors — none.
FrictionDetector.outstanding
Use it to list the fields the customer still has to deal with.
What the customer still has to deal with.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
fields | List<GraineField> | required | The screen's fields. |
Returns — List<GraineField> — its fields: GraineField. Example value: [].
Errors — none.
FrictionDetector.fill
Use it to fill a message's placeholders the way the SDK does.
Fills {name} placeholders; an unknown one becomes empty.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
template | String | required | The message with {title}, {screen}, {seconds}, {field} and {error} placeholders. |
vars | Map<String, Object?> | required | The values by placeholder name; an unknown placeholder becomes empty. |
Returns — String. Example value: 'Stuck on Delivery address for 45s'.
Errors — none.
GraineComponents
Use it to draw the components the agent shows — or answer them from your own UI.
class GraineComponents extends ChangeNotifier
What to expect — A component the agent drew — a product list, choices, time slots, an information card — with the data it was drawn from. The SDK's views draw it in your design.
| Property | Type | Meaning |
|---|---|---|
final void Function(String widgetId, Map<String, Object?> data, String summary) | nothing | Called when the customer answers, to pass the answer to the agent; the SDK sends it to whichever of the call or the chat drew the component. |
final Future<ActionResult> Function(String name, Map<String, Object?> args) | Future<ActionResult> | Runs an in-app action from a component; in the SDK this is GraineInApp.executeAction. |
final void Function(String name, String detail, Map<String, Object?> data) | nothing | Passes the agent a quiet note; the SDK sends it to the live call and the chat. |
GraineInApp? get app | GraineInApp? | The agent these components belong to, or null when they stand alone. |
bool get fromChat | bool | True when the component on screen came from the typed chat rather than a call. Nothing is listening then, so its view does not mention listening. |
GraineWidget? get widget | GraineWidget? | The component on screen, or null. |
WidgetContent? get content | WidgetContent? | The content widget boils down to — rows, chips, days — plus the answer that each tap sends. |
WidgetLook? get look | WidgetLook? | How widget asked to look. |
WidgetPending? get loading | WidgetPending? | A component that has been announced but is still loading; otherwise null. |
WidgetAnswered? get answered | WidgetAnswered? | The last answer, kept on screen as one line. |
bool get awaitingReply | bool | True after the customer answers and before the agent begins its reply. |
GraineWidget? get closed | GraineWidget? | The most recent component that was closed unanswered, so it can be offered with a "show it again". |
Its functions: GraineComponents, present, presentPending, answer, dismiss, reopen, reset — each with its parameters, what it returns, the errors it raises and an example.
GraineComponents.GraineComponents
Use it to make a components state of your own, for a host that drives its own conversation; the SDK makes one per agent.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
baseUrl | String | required | "https://www.graine.ai" unless your workspace is self-hosted. |
onAnswer | — | optional | Called when the customer answers. |
onAction | — | optional | Called when the customer taps an action. |
onReport | — | optional | Called with a report. |
clock | int Function()? | optional | The clock, in milliseconds since the epoch; the device's when left out. A test passes its own. |
Returns — a new GraineComponents.
Errors — none.
GraineComponents.present
Call it to put a component on screen from a frame you received.
Draws a frame that came from somewhere else, such as a preview or a test, just as it would if the agent had sent it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
frame | Map<String, Object?> | required | The component as Graine sent it. |
Returns — nothing; it returns when done.
Errors — none.
GraineComponents.presentPending
Call it when a component is on its way, so a loader stands where it will appear.
Displays the loader for an incoming component, the same as when the agent announces one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hint | Map<String, Object?> | required | What is known of the coming component — its id and kind. |
Returns — nothing; it returns when done.
Errors — none.
GraineComponents.answer
Call it when the customer chose something in a component you draw yourself.
The customer answered.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
a | WidgetAnswer | required | The answer: its data and its sentence (WidgetContent.pick and friends build one). |
Returns — nothing; it returns when done.
Errors — none.
GraineComponents.dismiss
Call it when the customer closes a component without choosing.
Closes the component with no choice made, or acts as "Clear" for the answered line.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineComponents.reopen
Call it to bring back the component the customer closed.
Restores the most recently closed component in the same state it was in.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineComponents.reset
Call it to clear every component, answer and loader.
Discards everything that has been drawn, as when a call ends or a new call starts.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineWidgetView
Use it to draw the agent's components yourself — where you want them, in the agent's design — instead of on the bar.
class GraineWidgetView extends StatefulWidget
What to expect — Place it where the components should appear; while it is mounted it draws them alone (the bar stops drawing them). It shows a loader while one is on its way and keeps the customer's answer on screen as one line.
| Property | Type | Meaning |
|---|---|---|
final GraineComponents? components | GraineComponents? | The state to draw. |
final GraineInApp? app | GraineInApp? | The agent the components belong to; the view uses its components, session and design. When left out: the agent that components belong to, or failing that the default agent. |
final String? accent | String? | #RRGGBB for buttons and badges. |
final double? radius | double? | Corner rounding. When left out, it falls back to the component's own rounding, then a pinned platform's, then the dashboard's. |
final String? scheme | String? | "light", "dark" or "auto" (the device). |
final GraineWidgetTheme? theme | GraineWidgetTheme? | Single colours of your own over the design's — surface, border, text, muted and the ink on the accent. |
final Map<String, Object?>? appearance | Map<String, Object?>? | The dashboard's Appearance. |
final ResolvedDesign? design | ResolvedDesign? | The design to draw. When left out, the session's design (GraineInApp.design) is used; if there is none either, components keep their pre-design look. |
final double maxHeight | double | The tallest the component can grow; beyond that, its body scrolls within it. |
Its functions: GraineWidgetView — each with its parameters, what it returns, the errors it raises and an example.
GraineWidgetView.GraineWidgetView
Use it to place the component area in your own layout.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
components | GraineComponents? | optional | The state to draw. |
accent | String? | optional | #RRGGBB for buttons and badges. |
radius | double? | optional | Corner rounding. When left out, it falls back to the component's own rounding, then a pinned platform's, then the dashboard's. |
scheme | String? | optional | "light", "dark" or "auto" (the device). |
theme | GraineWidgetTheme? | optional | Single colours of your own over the design's — surface, border, text, muted and the ink on the accent. |
appearance | Map<String, Object?>? | optional | The dashboard's Appearance. |
design | ResolvedDesign? | optional | The design to draw. When left out, the session's design (GraineInApp.design) is used; if there is none either, components keep their pre-design look. |
maxHeight | double | 460 | The tallest the component can grow; beyond that, its body scrolls within it. |
app | GraineInApp? | optional | The agent the components belong to; the view uses its components, session and design. When left out: the agent that components belong to, or failing that the default agent. |
Returns — a new GraineWidgetView.
Errors — none.
GraineWidgetTheme
Use it to give the components single colours of your own over the agent's design.
class GraineWidgetTheme
What to expect — Pass it as GraineWidgetView(theme:). Each colour left null keeps the design's.
| Property | Type | Meaning |
|---|---|---|
final Color? surface | Color? | Behind the component. |
final Color? border | Color? | Hairlines and chip fills. |
final Color? text | Color? | Titles and prices. |
final Color? muted | Color? | Subtitles, facts, secondary labels. |
final Color? onAccent | Color? | Readable ON the accent. |
Its functions: GraineWidgetTheme — each with its parameters, what it returns, the errors it raises and an example.
GraineWidgetTheme.GraineWidgetTheme
Use it to build the colour overrides for GraineWidgetView(theme:).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | Color? | optional | Behind the component. |
border | Color? | optional | Hairlines and chip fills. |
text | Color? | optional | Titles and prices. |
muted | Color? | optional | Subtitles, facts, secondary labels. |
onAccent | Color? | optional | Readable ON the accent. |
Returns — a new GraineWidgetTheme.
Errors — none.
GraineComponent
Read it as one component the agent drew — the same type as GraineWidget, under the name every Graine SDK uses.
typedef GraineComponent = GraineWidget;
What to expect — A component the agent drew — a product list, choices, time slots, an information card — with the data it was drawn from. The SDK's views draw it in your design.
GraineWidget
Read it to draw one component the agent drew: its kind, data, style and what a tap does in your app.
class GraineWidget
What to expect — A component the agent drew — a product list, choices, time slots, an information card — with the data it was drawn from. The SDK's views draw it in your design.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The component's id — every answer and dismissal carries it back. |
final String kind | String | Names the component's kind, such as "product_list", "plan_comparison" or "choices", or any other kind the agent declares. |
final Map<String, Object?> data | Map<String, Object?> | Its data, with root-relative picture paths already resolved against the agent's origin. |
final String fallbackText | String | What the agent would have said instead. |
final WidgetStyle style | WidgetStyle | How the dashboard asked for it to look. |
final WidgetSelectAction onSelect | WidgetSelectAction | The action the app takes when an item is tapped, in addition to informing the agent. |
Its functions: GraineWidget, adopt — each with its parameters, what it returns, the errors it raises and an example.
GraineWidget.GraineWidget
Use it to build a component by hand for a preview or a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The component's id — every answer and dismissal carries it back. |
kind | String | required | Names the component's kind, such as "product_list", "plan_comparison" or "choices", or any other kind the agent declares. |
data | Map<String, Object?> | required | Its data, with root-relative picture paths already resolved against the agent's origin. |
fallbackText | String | required | What the agent would have said instead. |
style | WidgetStyle | required | How the dashboard asked for it to look. |
onSelect | WidgetSelectAction | required | The action the app takes when an item is tapped, in addition to informing the agent. |
Returns — a new GraineWidget.
Errors — none.
GraineWidget.adopt
Use it to read a component from the frame Graine sends.
Turns the page's widget object into a component. Returns null when the object has no widget_id, because a frame the SDK cannot answer should not be drawn.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Map<String, Object?>? | required | The component as Graine sent it; null, or one with no id, gives null. |
baseUrl | String | required | "https://www.graine.ai" unless your workspace is self-hosted. |
Returns — GraineWidget?. Example value: null.
Errors — none.
WidgetContent
Use it to draw a component of your own: its rows, chips or days, and the answer each tap sends.
class WidgetContent
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final GraineWidget widget | GraineWidget | The component it was read from. |
late final bool isQuickActions | bool | A quick-actions component: draw chips. |
late final String selectLabel | String | The text on the button, which is also the verb used for "choose several". |
late final List<WidgetRow> rows | List<WidgetRow> | The rows to draw, up to eight. |
late final bool isProducts | bool | Draw rows — a product list, plans or a card. |
late final bool isChips | bool | Draw chips — choices or quick actions. |
late final bool isCalendar | bool | Draw days — time slots. |
late final bool drawable | bool | Something this build can draw. |
late final List<WidgetChip> chips | List<WidgetChip> | The chips to draw. |
late final List<WidgetDay> days | List<WidgetDay> | The days and their times, up to four days. |
late final String title | String | The component's title; empty for none. |
late final String prompt | String | The question it asks; empty for none. |
late final String note | String | A line under it; empty for none. |
Its functions: WidgetContent, surface, many, pick, pickMany, pickChip, pickSlot, toggle, manyButtonLabel, screenFooter, closeLabel, answeredLine — each with its parameters, what it returns, the errors it raises and an example.
WidgetContent.WidgetContent
Use it to read a component into what you draw.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widget | GraineWidget | required | The component it was read from. |
Returns — a new WidgetContent.
Errors — none.
WidgetContent.surface
Use it to know where the component is drawn: a full screen, a sheet or a card.
Which surface is really used: a kind that cannot be drawn never claims the screen or a sheet, and is given 'card'.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
look | WidgetLook | required | How it is drawn. |
Returns — String. Example value: 'sheet'.
Errors — none.
WidgetContent.many
Use it to know whether the customer may choose several.
Multiple selection is used only when there are items that can be ticked.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
look | WidgetLook | required | How it is drawn. |
Returns — bool. Example value: true.
Errors — none.
WidgetContent.pick
Use it to build the answer when the customer taps one row.
One row tapped.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
index | int | required | The position. |
Returns — WidgetAnswer — its fields: WidgetAnswer.
Errors — none.
WidgetContent.pickMany
Use it to build one answer for several rows the customer ticked.
Turns several picks into a single answer: all the items, their ids and titles flattened the way an in-app action's arguments usually expect, and one sentence naming them as a person would.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
ids | List<String> | required | The ids of the rows the customer ticked, in order. |
Returns — WidgetAnswer — its fields: WidgetAnswer.
Errors — none.
WidgetContent.pickChip
Use it to build the answer when the customer taps a chip.
A chip tapped.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
chip | WidgetChip | required | The chip tapped. |
Returns — WidgetAnswer — its fields: WidgetAnswer.
Errors — none.
WidgetContent.pickSlot
Use it to build the answer when the customer taps a time.
Handles a tap on a time, giving the day and the slot — the shape resultToText("calendar_slots") reads.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
day | WidgetDay | required | The day the time belongs to. |
slot | String | required | The time tapped, as shown. |
Returns — WidgetAnswer — its fields: WidgetAnswer.
Errors — none.
WidgetContent.toggle
Use it to tick or untick a row while the customer chooses several.
Ticks or unticks one row in a multiple selection; ticking at the cap drops the earliest tick to make room.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
ticked | List<String> | required | The ids ticked so far. |
id | String | required | The row tapped. |
maxSelect | int | required | The most rows that may be ticked (WidgetLook.maxSelect). |
Returns — List<String>. Example value: ['b', 'c', 'd'].
Errors — none.
WidgetContent.manyButtonLabel
Use it to get the words on the button under a multi-select list.
The one button under a multi-select list.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
chosen | int | required | How many rows are ticked. |
Returns — String. Example value: 'Pick 1 more'.
Errors — none.
WidgetContent.screenFooter
Use it to get a full-screen component's footer, when it has one.
A full-screen component's footer: on a call, the label STILL LISTENING and how to answer — the agent is still there, listening. A component that came through the chat belongs to no call, so it gets no footer.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
prompt | String | required | The component's question (WidgetContent.prompt); empty for the default line. |
typed | bool | required | The component arrived in the chat (no call is listening). |
Returns — ({String label, String line})? — the footer's label and line, or null with typed. Example value: (label: 'STILL LISTENING', line: 'Tap one, or just say it.').
Errors — none.
WidgetContent.closeLabel
Use it to get what a screen reader says for the component's close control.
What a screen reader announces for the component's close control; in the chat it leaves out talking, since there is none to carry on with.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
typed | bool | required | The component arrived in the chat (no call to keep talking on). |
Returns — String. Example value: 'Close and keep talking'.
Errors — none.
WidgetContent.answeredLine
Use it to get the line that stays on screen after the customer answered.
The line that stays on screen after an answer, read from the answer's data: a title (its name, title, label or slot) and a detail (its price and day, joined with " · "). Both empty means there is no line to draw.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | Map<String, Object?> | required | The answer's data. |
Returns — ({String title, String detail}). Example value: (title: 'Blue Mug', detail: '$12').
Errors — none.
WidgetAnswer
Read it as what a tap sends the agent: the data, and the sentence that is the customer's turn.
class WidgetAnswer
What to expect — What a tap on a component sends the agent: a sentence for the agent, and structured data for your webhooks.
| Property | Type | Meaning |
|---|---|---|
final Map<String, Object?> data | Map<String, Object?> | The structured answer the agent reads (the chosen item's id, title and price; a day and a slot). |
final String summary | String | The sentence that is the customer's turn ("I'll take a look at Blue Mug at $12."). Without it the conversation does not move. |
Its functions: WidgetAnswer — each with its parameters, what it returns, the errors it raises and an example.
WidgetAnswer.WidgetAnswer
Use it to build an answer for GraineComponents.answer.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | Map<String, Object?> | required | The structured answer the agent reads (the chosen item's id, title and price; a day and a slot). |
summary | String | required | The sentence that is the customer's turn ("I'll take a look at Blue Mug at $12."). Without it the conversation does not move. |
Returns — a new WidgetAnswer.
Errors — none.
WidgetRow
Read it to draw one row of a component: a product, a plan or a card.
class WidgetRow
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The item's id (its title when it has none). |
final String title | String | The item's name. |
final String subtitle | String | A line under the name; empty for none. |
final String price | String | The price as shown, with its suffix ("$12/mo"); empty for none. |
final List<String> facts | List<String> | Up to three short facts. |
final String image | String | The picture's address; empty for none. |
final bool unavailable | bool | Draw it greyed out and not choosable. |
final String selectLabel | String | The row's button words ("Choose", "Select"). |
Its functions: WidgetRow — each with its parameters, what it returns, the errors it raises and an example.
WidgetRow.WidgetRow
Use it to build a row by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The item's id (its title when it has none). |
title | String | required | The item's name. |
subtitle | String | required | A line under the name; empty for none. |
price | String | required | The price as shown, with its suffix ("$12/mo"); empty for none. |
facts | List<String> | required | Up to three short facts. |
image | String | required | The picture's address; empty for none. |
unavailable | bool | required | Draw it greyed out and not choosable. |
selectLabel | String | required | The row's button words ("Choose", "Select"). |
Returns — a new WidgetRow.
Errors — none.
WidgetChip
Read it to draw one chip: a choice or a quick action.
class WidgetChip
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The choice's id (its label when it has none). |
final String label | String | The chip's words. |
Its functions: WidgetChip — each with its parameters, what it returns, the errors it raises and an example.
WidgetChip.WidgetChip
Use it to build a chip by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The choice's id (its label when it has none). |
label | String | required | The chip's words. |
Returns — a new WidgetChip.
Errors — none.
WidgetDay
Read it to draw one day of a time-slot component.
class WidgetDay
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String label | String | The day as shown ("Tomorrow", "Thu 16 Oct"). |
final List<String> slots | List<String> | Its times as shown, up to eight. |
Its functions: WidgetDay — each with its parameters, what it returns, the errors it raises and an example.
WidgetDay.WidgetDay
Use it to build a day by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
label | String | required | The day as shown ("Tomorrow", "Thu 16 Oct"). |
slots | List<String> | required | Its times as shown, up to eight. |
Returns — a new WidgetDay.
Errors — none.
WidgetPending
Read it to draw the loader that stands where a component is about to appear.
class WidgetPending
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The coming component's id, when known. |
final String kind | String | Its kind, when known — to draw a fitting placeholder. |
Its functions: WidgetPending — each with its parameters, what it returns, the errors it raises and an example.
WidgetPending.WidgetPending
Use it to build a loading component by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The coming component's id, when known. |
kind | String | required | Its kind, when known — to draw a fitting placeholder. |
Returns — a new WidgetPending.
Errors — none.
WidgetAnswered
Read it to draw the line the customer's answer leaves on screen.
class WidgetAnswered
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final GraineWidget widget | GraineWidget | The component that was answered. |
final Map<String, Object?> data | Map<String, Object?> | The answer's data. |
final String summary | String | The answer's sentence. |
Its functions: WidgetAnswered — each with its parameters, what it returns, the errors it raises and an example.
WidgetAnswered.WidgetAnswered
Use it to build an answered line by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widget | GraineWidget | required | The component that was answered. |
data | Map<String, Object?> | required | The answer's data. |
summary | String | required | The answer's sentence. |
Returns — a new WidgetAnswered.
Errors — none.
WidgetSubmission
Read it as what to send for an answer, and the action of yours to run first.
class WidgetSubmission
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String widgetId | String | The component answered. |
final Map<String, Object?> data | Map<String, Object?> | The answer's data. |
final String summary | String | The answer's sentence. |
final SelectCall? action | SelectCall? | An action of yours to run first; null for none. |
Its functions: WidgetSubmission — each with its parameters, what it returns, the errors it raises and an example.
WidgetSubmission.WidgetSubmission
Use it to build a submission by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widgetId | String | required | The component answered. |
data | Map<String, Object?> | required | The answer's data. |
summary | String | required | The answer's sentence. |
action | SelectCall? | required | An action of yours to run first; null for none. |
Returns — a new WidgetSubmission.
Errors — none.
WidgetDismissal
Read it as what the agent is quietly told when the customer closes a component without choosing.
class WidgetDismissal
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String toolName | String | The component's id. |
final String kind | String | Its kind. |
final String title | String | Its title. |
Its functions: WidgetDismissal, eventData — each with its parameters, what it returns, the errors it raises and an example.
WidgetDismissal.WidgetDismissal
Use it to build a dismissal by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
toolName | String | required | The component's id. |
kind | String | required | Its kind. |
title | String | required | Its title. |
Returns — a new WidgetDismissal.
Errors — none.
WidgetDismissal.eventData
Use it to get the event's data as it is sent.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
WidgetFlow
Use it to run a component's lifecycle yourself — loading, shown, answered, closed — with time passed in.
class WidgetFlow
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String baseUrl | String | The agent's address, for pictures given as paths. |
GraineWidget? get widget | GraineWidget? | The component on screen, or null. |
WidgetAnswered? get answered | WidgetAnswered? | The last answer, kept on screen as one line; or null. |
WidgetPending? get loading | WidgetPending? | A component on its way, or null. |
bool get awaitingReply | bool | True after the customer answers and before the agent begins its reply. |
GraineWidget? get closed | GraineWidget? | The most recent component that was closed unanswered, so it can be offered with a "show it again". |
Its functions: WidgetFlow, seed, onPending, onWidget, onAgentStarted, submit, dismiss, reopen, reset, tick, nextDeadline — each with its parameters, what it returns, the errors it raises and an example.
WidgetFlow.WidgetFlow
Use it to make a lifecycle for components from one agent.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
baseUrl | String | required | The agent's address, for pictures given as paths. |
Returns — a new WidgetFlow.
Errors — none.
WidgetFlow.seed
Call it on mount with a component drawn while nothing was listening.
Picks up, when mounted, a component that was drawn while nothing was listening.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Map<String, Object?>? | required | The component waiting to be drawn (GraineInApp.pendingWidget). |
Returns — nothing; it returns when done.
Errors — none.
WidgetFlow.onPending
Call it when a component is on its way.
A component is on its way.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hint | Map<String, Object?>? | required | What is known of the coming component. |
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
WidgetFlow.onWidget
Call it when the agent drew a component.
The agent drew one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Map<String, Object?>? | required | The component as Graine sent it. |
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — bool. Example value: true.
Errors — none.
WidgetFlow.onAgentStarted
Call it when the agent starts answering.
Marks that the agent has started to speak — a caption or a component arrived — so the view no longer says it is waiting.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
WidgetFlow.submit
Call it when the customer answered.
The customer answered.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | Map<String, Object?> | required | The answer's data. |
summary | String | required | A short summary. |
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — WidgetSubmission? — its fields: WidgetSubmission. Example value: null.
Errors — none.
WidgetFlow.dismiss
Call it when the customer closed the component.
The component was closed with no choice made, or "Clear" was pressed on the answered line.
Parameters — none.
Returns — WidgetDismissal? — its fields: WidgetDismissal. Example value: null.
Errors — none.
WidgetFlow.reopen
Call it to bring back the component the customer closed.
Restores the most recently closed component in the same state it was in.
Parameters — none.
Returns — bool. Example value: true.
Errors — none.
WidgetFlow.reset
Call it to forget everything.
Use it when a call ends or another begins; nothing from the previous call should stay on screen.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
WidgetFlow.tick
Call it at nextDeadline to move the lifecycle on.
Apply every deadline that has passed.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — bool. Example value: true.
Errors — none.
WidgetFlow.nextDeadline
Use it to know when to call tick next.
When tick next has something to do, or null.
Parameters — none.
Returns — int?. Example value: 3.
Errors — none.
WidgetStyle
Read it as how the dashboard asked a component to look.
class WidgetStyle
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String? preset | String? | gallery, cards, list, spotlight or compact. |
final String? imageSize | String? | small, medium or large. |
final String? density | String? | comfortable or compact. |
final String? button | String? | filled, outline or row. |
final bool? facts | bool? | Show the facts under each item. |
final int? columns | int? | 1 or 2 (gallery and cards). |
final String? surface | String? | auto, screen, sheet or card. |
final int? radius | int? | Corner radius, 0–24. |
final String? accent | String? | #RRGGBB over the design's accent. |
final String? platform | String? | auto, ios, material or oneui. |
final String? select | String? | one or many. |
final int? maxSelect | int? | The most items when choosing several, 2–8. |
Its functions: WidgetStyle, toMap — each with its parameters, what it returns, the errors it raises and an example.
WidgetStyle.WidgetStyle
Use it to build a component's style by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
preset | String? | optional | gallery, cards, list, spotlight or compact. |
imageSize | String? | optional | small, medium or large. |
density | String? | optional | comfortable or compact. |
button | String? | optional | filled, outline or row. |
facts | bool? | optional | Show the facts under each item. |
columns | int? | optional | 1 or 2 (gallery and cards). |
surface | String? | optional | auto, screen, sheet or card. |
radius | int? | optional | Corner radius, 0–24. |
accent | String? | optional | #RRGGBB over the design's accent. |
platform | String? | optional | auto, ios, material or oneui. |
select | String? | optional | one or many. |
maxSelect | int? | optional | The most items when choosing several, 2–8. |
Returns — a new WidgetStyle.
Errors — none.
WidgetStyle.toMap
Use it to turn a style back into its JSON.
The keys that are set, as JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
WidgetLook
Read it to draw a component: its look with every default filled in.
class WidgetLook
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String preset | String | The preset drawn. |
final String imageSize | String | The picture size drawn. |
final String density | String | The density drawn. |
final String button | String | The button style drawn. |
final bool facts | bool | Whether facts are drawn. |
final int columns | int | 1 or 2 — two only for the gallery and cards presets. |
final String surface | String | The surface to use, with "auto" already turned into the right surface for the kind. |
final int? radius | int? | The corner radius; null: the design's. |
final String? accent | String? | #RRGGBB; null: the design's accent. |
final String platform | String | The platform as picked; the renderer resolves "auto", because it knows which phone it is on. |
final String select | String | one or many. |
final int maxSelect | int | The most items when choosing several. |
Its functions: WidgetLook, toMap — each with its parameters, what it returns, the errors it raises and an example.
WidgetLook.WidgetLook
Use it to build a look by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
preset | String | required | The preset drawn. |
imageSize | String | required | The picture size drawn. |
density | String | required | The density drawn. |
button | String | required | The button style drawn. |
facts | bool | required | Whether facts are drawn. |
columns | int | required | 1 or 2 — two only for the gallery and cards presets. |
surface | String | required | The surface to use, with "auto" already turned into the right surface for the kind. |
radius | int? | optional | The corner radius; null: the design's. |
accent | String? | optional | #RRGGBB; null: the design's accent. |
platform | String | required | The platform as picked; the renderer resolves "auto", because it knows which phone it is on. |
select | String | required | one or many. |
maxSelect | int | required | The most items when choosing several. |
Returns — a new WidgetLook.
Errors — none.
WidgetLook.toMap
Use it to turn a look into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
PlatformGrammar
Read it to draw a component in the shapes people on that phone already know.
class PlatformGrammar
What to expect — Fixed per platform (Widgets.grammar): the shapes change, the colours stay the brand's.
| Property | Type | Meaning |
|---|---|---|
final int radius | int | The card's corner radius, used only for an explicit platform. |
final int chipRadius | int | A chip's corner radius. |
final int buttonRadius | int | A button's corner radius. |
final bool pillButtons | bool | Draw buttons as pills. |
final int separatorInset | int | How far row separators are inset. |
final int grabberWidth | int | A sheet's handle width. |
final int grabberHeight | int | A sheet's handle height. |
final int titleWeight | int | CSS weight: 500, 600 or 700. |
final int padBoost | int | Extra padding inside cards. |
final bool chipOutlined | bool | Draw chips outlined rather than filled. |
Its functions: PlatformGrammar — each with its parameters, what it returns, the errors it raises and an example.
PlatformGrammar.PlatformGrammar
Use it to build a platform's shapes by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
radius | int | required | The card's corner radius, used only for an explicit platform. |
chipRadius | int | required | A chip's corner radius. |
buttonRadius | int | required | A button's corner radius. |
pillButtons | bool | required | Draw buttons as pills. |
separatorInset | int | required | How far row separators are inset. |
grabberWidth | int | required | A sheet's handle width. |
grabberHeight | int | required | A sheet's handle height. |
titleWeight | int | required | CSS weight: 500, 600 or 700. |
padBoost | int | required | Extra padding inside cards. |
chipOutlined | bool | required | Draw chips outlined rather than filled. |
Returns — a new PlatformGrammar.
Errors — none.
WidgetSelectAction
Read it as what your app should do when the customer taps a component's item, beyond telling the agent.
class WidgetSelectAction
What to expect — A component the agent drew — a product list, choices, time slots, an information card — with the data it was drawn from. The SDK's views draw it in your design.
| Property | Type | Meaning |
|---|---|---|
final String? path | String? | A screen of your app to open (for the open_screen action), with placeholders such as {id} filled from the tapped item. |
final String? action | String? | The action of yours to run, by its registered name. |
final Map<String, String>? args | Map<String, String>? | Its arguments, each a template filled from the tapped item. |
final String? say | String? | What to tell the agent instead of the default sentence. |
bool get isEmpty | bool | True when the component names no action and no path: a tap only answers the agent. |
Its functions: WidgetSelectAction, toMap — each with its parameters, what it returns, the errors it raises and an example.
WidgetSelectAction.WidgetSelectAction
Use it to build a tap action by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
path | String? | optional | A screen of your app to open (for the open_screen action), with placeholders such as {id} filled from the tapped item. |
action | String? | optional | The action of yours to run, by its registered name. |
args | Map<String, String>? | optional | Its arguments, each a template filled from the tapped item. |
say | String? | optional | What to tell the agent instead of the default sentence. |
Returns — a new WidgetSelectAction.
Errors — none.
WidgetSelectAction.toMap
Use it to turn a tap action into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
SelectCall
Read it as the action of yours to run for one tap, and its arguments.
class SelectCall
What to expect — A component the agent drew — a product list, choices, time slots, an information card — with the data it was drawn from. The SDK's views draw it in your design.
| Property | Type | Meaning |
|---|---|---|
final String name | String | The action to run. |
final Map<String, String> args | Map<String, String> | Its arguments, filled in. |
Its functions: SelectCall — each with its parameters, what it returns, the errors it raises and an example.
SelectCall.SelectCall
Use it to build a tap's action by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action to run. |
args | Map<String, String> | required | Its arguments, filled in. |
Returns — a new SelectCall.
Errors — none.
Widgets
Use it to apply the component rules every Graine SDK shares.
abstract final class Widgets
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
static const List<String> presets | List<String> | gallery, cards, list, spotlight, compact. |
static const List<String> imageSizes | List<String> | small, medium, large. |
static const List<String> densities | List<String> | comfortable, compact. |
static const List<String> buttons | List<String> | filled, outline, row. |
static const List<String> surfaceChoices | List<String> | auto, screen, sheet, card. |
static const List<String> platforms | List<String> | auto, ios, material, oneui. |
static const List<String> selects | List<String> | one, many. |
static const int maxSelectDefault | int | The most items when choosing several, unless the component says: 3. |
static const String defaultPreset | String | The preset when none is set: 'cards'. |
static const String navigateAction | String | The single handler an app registers to let the dashboard open any of its screens. |
static const int selectArgMax | int | The most arguments a tap action keeps: 10. |
static const int selectValueMax | int | The most characters a tap action's path, argument or sentence keeps: 200. |
static const int minLoaderMs | int | The minimum time a shown loader stays up, so that it looks like loading and not a glitch. |
static const int pendingWidgetMs | int | The longest a "component coming" loader may stay up while nothing arrives. |
static const int awaitingReplyMs | int | The longest the answered line keeps saying "thinking" while the agent has yet to start. |
static const Map<String, PlatformGrammar> grammar | Map<String, PlatformGrammar> | The shapes for ios, material and oneui. |
Its functions: surface, normaliseStyle, resolveLook, resolvePlatform, manySummary, normaliseSelectAction, fillSelectTemplate, fillSelectArgs, selectCall, resolveImages — each with its parameters, what it returns, the errors it raises and an example.
Widgets.surface
Use it to know where a kind of component is drawn by default.
Picks the surface for a component — one of "screen", "sheet" or "card".
| Parameter | Type | Default | Meaning |
|---|---|---|---|
kind | String? | required | The component's kind (product_list, choices, …). |
Returns — String. Example value: 'screen'.
Errors — none.
Widgets.normaliseStyle
Use it to read a component's style, keeping only the values the SDK knows.
Only the keys and values the renderers read.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The component's style as sent; anything unknown is dropped. |
Returns — WidgetStyle — its fields: WidgetStyle.
Errors — none.
Widgets.resolveLook
Use it to get a component's look with every default filled in.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
style | WidgetStyle? | required | The component's style; null for none. |
kind | String? | required | The component's kind, which decides where it is drawn by default. |
Returns — WidgetLook — its fields: WidgetLook.
Errors — none.
Widgets.resolvePlatform
Use it to know which phone's shapes to draw a component in.
Resolves "auto" to the phone's native design language: Material on Android, One UI on a Samsung, and Apple's on iOS as well as on anything it does not recognise.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
platform | String? | required | The style's platform: auto, ios, material or oneui. |
os | String? | required | The phone's system: android or ios. |
manufacturer | String? | optional | The phone's maker, on Android; a Samsung phone gets One UI's shapes. |
Returns — String. Example value: 'oneui'.
Errors — none.
Widgets.manySummary
Use it to write the sentence for several choices.
Builds the sentence the agent hears after a multiple choice, which is also the user's bubble in a text chat: the button's label exactly as written, followed by the names ("Taken: Morning and Evening").
| Parameter | Type | Default | Meaning |
|---|---|---|---|
titles | List<String> | required | The names of the chosen items, in order. |
label | String | 'Compare' | The button's words, as written ("Compare"); empty for the names alone. |
Returns — String. Example value: 'Taken: Morning and Evening'.
Errors — none.
Widgets.normaliseSelectAction
Use it to read a component's tap action, keeping only what is valid.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The component's tap action as sent. |
Returns — WidgetSelectAction — its fields: WidgetSelectAction.
Errors — none.
Widgets.fillSelectTemplate
Use it to fill a tap action's placeholders from the tapped item.
Fills {id}, {title}… from the tapped item. A placeholder it does not know is replaced with nothing rather than left as written.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
template | String | required | A path or argument with {id}, {title}… placeholders. |
item | Map<String, Object?> | required | The tapped item's data. |
Returns — String. Example value: '/products/mug-blue'.
Errors — none.
Widgets.fillSelectArgs
Use it to fill every argument of a tap action from the tapped item.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
args | Map<String, String>? | required | The tap action's arguments; null for none. |
item | Map<String, Object?> | required | The tapped item's data. |
Returns — Map<String, String>. Example value: {'sku': 'mug-blue'}.
Errors — none.
Widgets.selectCall
Use it to get the action of yours to run for a tap.
Works out which action one tap runs: an explicit action takes priority, otherwise a path is sent to navigateAction; in both cases the path is passed along as an argument.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
onSelect | WidgetSelectAction? | required | The component's tap action; null for none. |
item | Map<String, Object?> | required | The tapped item's data. |
Returns — SelectCall? — its fields: SelectCall. Example value: null.
Errors — none.
Widgets.resolveImages
Use it to turn a component's pictures that start with / into full addresses on the agent's site.
A root-relative picture (/samples/item.png) is resolved against the agent's origin — the one place it could have come from.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | Map<String, Object?> | required | The component's data. |
baseUrl | String | required | The agent's address (GraineConfig.baseUrl); empty leaves the data as it is. |
Returns — Map<String, Object?>. Example value: {'imageUrl': 'https://www.graine.ai/samples/item.png'}.
Errors — none.
Calls the user places
WhatsApp-style calls with the agent, on the native call engine the package carries: CallKit on iOS, a call notification and call screen on Android, the call going on with the screen off and the platform's echo canceller on the audio. Configure GraineCalls.instance once at launch, attach your agent so the call knows the customer, the screen and your actions, and place a call from a button. The in-app call the voice bar places is GraineCallState, at the end of this section.
A native call carries its audio over the WebSocket — or over WebRTC, in a build that has it (WebRTC calls). GraineCallsOptions.callTransport chooses, for calls in both directions (the ones the customer places and the ones Graine rings), and each call's snapshot says which one carried it: transport, and transportFallbackReason for a call that wanted WebRTC and runs on the WebSocket.
What 0.8.0's native engine does for every call:
- It starts at once on the agent's configuration the device already keeps (this launch's, or the last one), and refreshes that configuration behind the call instead of waiting for the network first.
- iOS: one deadline before the conversation opens. Fetching the configuration, the ticket and the connection share one 20-second deadline; past it the call fails with "The call could not connect within 20 seconds." (Before, each step's own timeout could add up to most of a minute on "Connecting".) The connection itself must still open within 15 seconds of the ticket, which can come first: "The conversation did not open within 15 seconds."
- iOS: a call is connected only once it can be heard. If CallKit has not started the call's audio 3 seconds after the conversation opens, the SDK starts it itself, once; still nothing 3 seconds later, the call fails with "The call's audio could not start." instead of staying open and silent.
- Android: a dead connection ends the call. A live connection answers every keep-alive; when nothing at all arrives for 50 seconds the call ends — the Android SDK words it "Nothing arrived for 50 seconds: the connection was lost." Before the conversation opens, Android's limit stays 15 seconds ("The call could not connect within 15 seconds.").
- Android: a slow network no longer freezes a call. Sending never waits for the network: at most 300 ms of the customer's audio is kept while the line falls behind (the oldest goes first), and hanging up lets go of the microphone at once.
Where your app sees these: a call that never connected reaches outcomes as GraineCallOutcomeKind.failed with the sentence in reason, and GraineCalls.instance.value.error keeps it until the next call starts; a call that was connected and then lost reaches outcomes as ended with reason 'failed'.
GraineCalls
Use it to place native calls with the agent and to draw them: configure it at launch, attach your agent, call startCall from a button, and listen to what became of each call.
class GraineCalls extends ChangeNotifier implements ValueListenable<GraineCallSnapshot>
What to expect — The native call engine. Configure it once at launch, before a push can arrive; hand it the push tokens and the pushes; place calls with startCall and listen for outcomes. One call at a time on the device.
| Property | Type | Meaning |
|---|---|---|
static final GraineCalls instance | GraineCalls | The one instance. |
bool get isSupported | bool | Native calls run on Android and iOS. |
Stream<GraineCallOutcome> get outcomes | Stream<GraineCallOutcome> | The result of each call, for you to pass on to your server. Outcomes from before anyone listened (a call that rang and ended while the app was not running) reach the first listener, oldest first — the last 20. |
Stream<GraineIncomingCall> get incomingCalls | Stream<GraineIncomingCall> | Fires when a call from an agent begins ringing, for your own ringing UI or for analytics. |
Its functions: configure, attach, startCall, end, setMuted, setSpeaker, resetForTesting, registerPushToken, enableVoIPPushes, handlePush, answer, decline, callPermissions, requestCallPermissions, openCallSettings, callSetupProblems — each with its parameters, what it returns, the errors it raises and an example.
GraineCalls.configure
Call it once at launch, before a push can arrive, to set how calls ring and what they show.
Hands the options to the native call engine, which keeps them — so a push that wakes a closed app rings before any Dart has run. Every agent the app configured under a name goes with them (each with its own key), so startCall(agent:) can call it and Graine's rings for it ring as it; an agent configured later reaches the engine then. Who is signed in reaches the engine too. Call it once at launch, after GraineInApp.init. On a platform other than Android and iOS it does nothing.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
options | GraineCallsOptions | required | How calls ring and what they show — see GraineCallsOptions. |
Returns — Future<void>, which completes once the engine has the options and the current call's state.
Errors — ArgumentError for an empty publishableKey or displayName; a PlatformException with the code invalid_options, naming the option, for anything else the engine refuses.
GraineCallsOptions
Use it to say how native calls ring and what they show: the agent's key, the name on calls, the ring and who draws the call screen.
class GraineCallsOptions
What to expect — Made once, at launch, before anything else. Optional fields have the defaults shown; nothing in it is sent to Graine except what the descriptions say.
| Property | Type | Meaning |
|---|---|---|
final String publishableKey | String | The default agent's publishable key, pk_live_… (Agent → Embed & Widgets → Install) — public by design. Agents the app configured under a name go with it, each with its own key. |
final String displayName | String | The name on calls the customer places, and on a ring whose push names nobody. A push's caller_name wins for its own call — so a call Graine rings shows the agent's call name from Calls & scheduling. |
final String baseUrl | String | Where Graine is: 'https://www.graine.ai' unless your workspace is self-hosted. Use the same value as GraineConfig.baseUrl. |
final String? ringtoneSound | String? | The ring: on iOS a sound file of 30 seconds or less in the app bundle, on Android a res/raw resource name. Null (the default): the ring the brand chose in the call screen design — the phone's own unless it chose one. Set, it replaces the brand's ring. |
final Duration ringTimeout | Duration | How long a ring from your own server lasts before it is missed (default 30 seconds). A ring Graine sends lasts the agent's ring time instead (CallsSetting.ringTimeoutSeconds, 45 seconds by default). |
final String? appVersion | String? | The app build that placed the call, recorded on the call record. |
final GraineCallScreen callScreen | GraineCallScreen | Who draws the call while the app is open: GraineCallScreen.sdk (the default) — the SDK's call screen in the brand's call screen design, a full-screen call activity on Android and a full-screen view over your app on iOS — or GraineCallScreen.app, your own screen drawn from GraineCalls.instance in the design's call colours (GraineInApp.instance.tokens?.call; with several agents, those of the agent the call is with). The system's call screen always appears on a locked iPhone. |
final GraineCallTransport callTransport | GraineCallTransport | How calls carry their audio, in both directions — the calls the customer places and the ones Graine rings: GraineCallTransport.auto (the default) takes WebRTC in a build that has it (WebRTC calls), else the WebSocket; websocket always the WebSocket; webrtc WebRTC wherever it can carry the call. A call WebRTC cannot set up continues on the WebSocket inside the same call, and the agent's In-app call audio setting can move every install to the WebSocket without a release. New in 0.9.0. |
final bool debug | bool | Turns on the native SDK's debug log in Xcode's console or logcat, showing how each call connected and what its audio did, so you can work out why a call did not connect. Off by default; turn it on in debug builds. Read once at launch: a change takes effect at the next launch. |
final String? androidSmallIcon | String? | Android only: the name of a monochrome drawable used in the call notifications. |
final String? iosIconTemplate | String? | iOS only: the name of a template image in the app bundle, shown on the system call screen. |
final bool iosIncludesCallsInRecents | bool | iOS only: show these calls in the Recents list of the Phone app. |
Its functions: GraineCallsOptions, toMap — each with its parameters, what it returns, the errors it raises and an example.
GraineCallsOptions.GraineCallsOptions
Use it to build the options you pass to GraineCalls.instance.configure.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
publishableKey | String | required | The default agent's publishable key, pk_live_… (Agent → Embed & Widgets → Install) — public by design. Agents the app configured under a name go with it, each with its own key. |
displayName | String | required | The name on calls the customer places, and on a ring whose push names nobody. A push's caller_name wins for its own call — so a call Graine rings shows the agent's call name from Calls & scheduling. |
baseUrl | String | 'https://www.graine.ai' | Where Graine is: 'https://www.graine.ai' unless your workspace is self-hosted. Use the same value as GraineConfig.baseUrl. |
ringtoneSound | String? | optional | The ring: on iOS a sound file of 30 seconds or less in the app bundle, on Android a res/raw resource name. Null (the default): the ring the brand chose in the call screen design — the phone's own unless it chose one. Set, it replaces the brand's ring. |
ringTimeout | Duration | const Duration(seconds: 30) | How long a ring from your own server lasts before it is missed (default 30 seconds). A ring Graine sends lasts the agent's ring time instead (CallsSetting.ringTimeoutSeconds, 45 seconds by default). |
appVersion | String? | optional | The app build that placed the call, recorded on the call record. |
callScreen | GraineCallScreen | GraineCallScreen.sdk | Who draws the call while the app is open: GraineCallScreen.sdk (the default) — the SDK's call screen in the brand's call screen design, a full-screen call activity on Android and a full-screen view over your app on iOS — or GraineCallScreen.app, your own screen drawn from GraineCalls.instance in the design's call colours (GraineInApp.instance.tokens?.call; with several agents, those of the agent the call is with). The system's call screen always appears on a locked iPhone. |
callTransport | GraineCallTransport | GraineCallTransport.auto | How calls carry their audio, in both directions: auto takes WebRTC in a build that has it (WebRTC calls), else the WebSocket; websocket always the WebSocket; webrtc WebRTC wherever it can carry the call. A call WebRTC cannot set up continues on the WebSocket inside the same call. |
debug | bool | false | Turns on the native SDK's debug log in Xcode's console or logcat, showing how each call connected and what its audio did, so you can work out why a call did not connect. Off by default; turn it on in debug builds. Read once at launch: a change takes effect at the next launch. |
androidSmallIcon | String? | optional | Android only: the name of a monochrome drawable used in the call notifications. |
iosIconTemplate | String? | optional | iOS only: the name of a template image in the app bundle, shown on the system call screen. |
iosIncludesCallsInRecents | bool | false | iOS only: show these calls in the Recents list of the Phone app. |
Returns — a new GraineCallsOptions.
Errors — none.
GraineCallsOptions.toMap
Use it to see the options exactly as the native engine receives them — for a log or a test.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
GraineCallScreen
Use it to choose who draws the call while your app is open: the SDK's call screen, or your own.
enum GraineCallScreen { sdk, app }
What to expect — Read once, from GraineCallsOptions.callScreen. A locked iPhone always shows the system's call screen, whichever you choose.
| Case | Meaning |
|---|---|
sdk | The SDK's call screen, drawn from the brand's call screen design — a full-screen call activity on Android, a full-screen view over your app on iOS. The default. |
app | Your own screen, drawn from GraineCalls.instance in the design's call colours (GraineInApp.instance.tokens?.call). |
GraineCallTransport
Use it to choose how native calls carry their audio — WebRTC in a build that has it, or always the WebSocket — and to read which one carried a call.
enum GraineCallTransport
What to expect — Chosen once, in GraineCallsOptions.callTransport, for calls in both directions: the ones the customer places and the ones Graine rings. Whatever is chosen, a call WebRTC cannot set up continues on the WebSocket inside the same call, and the agent's In-app call audio setting set to Standard moves every install's calls to the WebSocket without an app release (WebRTC calls). Each call then reports what carried it in GraineCallSnapshot.transport — webrtc or websocket, never auto. Native calls only: the voice bar's in-app call is Transport. New in 0.9.0.
| Case | Meaning |
|---|---|
auto('auto') | WebRTC when the app was built with it and the agent's In-app call audio allows it, else the WebSocket. The default. |
websocket('websocket') | Always the WebSocket. |
webrtc('webrtc') | WebRTC wherever it can carry the call; the WebSocket only when the build has no WebRTC, the agent's In-app call audio is Standard, or WebRTC cannot set up this call. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The value as the native engine reads and reports it — the same word as the value's name. |
Its functions: GraineCallTransport, fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineCallTransport.GraineCallTransport
The enum's constructor; use the values (GraineCallTransport.auto, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The value as the native engine reads and reports it — the same word as the value's name. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
GraineCallTransport.fromWire
Use it to read what carried a call from the native engine's word — for a test; the snapshot does this itself.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | Object? | required | The word the native engine reports for a call: 'webrtc' or 'websocket'. |
Returns — GraineCallTransport? — webrtc or websocket; null for anything else, 'auto' included: it is a choice, never what carried a call. Example value: GraineCallTransport.webrtc.
Errors — none.
GraineCalls.attach
Call it once after configure so native calls know who the customer is, the prompt variables, the screen and your actions — kept in step as they change.
Hands native calls what the app already tells the agent through graine — who the customer is, the prompt variables, the screen and the actions it registered — kept in step as they change, and answers the agent's actions on a call through the app's own handlers. With several agents, attach the default one: while a call is with another agent (startCall(agent:), or a ring for it), the engine holds that agent's variables and actions instead, and its actions run in that agent's handlers.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
graine | GraineInApp? | optional | The agent whose context native calls carry; the default agent when left out. |
Returns — void Function() — call it to detach: the engine then holds no actions, and an action the agent asks for on a call is refused.
Errors — none. Before init, leaving out graine throws StateError (from GraineInApp.instance).
GraineCalls.startCall
Call it from a "Call" button to call the agent now.
The customer calls the agent, now, as a native call — the system's call UI on iOS (CallKit), the SDK's call screen (or yours) on Android. The agent is given who_called = "customer" and call_reason; variables are merged over the app's own and take precedence. The call starts at once on the agent's configuration the device already keeps and refreshes it behind the call. Before the conversation opens, iOS gives the whole connect one 20-second deadline and Android 15 seconds; a call that misses it ends failed — "The call could not connect within 20 seconds." on iOS (or, when the connection itself takes more than 15 seconds to open, "The conversation did not open within 15 seconds."), "The call could not connect within 15 seconds." on Android. On iOS a call whose audio never starts fails with "The call's audio could not start."; on Android a connected call on which nothing arrives for 50 seconds ends with reason failed. Follow it on GraineCalls.instance and outcomes.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
reason | String? | optional | Why the customer is calling — the agent hears it as call_reason. |
variables | Map<String, Object?> | const <String, Object?>{} | Prompt variables for this call, over the app's own; masked on the device before they leave it. |
agent | String? | optional | Which agent to call, by the name the app configured it under; the default agent when left out. |
Returns — Future<String?> — the call's id, which every outcome carries; null when a call is already live (one at a time), on a platform other than Android and iOS, or in a build without the native engine. Example value: 'call_6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44'.
Errors — a PlatformException when the engine refuses to place it (for example before configure). The microphone is asked for by the SDK; refused, the call ends failed ("The microphone permission was denied.").
GraineCalls.end
Call it from your own call screen to hang up — or decline, while it rings.
Hangs up the live call — or declines it while it rings. On Android 0.8.0 the microphone is let go at once, and a hang-up the network cannot carry is forced within about a second. The outcome follows on outcomes (ended, reason local; or declined).
Parameters — none.
Returns — Future<void>, which completes once the engine has it.
Errors — none; with no call it does nothing.
GraineCalls.setMuted
Call it from your own call screen to stop, or resume, sending the customer's voice.
Stops, or resumes, sending the customer's voice without ending the call. The snapshot's muted follows.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
muted | bool | required | true to stop sending the customer's voice; false to send it again. |
Returns — Future<void>.
Errors — none; with no call it does nothing.
GraineCalls.setSpeaker
Call it from your own call screen to switch between the loudspeaker and the earpiece or headset.
Moves the call's audio to the loudspeaker, or back to the earpiece or a headset. Calls start on the earpiece, like a phone call. The snapshot's speakerOn follows.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
on | bool | required | true for the loudspeaker; false for the earpiece or a headset. |
Returns — Future<void>.
Errors — none.
GraineCalls.resetForTesting
Call it between tests to forget everything the instance holds.
For tests only (@visibleForTesting): forgets everything the instance holds — the listener, the call's state, outcomes and rings waiting for a listener, the token watchers, the attached agent and the options.
Parameters — none.
Returns — nothing.
Errors — none.
GraineCallSnapshot
Read it to draw your own call screen: where the call is, who it is with, the caption and the controls' state.
class GraineCallSnapshot
What to expect — GraineCalls.instance.value, replaced on every change (listen to GraineCalls.instance). status goes idle → ringing (an incoming call) or connecting (a call placed) → active → ended, then idle again once reported. One call at a time: a second ring while a call is live is missed (busy). While no call is live, each field holds its idle value. error keeps why the last call could not connect — "The call could not connect within 20 seconds.", "The conversation did not open within 15 seconds." or "The call's audio could not start." on iOS, "The call could not connect within 15 seconds." on Android — until the next call starts; a call that connected and was then lost leaves no error (its outcome says ended, failed).
| Property | Type | Meaning |
|---|---|---|
static const GraineCallSnapshot idle | GraineCallSnapshot | The state with no call: every field at its idle value. |
final GraineNativeCallStatus status | GraineNativeCallStatus | Where the call is: idle, ringing, connecting, active or ended. Pick the call screen's state from it. |
final String? callId | String? | For a call your server rang, your server's id; for a call the customer placed, an id generated for it. Every outcome carries it. |
final GraineCallDirection? direction | GraineCallDirection? | Who placed the call: incoming (a ring reached this phone) or outgoing (the customer called); null with no call. |
final String? reason | String? | The reason carried by the push, or the reason passed to startCall. |
final String? callerName | String? | The name the call shows. |
final bool muted | bool | True while the customer's voice is not being sent. Draw the mute button's state from it. |
final bool speakerOn | bool | True when sound plays through the loudspeaker instead of the earpiece or a headset. |
final bool agentSpeaking | bool | The agent's voice is playing right now. |
final GraineCallCaption? caption | GraineCallCaption? | The most recent line — the agent's words while being spoken, or the customer's while being heard. |
final DateTime? connectedAt | DateTime? | The time the conversation began, for showing a call timer. |
final String? error | String? | Why the last call could not connect, in the engine's words; cleared when the next call starts. |
final String? agent | String? | The agent the call is with, by the name the app configured it under ('default' for the default agent) — the one startCall named, or the one a ring was routed to by its push. Null with no call. |
final GraineCallTransport? transport | GraineCallTransport? | What carries the call's audio: GraineCallTransport.webrtc or GraineCallTransport.websocket — for a call the customer placed and a call Graine rang alike. Read it once the call is active. Null with no call, before the way is decided, and from an engine that predates WebRTC. New in 0.9.0. |
final String? transportFallbackReason | String? | Why a call that wanted WebRTC runs on the WebSocket instead — one of the words below; null when it did not fall back. Read it once the call is active. New in 0.9.0. |
Why a call is on the WebSocket — transportFallbackReason, set only for a call that wanted WebRTC and runs on the WebSocket. The first six come from a WebRTC setup that gave up before any audio flowed; the call went on, inside the same call:
| Value | Meaning |
|---|---|
mint_failed | The call's WebRTC session could not be set up: refused, rate-limited, or unreachable. |
register_failed | Graine's media service did not accept the connection, or never answered it. |
no_response | The call got no reply at all. |
no_answer | Replies came; the answer did not. |
ice_timeout | Answered, but the audio path never connected — a network that blocks WebRTC. |
error | Anything else before the audio flowed. |
dashboard | Android only: the agent's In-app call audio setting is Standard, so a call that would have taken WebRTC runs on the WebSocket. On iOS such a call simply runs on the WebSocket, with no reason. |
unavailable | Android only: the app asked for GraineCallTransport.webrtc in a build without WebRTC. On iOS such a call simply runs on the WebSocket, with no reason. |
Its functions: GraineCallSnapshot, fromMap — each with its parameters, what it returns, the errors it raises and an example.
GraineCallSnapshot.GraineCallSnapshot
Use it to build a call's state by hand for a preview or a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
status | GraineNativeCallStatus | GraineNativeCallStatus.idle | Where the call is: idle, ringing, connecting, active or ended. Pick the call screen's state from it. |
callId | String? | optional | For a call your server rang, your server's id; for a call the customer placed, an id generated for it. Every outcome carries it. |
direction | GraineCallDirection? | optional | Who placed the call: incoming (a ring reached this phone) or outgoing (the customer called); null with no call. |
reason | String? | optional | The reason carried by the push, or the reason passed to startCall. |
callerName | String? | optional | The name the call shows. |
muted | bool | false | True while the customer's voice is not being sent. Draw the mute button's state from it. |
speakerOn | bool | false | True when sound plays through the loudspeaker instead of the earpiece or a headset. |
agentSpeaking | bool | false | The agent's voice is playing right now. |
caption | GraineCallCaption? | optional | The most recent line — the agent's words while being spoken, or the customer's while being heard. |
connectedAt | DateTime? | optional | The time the conversation began, for showing a call timer. |
error | String? | optional | Why the last call could not connect, in the engine's words; cleared when the next call starts. |
agent | String? | optional | The agent the call is with, by the name the app configured it under ('default' for the default agent) — the one startCall named, or the one a ring was routed to by its push. Null with no call. |
transport | GraineCallTransport? | optional | What carries the call's audio: webrtc or websocket; null with no call. |
transportFallbackReason | String? | optional | Why a call that wanted WebRTC runs on the WebSocket (no_answer, ice_timeout, …); null when it did not fall back. |
Returns — a new GraineCallSnapshot.
Errors — none.
GraineCallSnapshot.fromMap
Use it to read a call's state from the native engine's message — for a test; GraineCalls.instance does this itself.
From the engine's snapshot.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
m | Map<Object?, Object?>? | required | The call's state as the native engine sent it; null reads as no call. |
Returns — GraineCallSnapshot — the call's state; anything missing reads as its idle value, and null as GraineCallSnapshot.idle.
Errors — none.
GraineNativeCallStatus
Read it to know where a native call is: idle, ringing, connecting, active or ended.
enum GraineNativeCallStatus
What to expect — idle → ringing (an incoming call) or connecting (a call placed) → active → ended, then idle again once reported. One call at a time: a second ring while a call is live is missed (busy).
| Case | Meaning |
|---|---|
idle('idle') | No call. The state between calls, and before the first one. |
ringing('ringing') | An agent's call is ringing on this phone and has not been answered. |
connecting('connecting') | The customer answered, or placed the call, and the conversation is being opened. |
active('active') | The call is connected and its audio runs: the customer and the agent can hear each other. |
ended('ended') | The call is over; idle follows once it has been reported. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The status as the native engine words it — the same word as the value's name. |
bool get isLive | bool | Ringing, connecting or connected. |
Its functions: GraineNativeCallStatus, fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineNativeCallStatus.GraineNativeCallStatus
The enum's constructor; use the values (GraineNativeCallStatus.ringing, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The status as the native engine words it — the same word as the value's name. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
GraineNativeCallStatus.fromWire
Use it to read a call's status from its word.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | Object? | required | The status's word; anything else reads as idle. |
Returns — GraineNativeCallStatus. Example value: GraineNativeCallStatus.idle.
Errors — none.
GraineCallDirection
Read it to know who placed the call: the agent (a ring reached the phone) or the customer.
enum GraineCallDirection { incoming, outgoing }
What to expect — Set while a call is live; null with no call.
| Case | Meaning |
|---|---|
incoming | The agent placed it: a ring reached this phone (a push from Graine or your server). |
outgoing | The customer placed it (startCall). |
GraineCallCaption
Read it to show the line being said on a native call.
class GraineCallCaption
What to expect — The line being said right now, by either side; live while it is still being recognised or spoken. Replaced as the conversation moves on: draw the latest.
| Property | Type | Meaning |
|---|---|---|
final Role role | Role | Who is saying it: Role.agent or Role.customer. |
final String text | String | The words, as far as they have been said or heard. |
final bool live | bool | Still being said. |
Its functions: GraineCallCaption — each with its parameters, what it returns, the errors it raises and an example.
GraineCallCaption.GraineCallCaption
Use it to build a caption by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
role | Role | required | Who is saying it: Role.agent or Role.customer. |
text | String | required | The words, as far as they have been said or heard. |
live | bool | false | Still being said. |
Returns — a new GraineCallCaption.
Errors — none.
GraineCallOutcome
Read it to learn what became of each call — to tell your own server, or to follow up.
class GraineCallOutcome
What to expect — Reported once per change on GraineCalls.instance.outcomes: ringing (a call Graine rang), then answered and ended (with reason local, remote or failed, and durationSeconds where the platform reports it) — or declined, missed (busy when another call was live) or failed with why. Outcomes from before anyone listened — a call that rang and ended while the app was not running — reach the first listener, oldest first (the last 20). hosted means Graine rang it and the SDK has already told Graine; tell your own server about the others, under callId. Do not rely on their order relative to the call's state changes.
| Property | Type | Meaning |
|---|---|---|
final String callId | String | The call's id — your server's call_id for a ring it sent, Graine's for a ring Graine sent, or the one startCall returned. Report the outcome under it. |
final GraineCallOutcomeKind outcome | GraineCallOutcomeKind | What became of the call: ringing, answered, declined, missed, ended or failed. Branch on it; wire is the same as one word. |
final String? reason | String? | With ended: local, remote or failed. With failed: why the call never connected, as the native engine words it — "The call could not connect within 20 seconds.", "The conversation did not open within 15 seconds." or "The call's audio could not start." (iOS), "The call could not connect within 15 seconds." (Android), "The microphone permission was denied.", … |
final int? durationSeconds | int? | How long the conversation lasted, with ended, when the engine says. |
final bool hosted | bool | True when Graine rang the call (hosted ringing); the SDK has already reported its result to Graine. |
final String? agent | String? | The name under which the app configured the agent on this call ('default' for the default agent), or null if the engine cannot tell. |
String get wire | String | Its value as one word, for your server: one of ringing, answered, declined, missed, ended, failed. |
GraineCallOutcomeKind get kind | GraineCallOutcomeKind | outcome, by its 0.6 name. Deprecated: use outcome. |
String? get endReason | String? | reason of an ended call, by its 0.6 name. Deprecated: use reason. |
String? get error | String? | reason of a failed call, by its 0.6 name. Deprecated: use reason. |
Its functions: GraineCallOutcome, fromMap — each with its parameters, what it returns, the errors it raises and an example.
GraineCallOutcome.GraineCallOutcome
Use it to build an outcome by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
callId | String | required | The call's id — your server's call_id for a ring it sent, Graine's for a ring Graine sent, or the one startCall returned. Report the outcome under it. |
outcome | GraineCallOutcomeKind | required | What became of the call: ringing, answered, declined, missed, ended or failed. Branch on it; wire is the same as one word. |
reason | String? | optional | With ended: local, remote or failed. With failed: why the call never connected, as the native engine words it — "The call could not connect within 20 seconds.", "The conversation did not open within 15 seconds." or "The call's audio could not start." (iOS), "The call could not connect within 15 seconds." (Android), "The microphone permission was denied.", … |
durationSeconds | int? | optional | How long the conversation lasted, with ended, when the engine says. |
hosted | bool | false | True when Graine rang the call (hosted ringing); the SDK has already reported its result to Graine. |
agent | String? | optional | The name under which the app configured the agent on this call ('default' for the default agent), or null if the engine cannot tell. |
Returns — a new GraineCallOutcome.
Errors — none.
GraineCallOutcome.fromMap
Use it to read an outcome from the native engine's message — for a test; outcomes does this itself.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
m | Map<Object?, Object?> | required | The outcome as the native engine sent it. |
Returns — GraineCallOutcome. An outcome word this build does not know reads as failed; a failed call's reason is the engine's sentence for why it never connected.
Errors — none.
GraineCallOutcomeKind
Read it to know what became of a call: ringing, answered, declined, missed, ended or failed.
enum GraineCallOutcomeKind { ringing, answered, declined, missed, ended, failed }
What to expect — A call Graine rang reports ringing first; then answered, and ended when it is over — or declined, missed or failed instead. A word this build does not know reads as failed.
| Case | Meaning |
|---|---|
ringing | It started ringing on this device. |
answered | The customer answered. |
declined | The customer declined. |
missed | Nobody answered before ringTimeout, or another call was live (busy). |
ended | It was connected and is over. reason: local (this app hung up), remote (the agent did) or failed (the connection was lost mid-call — on Android, also when nothing at all arrived for 50 seconds). |
failed | It never connected. reason says why, in a sentence — for example "The call could not connect within 20 seconds.", "The conversation did not open within 15 seconds." or "The call's audio could not start." on iOS, "The call could not connect within 15 seconds." on Android, or "The microphone permission was denied." |
GraineCallState
Use it to draw your own controls for the in-app call the voice bar places — GraineInApp.instance.voice is the one to use; a test hands the widgets a fake.
abstract class GraineCallState implements Listenable
What to expect — This is the voice bar's in-app call, not a native call (that is GraineCallSnapshot). GraineInApp.instance.voice implements it and GraineAgentBar draws from it; listen to it and redraw on every change. connecting turns true at start() — while the app is asked for the microphone, and while a start waits for the page — then connected once the conversation opens. One conversation at a time: starting it ends a chat or a call another agent holds, and it waits while a native call is live.
| Property | Type | Meaning |
|---|---|---|
bool get connected | bool | True while the call is connected — the customer and the agent can hear each other. Draw the in-call controls from it. |
bool get connecting | bool | True from start() until the call connects or fails — a held start, the microphone question and the dial included. Draw "Connecting…" from it. |
bool get muted | bool | True while the customer's voice is not being sent (setMuted(true)). Draw the microphone button's state from it. |
bool get ready | bool | The page that carries the call is loaded and ready: a start connects at once. Until then a start is held and fired when it is ready. |
bool get reconnecting | bool | True while the call is being brought back after a network interruption. |
bool? get online | bool? | Whether the device is online, as last reported; null before the first report. |
ConnectionQuality get quality | ConnectionQuality | The call's connection right now, in one word; unknown before the first measurement and between calls. Show "Weak connection" on poor. |
GraineConnectivity get connectivity | GraineConnectivity | Whether the page that carries the call is there: loading, ready, retrying or failed. Offer "Try again" (retry()) on failed. |
List<Caption> get captions | List<Caption> | What has been said so far, oldest first, a sentence growing word by word kept as one line. |
Caption? get caption | Caption? | The line being said now, or the last one; null before any. |
bool get agentSpeaking | bool | The agent is mid-sentence. |
bool get micDenied | bool | The last start was refused the microphone. |
Map<String, Object?> get appearance | Map<String, Object?> | The dashboard's Appearance for this agent; empty until the session loads. |
Its functions: start, end, setMuted, retry — each with its parameters, what it returns, the errors it raises and an example.
GraineCallState.start
Call it from your own button to start the agent's in-app voice call.
Places the agent's in-app voice call — what the bar's microphone does. With GraineConfig.requestMicrophone set, the app is asked for the microphone first; a refusal places nothing and reports onMicDenied('NotAllowedError'). Before the page that carries the call is ready, the start is held and fired when it is. One conversation at a time: it ends a chat or a call another agent holds.
Parameters — none.
Returns — Future<void>, which completes once the call is placed or held — not when it connects; follow connecting and connected.
Errors — none thrown: with a native call live it reports onError('A call is already in progress.'); with no GraineEngine on screen it reports onError asking you to place one, and places nothing.
GraineCallState.end
Call it from your own button to hang up the in-app call.
Hangs up the in-app call — or cancels a start still waiting for the page. If the page never confirms the end, the call is torn down on the device after GraineTiming.endWatchdogMs (4 seconds by default).
Parameters — none.
Returns — nothing.
Errors — none.
GraineCallState.setMuted
Call it from your own button to stop, or resume, sending the customer's voice on the in-app call.
Stops, or resumes, sending the customer's voice on the in-app call without ending it. muted follows at once.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
muted | bool | required | true to stop sending the customer's voice; false to send it again. |
Returns — nothing.
Errors — none.
GraineCallState.retry
Call it from a "Try again" button when the page that carries the call could not load.
Reloads the page that carries the call and starts its retry ladder over — for a "Try again" button when connectivity is failed. connectivity goes back to loading.
Parameters — none.
Returns — nothing.
Errors — none.
Calls Graine rings
When your workspace has uploaded its push credentials (Workspace settings → In-app calling), Graine itself rings your users for the calls the agent or the user booked — and your own server can ring them with a push too. On Android, Firebase Cloud Messaging in the app is all it takes — the SDK registers for pushes itself — and an app whose own messaging service receives the pushes (firebase_messaging) forwards them to handlePush; on iOS, enableVoIPPushes is all it takes. The SDK tells Graine what became of every ring it sent; a ring nobody answers reaches outcomes as missed. The push carries nothing personal: type, call_id, caller_name, hosted and agent_id.
A call answered here carries its audio the way the calls the customer places do: over WebRTC in a build that has it (WebRTC calls) — prepared while the ring shows, so answering connects at once — as GraineCallsOptions.callTransport and the agent's In-app call audio allow, and over the WebSocket otherwise. Once it is active, its snapshot says which (GraineCallSnapshot.transport, transportFallbackReason).
GraineCalls.registerPushToken
Call it on Android only when your app's own messaging service receives the tokens (firebase_messaging), from onTokenRefresh. With Firebase Cloud Messaging in the app the SDK reads the token itself at launch, and without a messaging service of your own the SDK's receives every new one.
Android: registers this device with Graine for hosted ringing, with your Firebase messaging token — when the workspace has Graine ring its users — together with who is signed in, and again whenever they change. Most apps never call it: the SDK reads the token at launch. On iOS it does nothing: the VoIP token is registered natively (enableVoIPPushes).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
token | String | required | The FCM token; trimmed, and an empty one is ignored. |
Returns — Future<void>.
Errors — none: a failure is logged with debugPrint ("[Graine] calls: registerPushToken failed (…)"); a build without the native engine ignores it.
GraineCalls.enableVoIPPushes
Call it once on iOS to receive the agent's calls as VoIP pushes — all an iOS app needs for Graine to ring it.
iOS: receives the agent's calls as VoIP pushes through CallKit. The SDK registers the VoIP token with Graine itself when your workspace has Graine ring its users; onToken gets it too, for your own server's pushes (APNs, apns-push-type: voip) — now, if the device has one, and whenever it changes; null when it is invalidated. Every VoIP push rings, as iOS requires. On Android it does nothing — use handlePush.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
onToken | void Function(String? token) | required | Called with the VoIP token, and with null when it is invalidated. |
Returns — void Function() — call it to stop hearing tokens.
Errors — none.
GraineCalls.handlePush
Call it on Android from your Firebase message handlers, foreground and background, when your app's own messaging service receives the pushes (firebase_messaging), so a Graine call rings even when the app was closed. Without one, the SDK's own messaging service hands every push to the engine natively.
Android: hands a push's data to the call engine, from your Firebase message handlers in the foreground and the background. A Graine call rings with a call notification and the call screen, even when the app was not running; a ring that arrives during a live call is missed (busy). The push carries nothing personal — type, call_id, caller_name, hosted and agent_id. On iOS it does nothing: VoIP pushes arrive natively.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | Map<String, Object?> | required | The push's data, exactly as Firebase delivered it (RemoteMessage.data). |
Returns — Future<bool> — true when the push was a call (ringing, busy or malformed) and the app should do nothing more with it; false for any other push, on iOS, or in a build without the native engine. Example value: true.
Errors — none.
GraineCalls.answer
Call it to answer the ringing call from your own screen; the SDK's call screens and the system's answer by themselves.
Answers the ringing call from a screen of your own (GraineCallScreen.app). The SDK's call screen and the system's answer by themselves. The microphone is checked as for a call placed: refused, the call ends failed after answered.
Parameters — none.
Returns — Future<void>.
Errors — none; with nothing ringing it does nothing.
GraineCalls.decline
Call it to decline the ringing call from your own screen.
Declines the ringing call from a screen of your own. For a call Graine rang, nothing rings this customer again for 6 hours; the outcome is declined.
Parameters — none.
Returns — Future<void>.
Errors — none; with nothing ringing it does nothing.
GraineIncomingCall
Read it to know an agent's call has started ringing on this device — for your own ringing UI or analytics.
class GraineIncomingCall
What to expect — When a ring reaches this device (a push from Graine or your server) — before the customer answers. It carries only what the ring shows: nothing personal.
| Property | Type | Meaning |
|---|---|---|
final String callId | String | The ringing call's id, as the push named it — the same id its outcome will carry. |
final String? reason | String? | Why the agent is calling, as the push said it; null when it said nothing. Graine's own rings never carry the booking's reason. |
final String? callerName | String? | The name the ring shows — the push's caller_name, else GraineCallsOptions.displayName. |
final bool hosted | bool | True when the ring came from Graine (hosted ringing) and not from a push your server sent. |
final String? agent | String? | The name under which the app configured the ringing agent ('default' for the default agent). The native engine finds it by matching the push's agent_id against the configured agents' ids, falling back to the default agent when none match. |
Its functions: GraineIncomingCall — each with its parameters, what it returns, the errors it raises and an example.
GraineIncomingCall.GraineIncomingCall
Use it to build a ring by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
callId | String | required | The ringing call's id, as the push named it — the same id its outcome will carry. |
reason | String? | optional | Why the agent is calling, as the push said it; null when it said nothing. Graine's own rings never carry the booking's reason. |
callerName | String? | optional | The name the ring shows — the push's caller_name, else GraineCallsOptions.displayName. |
hosted | bool | false | True when the ring came from Graine (hosted ringing) and not from a push your server sent. |
agent | String? | optional | The name under which the app configured the ringing agent ('default' for the default agent). The native engine finds it by matching the push's agent_id against the configured agents' ids, falling back to the default agent when none match. |
Returns — a new GraineIncomingCall.
Errors — none.
CallsSetting
Read it to know whether Graine rings this workspace's apps, on which platforms, for how long, and what customers may book.
class CallsSetting
What to expect — Part of the session; null until it arrives, and from an agent that does not say — which means no hosted ringing and no booking.
| Property | Type | Meaning |
|---|---|---|
final bool hosted | bool | True if push credentials were uploaded for the workspace, which lets Graine ring its users' devices. |
final List<String> platforms | List<String> | Where it can ring: ios, android. |
final int ringTimeoutSeconds | int | How long a ring Graine sends lasts before it is missed, in seconds (default 45; read within 20–60). |
final String? callName | String? | The name the phone displays for the agent's calls; when null, the agent's display name is shown. |
final SchedulingSetting? scheduling | SchedulingSetting? | What customers may book from the app; null when the agent's settings say nothing (no booking). |
Its functions: CallsSetting, fromJson — each with its parameters, what it returns, the errors it raises and an example.
CallsSetting.CallsSetting
Use it to build the call settings by hand for a test; the session carries the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hosted | bool | false | True if push credentials were uploaded for the workspace, which lets Graine ring its users' devices. |
platforms | List<String> | const <String>[] | Where it can ring: ios, android. |
ringTimeoutSeconds | int | 45 | How long a ring Graine sends lasts before it is missed, in seconds (default 45; read within 20–60). |
callName | String? | optional | The name the phone displays for the agent's calls; when null, the agent's display name is shown. |
scheduling | SchedulingSetting? | optional | What customers may book from the app; null when the agent's settings say nothing (no booking). |
Returns — a new CallsSetting.
Errors — none.
CallsSetting.fromJson
Use it to read the call settings from the session's JSON.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The value as decoded from JSON; anything that is not the expected object reads as null. |
Returns — CallsSetting?. Example value: null.
Errors — none.
Permissions and the setup check
What a call needs from the phone, and from your app's setup, in one place. The SDK never asks on its own at launch: it asks for the microphone when a call starts without it, and requestCallPermissions() asks earlier, when your app chooses — on Android from a transparent screen of the SDK's own, so nothing forwards a permission result. callSetupProblems() says what your setup still lacks; the native SDK logs each problem once from configure on, and a debug build also prints each once in the console flutter run shows. A problem is never an exception: calls still work where they can.
GraineCalls.callPermissions
Read it to see which call permissions the phone holds now.
The microphone, and on Android the ring's notifications (13+ asks) and the full-screen ring (14+, Settings only); on iOS those two are notNeeded — CallKit rings and draws its own screen. Readable before configure. On a platform other than Android and iOS, everything is notNeeded.
Returns — Future<GraineCallPermissions>. Read it again when the app returns to the foreground: the customer may have changed Settings.
Errors — none: a build without the plugin's native side reads everything as denied.
GraineCalls.requestCallPermissions
Call it at a moment you choose — onboarding, a "Call me" screen — to ask for what a call needs.
Asks for the call permissions the system's dialog can still ask for — the microphone, and notifications on Android 13+ — and returns them as they stand after. Nothing to ask: the answer comes at once. The full-screen ring has no dialog: openCallSettings(GraineCallPermission.fullScreen) opens its page. The SDK never asks on its own at launch; a call that starts without the microphone still asks then.
Returns — Future<GraineCallPermissions>, after the customer answers.
Errors — none.
GraineCalls.openCallSettings
Call it to send the customer to the Settings page that changes a call permission.
Opens, on Android, the full-screen ring's own page (14+) or the app's notification settings; otherwise the app's page, where the microphone is.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
item | GraineCallPermission | required | The permission the customer should change. |
Returns — Future<bool>: true when a page opened. Example value: true.
Errors — none: a build without the plugin's native side returns false and says so in the console.
GraineCalls.callSetupProblems
Read it to learn what your app's setup still lacks for calls, in plain words.
What the app's setup still lacks for calls, read now — each a stable code and a sentence with the exact fix. Empty when nothing is missing, and before configure.
| Code | Platform | When |
|---|---|---|
microphone_usage_missing | iOS | ios/Runner/Info.plist has no NSMicrophoneUsageDescription: iOS closes the app when a call asks for the microphone. A plugin cannot add it. |
background_audio_missing | iOS | UIBackgroundModes lacks audio: a call goes silent when the screen locks. |
background_voip_missing | iOS | UIBackgroundModes lacks voip: iOS does not wake the app for a ring. |
push_entitlement_missing | iOS | Signed without Push Notifications (read from development and ad hoc builds). |
voip_pushes_not_enabled | iOS | enableVoIPPushes not called 15 seconds after configure. |
no_voip_token | iOS | No VoIP token 15 seconds after enableVoIPPushes (never on the simulator). |
manifest_entry_missing | Android | The merged manifest lost a call entry (look for tools:node="remove"). |
no_push_token | Android | No push token 15 seconds after configure: Firebase Cloud Messaging is missing or not set up in the Android app (the message says which), or an app whose own messaging service receives the tokens never called registerPushToken. Calls can't ring. |
notifications_not_allowed | Android | A call can't ring while the app is closed or in the background. |
full_screen_not_allowed | Android | A locked phone rings with a heads-up notification instead. |
microphone_blocked | Both | Only Settings can let calls hear the customer. |
hosted_ringing_off | Both | No push credentials uploaded for this platform: Graine can't ring this phone. |
Returns — Future<List<GraineCallSetupProblem>>.
Errors — none.
GraineCallPermission
Use it to name a call permission.
enum GraineCallPermission
What to expect — Three permissions, the same on every SDK. On iOS only the microphone is ever asked for.
| Case | Meaning |
|---|---|
microphone('microphone') | The customer's voice. |
notifications('notifications') | A call that rings while the app is closed or in the background — Android (13+ asks). iOS rings through CallKit, which needs none. |
fullScreen('fullScreen') | A ring that fills a locked screen — Android 14+, allowed in Settings. iOS: CallKit's own screen. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The word every Graine SDK uses for it. |
Its functions: GraineCallPermission — each with its parameters, what it returns, the errors it raises and an example.
GraineCallPermission.GraineCallPermission
The enum's constructor; use the values (GraineCallPermission.microphone, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The word every Graine SDK uses for it. |
Returns — nothing you call: an enum's constructor runs once for each value.
Errors — none.
GraineCallPermissionStatus
Read it to tell whether a call permission is allowed, can still be asked for, or only Settings can change it.
enum GraineCallPermissionStatus
What to expect — granted and notNeeded need nothing; denied means requestCallPermissions() can ask; blocked means only Settings can change it — offer openCallSettings.
| Case | Meaning |
|---|---|
granted('granted') | Allowed. |
denied('denied') | Not allowed yet: requestCallPermissions() can ask for it. |
blocked('blocked') | Refused for good, or only allowed in Settings: only the Settings app can change it. |
notNeeded('notNeeded') | This phone needs no such permission. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The word every Graine SDK uses for it. |
bool get isSatisfied | bool | Granted, or nothing to grant. |
Its functions: GraineCallPermissionStatus, fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineCallPermissionStatus.GraineCallPermissionStatus
The enum's constructor; use the values (GraineCallPermissionStatus.granted, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The word every Graine SDK uses for it. |
Returns — nothing you call: an enum's constructor runs once for each value.
Errors — none.
GraineCallPermissionStatus.fromWire
Use it to read a status from the engine's word — for a test; GraineCallPermissions.fromMap does this itself.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | Object? | required | The engine's word: 'granted', 'denied', 'blocked' or 'notNeeded'. |
Returns — GraineCallPermissionStatus; anything it does not know is denied, never granted. Example value: GraineCallPermissionStatus.blocked.
Errors — none.
GraineCallPermissions
Read it to see every call permission at once.
class GraineCallPermissions
What to expect — A snapshot of the phone when read: call callPermissions() again for the latest. allGranted is the one check before offering calls; permissions[GraineCallPermission.microphone] reads one by name. Equal when every status is.
| Property | Type | Meaning |
|---|---|---|
final GraineCallPermissionStatus microphone | GraineCallPermissionStatus | The microphone. |
final GraineCallPermissionStatus notifications | GraineCallPermissionStatus | The ring's notifications — notNeeded on iOS. |
final GraineCallPermissionStatus fullScreen | GraineCallPermissionStatus | The full-screen ring — notNeeded on iOS. |
bool get allGranted | bool | Every permission is granted or not needed: calls can ring and connect. |
Its functions: GraineCallPermissions, fromMap — each with its parameters, what it returns, the errors it raises and an example.
GraineCallPermissions.GraineCallPermissions
Use it to build permissions for a test or a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
microphone | GraineCallPermissionStatus | required | The microphone's status. |
notifications | GraineCallPermissionStatus | required | The notifications' status. |
fullScreen | GraineCallPermissionStatus | required | The full-screen ring's status. |
Returns — a new GraineCallPermissions.
Errors — none.
GraineCallPermissions.fromMap
Use it to read the permissions from the engine's map — for a test; callPermissions() does this itself.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
m | Map<Object?, Object?>? | required | {microphone, notifications, fullScreen}, each the engine's word. |
Returns — a GraineCallPermissions; a missing or unknown word reads denied.
Errors — none.
GraineCallSetupProblem
Read it to show or log what your app's setup still lacks.
class GraineCallSetupProblem
What to expect — The code is stable and the same on every SDK (the list is under GraineCalls.callSetupProblems); the message is a sentence for the developer, with the exact fix. Equal when both are.
| Property | Type | Meaning |
|---|---|---|
final String code | String | Stable: act on it, or count it. |
final String message | String | What is missing and how to fix it, in plain words. |
Its functions: GraineCallSetupProblem — each with its parameters, what it returns, the errors it raises and an example.
GraineCallSetupProblem.GraineCallSetupProblem
Use it to build a problem for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
code | String | required | The stable code. |
message | String | required | The sentence with the fix. |
Returns — a new GraineCallSetupProblem.
Errors — none.
Booking with the SDK's sheet
New in 0.8.0: the SDK draws the booking screen itself — "Call me at…" with no screen of your own. GraineBooking.show(context) opens it over your app in the agent's design, light or dark: a sheet up from the bottom on a phone, a centred panel on a tablet. The customer picks a day and a time, may say what the call is about, taps Book call, and Graine rings them then.
What the customer sees, top to bottom:
- Book a call, and under it who will ring them — "Asha will call you" — named by the agent's call name from Calls & scheduling, else the chat's title, else the heading, else "Assistant".
- Day — chips from today to the furthest day the agent allows: "Today", "Tomorrow", then the weekday and date ("Thu 16 Oct"). Days that have no time remaining are left out.
- Time — Flutter's own time picker (
showTimePicker, which works without aMaterialApptoo). The choice is rounded to 5 minutes and held between the earliest and the latest time the agent allows; the first time on the chosen day is offered to start with. - The device's time zone and the time chosen: "Asia/Kolkata · Wed 14 Oct, 6:00 PM".
- What's it about? (optional) — one line, at most 120 characters;
reasonfills it in, and the customer may change it. - Book call — a spinner while it books; then the sheet says "Booked — Asha will call you on Wed 14 Oct, 6:00 PM" (always the date, never "Today") with Done.
A refusal stays in the sheet as one line under the button, word for word:
| When | The line |
|---|---|
tooSoon | Pick a time at least 5 minutes from now (the agent's notice, counted: "1 minute", "5 minutes") — the sheet then moves on to the new earliest time |
tooFar | Pick a time within 14 days (the agent's horizon) |
outsideWindow | That time is outside the hours we can call — pick another |
tooManyPending | You already have 3 calls booked — cancel one first (the agent's limit) |
schedulingOff | Booking a call isn't available right now |
identityRequired | Sign in to book a call |
rateLimited, unavailable, network and anything else | Couldn't book just now — try again |
The future GraineBooking.show returns completes with the booked GraineScheduledCall once the sheet closes, or null when the customer closed it without booking. Show your own "Call me" button only when bookingAvailable is true; the SDK's chat window does the same: Book a call sits under the booked calls in its Upcoming calls card — or on its own in the card's place while none are booked — and never when the design hides the booked-calls card (ChatPieces.book). A booking from the sheet or from scheduleCall shows on the card at once. For a booking screen of your own, Booking holds the same rules and words.
GraineInApp.bookingAvailable
Read it to decide whether to show your own "Call me" button: true only when this customer can book a call from here.
True only when all of these hold:
- the agent lets customers book (Agent → Calls & scheduling → users may book;
schedulingRules.usersCanBook); - Graine rings this phone: the workspace set up In-app calling (
session.calls.hosted), and its platforms are empty or name this one —iosorandroid; - the customer is identified with the trait the agent's Identity setting names (
identify—user_idunless the dashboard names another).
False until the agent's settings have loaded (loadSession()), and false on any platform other than iOS and Android. Each agent has its own. It changes when the settings arrive and when the customer signs in or out; bookingListenable redraws a widget then, and bookingBlocker says why it is false. GraineBooking.show opens the SDK's booking sheet.
Parameters — none.
Returns — bool. Example value: true.
Errors — none.
GraineInApp.bookingBlocker
Read it to know why booking is not available — to say so, or to ask the customer to sign in.
Why bookingAvailable is false, as the booking sheet says it — or null when it is true. The agent's settings are checked first: signing in would not help while booking is off.
| Value | When | The sheet's line |
|---|---|---|
GraineErrorCode.schedulingOff | The agent takes no bookings, Graine does not ring this phone (no In-app calling, or not for this platform), the app runs on neither iOS nor Android, or the settings have not loaded | Booking a call isn't available right now |
GraineErrorCode.identityRequired | Booking is on, but nobody is identified | Sign in to book a call |
null | Booking is available | No line: Book call books |
Parameters — none.
Returns — GraineErrorCode?. Example value: GraineErrorCode.identityRequired.
Errors — none.
GraineInApp.bookingListenable
Use it to redraw a widget — your "Call me" button — when booking becomes available or stops being so.
bookingAvailable, as a listenable: it starts false and changes when the agent's settings arrive and when the customer signs in or out.
Parameters — none.
Returns — ValueListenable<bool>. Example value: its value is true once booking is available.
Errors — none.
GraineInApp.deviceTimezone
Read it to show the customer which time zone a time is in, as the booking sheet does.
The device's time zone as an IANA name ("Asia/Kolkata"), once the SDK has read it — it reads it as it starts, and again before every request, since people travel. Null before then, or when the platform cannot say. The booking sheet shows this zone next to the chosen time.
Parameters — none.
Returns — String?. Example value: 'Asia/Kolkata'.
Errors — none.
GraineBooking
Use it to open the SDK's booking sheet — "Call me at…" with no screen of your own.
abstract final class GraineBooking
What to expect — One static function, show. The sheet books through the agent's scheduleCall, so a booking appears on the chat's Upcoming calls card at once and in scheduledCalls(); Graine rings the customer at the time chosen.
Its functions: show — each with its parameters, what it returns, the errors it raises and an example.
GraineBooking.show
Call it from a "Call me" button to let the customer book a call: it opens the sheet and completes with the booked call.
Opens the SDK's booking sheet over context's navigator, in the agent's design: on a phone (shortest side under 600) a sheet slides up from the bottom, the app dimmed behind it; on a tablet a panel 420 wide fades in at the centre. The customer picks a day and a time, may say what the call is about, and taps Book call; the sheet then says when the agent will call, and Done closes it. A tap outside the sheet closes it too. A refusal stays in the sheet as one line under the button (the table above), and the customer can try again. The sheet loads the agent's settings itself when they have not arrived, and checks the time every 30 seconds while it is open: what was bookable a minute ago may not be. Opened while booking is not available, it says why and books nothing.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
context | BuildContext | required | Where to open it: the sheet goes over this context's navigator. |
app | GraineInApp? | optional | The agent to book with; the default agent when left out. |
reason | String? | optional | Fills "What's it about?" — trimmed and cut to 120 characters; the customer may change it. It is kept with the call for the agent and never put in the push that rings it. |
Returns — Future<GraineScheduledCall?> — once the sheet closes: the booked call (status scheduled) — also when the customer booked and then tapped outside instead of Done — or null when they closed it without booking. Example value: GraineScheduledCall(6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44, 2026-10-14T12:30:00.000Z, scheduled).
Errors — none: every refusal (tooSoon, tooFar, outsideWindow, tooManyPending, schedulingOff, identityRequired, rateLimited, unavailable, network) is shown in the sheet, word for word as listed above. Called before GraineInApp.init, it logs "[Graine] GraineBooking.show before GraineInApp.init: there is no agent to book with." and completes with null without opening.
GraineBookingSheet
Use it to show the booking sheet your own way — on a route, in your own sheet, or in a widget test.
class GraineBookingSheet extends StatefulWidget
What to expect — The same sheet GraineBooking.show opens, as a widget you place yourself: "Book a call", who will call, the day chips, the time (Flutter's showTimePicker), the time zone line, "What's it about? (optional)", Book call — then "Booked — …" and Done. It sizes itself to its content and scrolls when space is short; it keeps clear of the keyboard and, as a sheet, of the home indicator. It does not close itself: onClose (Done, or the close button) is yours to handle.
| Property | Type | Meaning |
|---|---|---|
final GraineInApp? app | GraineInApp? | The agent to book with; the default agent when null. |
final String? reason | String? | Fills "What's it about?" (at most 120 characters); the customer may change it. |
final ValueChanged<GraineScheduledCall>? onBooked | ValueChanged<GraineScheduledCall>? | Called with the booked call, as the sheet switches to "Booked — …". |
final VoidCallback? onClose | VoidCallback? | Called by Done and by the close button; null draws no close button (Done still shows, and does nothing). |
final bool sheet | bool | True (the default): drawn as a sheet — rounded top corners and a grab handle; false: a panel with every corner rounded and an outline. |
final DateTime Function()? now | DateTime Function()? | The clock, for a test; the device's when null. |
static const Key sheetKey | Key | The whole sheet, for a widget test ('graine-booking-sheet'). |
static Key dayKey(String day) | Key | One day chip, by its YYYY-MM-DD date, for a widget test. |
static const Key timeKey | Key | The time field that opens the time picker. |
static const Key zoneKey | Key | The time zone line. |
static const Key aboutKey | Key | The "What's it about?" field. |
static const Key bookKey | Key | The Book call button. |
static const Key lineKey | Key | The refusal line under the button. |
static const Key doneKey | Key | The Done button, once booked. |
static const Key closeKey | Key | The close button (shown when onClose is set). |
Its functions: GraineBookingSheet, dayKey — each with its parameters, what it returns, the errors it raises and an example.
GraineBookingSheet.GraineBookingSheet
Use it to place the booking sheet yourself, instead of GraineBooking.show.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | Key? | optional | The widget's key, as for any Flutter widget. |
app | GraineInApp? | optional | The agent to book with; the default agent when null. |
reason | String? | optional | Fills "What's it about?" (at most 120 characters); the customer may change it. |
onBooked | ValueChanged<GraineScheduledCall>? | optional | Called with the booked call, as the sheet switches to "Booked — …". |
onClose | VoidCallback? | optional | Called by Done and by the close button; null draws no close button (Done still shows, and does nothing). |
sheet | bool | true | True (the default): drawn as a sheet — rounded top corners and a grab handle; false: a panel with every corner rounded and an outline. |
now | DateTime Function()? | optional | The clock, for a test. |
Returns — a new GraineBookingSheet.
Errors — none; refusals are shown in the sheet.
GraineBookingSheet.dayKey
Use it in a widget test to find one day chip of the sheet.
The key of one day chip.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
day | String | required | The day on the device, YYYY-MM-DD (BookingDay.key). |
Returns — Key — ValueKey<String>('graine-booking-day-' + day).
Errors — none.
ChatPieces.book
Read it to decide whether your own chat window shows "Book a call" — as the SDK's chat window does.
True when the chat window offers Book a call: the design keeps the booked-calls card (ThemeChat.showUpcomingCalls) and booking is available here (GraineInApp.bookingAvailable). With calls booked it sits under them in the Upcoming calls card; with none, it is a compact row in the card's place. It never shows when the design hides the booked-calls card. The SDK's chat window opens GraineBooking.show from it.
Parameters — none.
Returns — bool. Example value: true.
Errors — none.
Booking
Use it to build a booking screen of your own with the same rules and words as the SDK's sheet.
abstract final class Booking
What to expect — Pure rules and words, the same on every Graine SDK: nothing here asks Graine anything. Book with GraineInApp.scheduleCall once the customer has chosen.
| Property | Type | Meaning |
|---|---|---|
static const String title | String | The sheet's title: 'Book a call'. |
static const String about | String | The reason field's label: "What's it about? (optional)". |
static const String book | String | The button: 'Book call'. |
static const String done | String | The button once booked: 'Done'. |
static const String web | String | What a website's sheet says, since a browser cannot be rung: "We'll ring you in the app". |
static const int reasonMax | int | The longest reason a booking carries: 120 characters. |
static const int roundMinutes | int | The grid every time is on: 5 minutes — the earliest rounded up to it, the latest down. |
Its functions: subtitle, callName, blocker, available, bounds, clamp, dayLabel, days, onDay, zoneLine, doneLine, errorLine — each with its parameters, what it returns, the errors it raises and an example.
Booking.subtitle
Use it to write the line under the sheet's title.
The line under the title: who will call.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
callName | String | required | Who calls (Booking.callName). |
Returns — String. Example value: 'Asha will call you'.
Errors — none.
Booking.callName
Use it to pick the name the sheet says will call.
The first name that is not empty after trimming, else "Assistant". The sheet passes the agent's call name (Calls & scheduling), the chat's title and the heading, in that order.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
names | List<String?> | required | The candidates, best first; nulls and blanks are skipped. |
Returns — String. Example value: 'Asha'.
Errors — none.
Booking.blocker
Use it to work out why booking is not offered — the same rule as bookingAvailable.
Why booking is not offered, or null when it is — one rule for every SDK. Booking needs all of: the agent lets customers book; Graine can ring this phone (hosted ringing, and platforms empty or naming platform) — a web page cannot be rung, so with platform 'web' it books for the customer's app and needs only the rest; and the customer is identified. The agent's settings are checked first.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
calls | CallsSetting? | required | The session's call settings (session?.calls); null allows nothing. |
platform | String? | required | 'ios', 'android' or 'web'; anything else (or null) is schedulingOff. |
identified | bool | required | The customer is identified with the agent's identity trait. |
Returns — GraineErrorCode? — schedulingOff, identityRequired, or null. Example value: GraineErrorCode.identityRequired.
Errors — none.
Booking.available
Use it to work out whether booking is offered from the agent's call settings, the platform and whether the customer is identified.
True when Booking.blocker says nothing — the rule GraineInApp.bookingAvailable applies.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
calls | CallsSetting? | required | The session's call settings. |
platform | String? | required | 'ios', 'android' or 'web'. |
identified | bool | required | The customer is identified. |
Returns — bool. Example value: false.
Errors — none.
Booking.bounds
Use it to get the earliest and the latest time a booking may take, on the 5-minute grid.
The interval a booking may take at now: now plus the agent's notice, rounded up to 5 minutes, to now plus its horizon in days, rounded down.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
rules | GraineSchedulingRules | required | The agent's rules (GraineInApp.schedulingRules). |
now | DateTime | required | The time now — pass DateTime.now(). |
Returns — BookingBounds. Example value: at 6:02 PM with 5 minutes' notice, earliest is 6:10 PM.
Errors — none.
Booking.clamp
Use it to move any time inside the bounds, on the 5-minute grid.
at moved to the nearest 5-minute mark, then held inside the bounds.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | Any time. |
bounds | BookingBounds | required | From Booking.bounds. |
Returns — DateTime. Example value: 6:12 PM becomes 6:10 PM; a time before earliest becomes earliest.
Errors — none.
Booking.dayLabel
Use it to get a day chip's words: "Today", "Tomorrow" or the weekday and date.
A day chip's words, on the device's clock: "Today", "Tomorrow", else the weekday and date as ChatTime.day writes it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | A time on the day. |
now | DateTime | required | The time now. |
Returns — String. Example value: 'Thu 16 Oct'.
Errors — none.
Booking.days
Use it to get the days to offer, each with its first and last bookable time.
The days to offer, from the day of the earliest time to the day of the latest, each with its first and last bookable time on the 5-minute grid. A day with no time left in it is left out — late in the evening, "Today" may not be offered.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
bounds | BookingBounds | required | From Booking.bounds. |
now | DateTime | required | The time now, for the chips' words. |
Returns — List<BookingDay> — empty when the bounds hold no time at all. Example value: [Today, Tomorrow, Thu 16 Oct, …].
Errors — none.
Booking.onDay
Use it to turn the hour and minute a time picker answered into a bookable time on the chosen day.
The time a picker answered (hour:minute on the device's clock) on day, moved to the nearest 5-minute mark and held between the day's first and last time.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
day | BookingDay | required | The chosen day. |
hour | int | required | 0–23. |
minute | int | required | 0–59. |
Returns — DateTime. Example value: 18:02 on a day that offers until 22:00 becomes 18:00.
Errors — none.
Booking.zoneLine
Use it to write the time zone line under the time.
The line under the time: the zone, then the day and time chosen — or just the day and time when the zone is unknown.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | The time chosen. |
zone | String? | required | The device's zone (GraineInApp.deviceTimezone); null or empty leaves it out. |
h24 | bool | required | true on a device set to the 24-hour clock — MediaQuery.alwaysUse24HourFormatOf(context). |
Returns — String. Example value: 'Asia/Kolkata · Wed 14 Oct, 6:00 PM'.
Errors — none.
Booking.doneLine
Use it to write the sentence the sheet shows once the call is booked.
The sentence once booked — always with the date ("on Wed 14 Oct, 6:00 PM"), never "on Today".
| Parameter | Type | Default | Meaning |
|---|---|---|---|
callName | String | required | Who calls. |
at | DateTime? | required | When the call rings; null leaves the time out. |
h24 | bool | required | true on a device set to the 24-hour clock. |
Returns — String. Example value: 'Booked — Asha will call you on Wed 14 Oct, 6:00 PM'.
Errors — none.
Booking.errorLine
Use it to turn a refusal into the one line the sheet shows under its button.
The one line the sheet shows under Book call for a refusal, in plain words, with the agent's own numbers:
| Code | The line |
|---|---|
tooSoon | Pick a time at least 5 minutes from now (the notice, counted: "1 minute", "5 minutes") |
tooFar | Pick a time within 14 days (the horizon) |
outsideWindow | That time is outside the hours we can call — pick another |
tooManyPending | You already have 3 calls booked — cancel one first (the limit) |
schedulingOff | Booking a call isn't available right now |
identityRequired | Sign in to book a call |
anything else, or null — rateLimited, unavailable, network, unknown | Couldn't book just now — try again |
| Parameter | Type | Default | Meaning |
|---|---|---|---|
code | GraineErrorCode? | required | The refusal's code (GraineException.code). |
rules | GraineSchedulingRules | required | The agent's rules, for the numbers. |
Returns — String. Example value: 'Pick a time at least 5 minutes from now'.
Errors — none.
BookingBounds
Read it as the earliest and the latest time a booking may take right now.
final class BookingBounds
What to expect — Both ends on the 5-minute grid. Computed for one moment: compute them again as time passes (the SDK's sheet does every 30 seconds).
| Property | Type | Meaning |
|---|---|---|
final DateTime earliest | DateTime | Now plus the agent's notice (minLeadMinutes), rounded up to 5 minutes. |
final DateTime latest | DateTime | Now plus the agent's horizon (maxDaysAhead days), rounded down to 5 minutes. |
Its functions: BookingBounds — each with its parameters, what it returns, the errors it raises and an example.
BookingBounds.BookingBounds
Use it to build bounds by hand for a test; Booking.bounds gives the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
earliest | DateTime | required | Now plus the agent's notice (minLeadMinutes), rounded up to 5 minutes. |
latest | DateTime | required | Now plus the agent's horizon (maxDaysAhead days), rounded down to 5 minutes. |
Returns — a new BookingBounds.
Errors — none.
BookingDay
Read it to draw one day chip: its words and the first and last time it offers.
final class BookingDay
What to expect — One chip of the sheet's day row, in order from the first bookable day. first and last are on the 5-minute grid and inside the bounds; on the first day first is the earliest bookable time, on the last day last is the latest.
| Property | Type | Meaning |
|---|---|---|
final String key | String | The day on the device, YYYY-MM-DD — the chip's key (GraineBookingSheet.dayKey). |
final String label | String | The chip's words: "Today", "Tomorrow", then the weekday and date ("Thu 16 Oct"). |
final DateTime first | DateTime | The first time the day offers. |
final DateTime last | DateTime | The last time the day offers. |
Its functions: BookingDay — each with its parameters, what it returns, the errors it raises and an example.
BookingDay.BookingDay
Use it to build a day by hand for a test; Booking.days gives the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
key | String | required | The day on the device, YYYY-MM-DD — the chip's key (GraineBookingSheet.dayKey). |
label | String | required | The chip's words: "Today", "Tomorrow", then the weekday and date ("Thu 16 Oct"). |
first | DateTime | required | The first time the day offers. |
last | DateTime | required | The last time the day offers. |
Returns — a new BookingDay.
Errors — none.
The scheduled-calls list
Book a call from your own screen, list the customer's booked calls and cancel one. Bookings are checked on the device first against the agent's rules (schedulingRules), then by Graine — the calling hours, and how many calls each customer may have waiting. The SDK's chat window shows the booked calls in its Upcoming calls card, with Cancel; GraineInApp.instance.chat exposes the same list for a chat of your own.
GraineInApp.schedulingRules
Read it to know what the agent lets customers book — whether at all, how soon, how far ahead and how many — before you offer times.
What the agent lets customers book, and how Graine rings — from the agent's settings, with no request. Before the settings load, and from an agent that says nothing, the defaults, which allow no booking. earliest(now) and latest(now) bound a booking; scheduleCall checks them before it asks Graine.
Parameters — none.
Returns — GraineSchedulingRules — its fields: GraineSchedulingRules. Example value: usersCanBook: true, minLeadMinutes: 5, maxDaysAhead: 14, maxPendingPerUser: 3.
Errors — none.
GraineInApp.scheduleCall
Call it from your own booking screen to book a call from the agent at a time the customer chose.
Books a call from the agent at at ("call me tomorrow at 6"). The agent rings this user's devices (with nobody identified, this install) through the app. reason is trimmed, at most 120 characters, kept with the call for the agent, and never put in the push that rings it. Checks made on the device before the booking request is sent: a reason over 120 characters (invalidRequest, checked first); then, once the agent's configuration has loaded, schedulingOff when users may not book, tooSoon before schedulingRules.earliest(now) and tooFar after schedulingRules.latest(now), where now is the device clock. Those three say the booking sheet's words as their message — "Booking a call isn't available right now", "Pick a time at least 5 minutes from now", "Pick a time within 14 days" (the agent's notice and horizon, counted: "1 minute" for one) — the same on every SDK and the website. The time is sent as ISO-8601 with the device's offset. An open chat's Upcoming calls card shows the booking at once.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | When the call should ring: a moment in time. It is sent with the device's offset and time zone; it must fall between schedulingRules.earliest(now) and latest(now). |
reason | String? | optional | What the call is about, at most 120 characters — the agent hears it as call_reason when it rings. |
Returns — Future<GraineScheduledCall> — the booked call, status scheduled.
Errors — GraineException — on the device: invalidRequest, schedulingOff, tooSoon, tooFar; from Graine: outsideWindow, tooManyPending, identityRequired, deviceLimit, invalidRequest, rateLimited, unavailable, invalidKey, originRefused, network; unknown (codeName "bad_response") when the booking is not confirmed
GraineInApp.scheduledCalls
Call it to list the customer's booked calls, upcoming first — for a screen of your own.
This user's calls (with nobody identified, this install's), in Graine's order: upcoming first. Entries that are not calls are skipped.
Parameters — none.
Returns — Future<List<GraineScheduledCall>> — its fields: GraineScheduledCall. Example value: [GraineScheduledCall(id: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44', at: 2026-10-15 12:30:00.000Z, status: GraineCallStatus.scheduled, source: GraineCallSource.app, reason: 'follow_up')].
Errors — GraineException: rateLimited, unavailable, invalidKey, originRefused, network, notFound (a server with no booked calls to list), unknown
GraineInApp.cancelScheduledCall
Call it when the customer cancels a booked call from your own screen.
Cancels one of this user's booked calls. The id is trimmed. Completes with the status Graine reports afterwards — GraineCallStatus.cancelled when it does not say. An open chat's Upcoming calls card drops the call.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The booking's ID (a UUID), from GraineScheduledCall.id. |
Returns — Future<GraineCallStatus> — the call's status afterwards. Example value: GraineCallStatus.cancelled.
Errors — GraineException: invalidRequest (an empty id, on the device), notFound (not this user's or install's), rateLimited, unavailable, invalidKey, originRefused, network, unknown
GraineChatSession.refreshUpcoming
Call it to read the customer's booked calls again now — after your own screen booked or cancelled one.
Read the booked calls again now.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineChatSession.cancelUpcoming
Call it from your own chat's Upcoming calls card when the customer taps Cancel.
Runs the card's Cancel. The row reads "Cancelling…" until Graine replies and then disappears; if it fails, the row shows the failure and tapping it retries.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The booking's ID, from the chat's upcoming calls. |
Returns — nothing; it returns when done.
Errors — none.
GraineChatSession.cancelStateOf
Use it to draw a booked call's Cancel: not asked, cancelling, or failed.
Where a booked call's Cancel is.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The booked call's id (GraineScheduledCall.id). |
Returns — GraineUpcomingCancel — its fields: GraineUpcomingCancel. Example value: GraineUpcomingCancel.none.
Errors — none.
GraineUpcomingCancel
Read it to draw a booked call's Cancel on your own Upcoming calls card.
enum GraineUpcomingCancel
What to expect — Give every switch over it a default case.
| Case | Meaning |
|---|---|
none | Not asked. |
cancelling | The cancellation has been requested, and the row shows "Cancelling…" until Graine replies. |
failed | The cancellation did not go through, and the row reads "Couldn’t cancel · tap to retry". |
GraineScheduledCall
Read it to show one booked call: when it rings, what it is about, where it stands, and whether it can still be cancelled.
class GraineScheduledCall
What to expect — From scheduleCall (status scheduled), scheduledCalls() (upcoming first) and the chat's upcoming calls. id is a UUID. at is a moment (null only when Graine's time could not be read): show it in the device's time zone. reason is at most 120 characters, or null. isUpcoming is scheduled or ringing; canCancel is scheduled only. A status or source newer than the SDK arrives as unknown, carrying its word.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The id Graine gave the booking; a GraineScheduledCall is cancelled by this id. |
final DateTime? at | DateTime? | The UTC time the call rings (use .toLocal() for the user's clock); it is null only if the server's time could not be read. |
final GraineCallStatus status | GraineCallStatus | Where the booked call stands: scheduled until it rings, then ringing, answered, completed — or why it did not happen. A status newer than this SDK is unknown (see statusName). |
final String statusName | String | The server's own word for the status; when the status is GraineCallStatus.unknown, this holds the word this build does not recognise. |
final GraineCallSource? source | GraineCallSource? | Who made the booking, or null if the server leaves it out. |
final String? sourceName | String? | The server's own word for the source (sdk, agent, …), or null. |
final String? reason | String? | What it is about, as booked. |
bool get isUpcoming | bool | Still to come: scheduled or ringing. |
bool get canCancel | bool | It can still be called off: scheduled. |
String get statusWire | String | The status as one word — statusName if the server sent one, otherwise the word for status. |
Its functions: GraineScheduledCall, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
GraineScheduledCall.GraineScheduledCall
Use it to build a booked call by hand for a preview or a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The id Graine gave the booking; a GraineScheduledCall is cancelled by this id. |
at | DateTime? | optional | The UTC time the call rings (use .toLocal() for the user's clock); it is null only if the server's time could not be read. |
status | GraineCallStatus | GraineCallStatus.scheduled | Where the booked call stands: scheduled until it rings, then ringing, answered, completed — or why it did not happen. A status newer than this SDK is unknown (see statusName). |
statusName | String? | optional | The server's own word for the status; when the status is GraineCallStatus.unknown, this holds the word this build does not recognise. |
source | GraineCallSource? | optional | Who made the booking, or null if the server leaves it out. |
sourceName | String? | optional | The server's own word for the source (sdk, agent, …), or null. |
reason | String? | optional | What it is about, as booked. |
Returns — a new GraineScheduledCall.
Errors — none.
GraineScheduledCall.fromJson
Use it to read a booked call from JSON you stored.
Returns null unless the input is a call that has an id.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The booked call as Graine sent it; anything without an id reads as null. |
Returns — GraineScheduledCall?. Example value: GraineScheduledCall(id: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44', at: 2026-10-15 12:30:00.000Z, status: GraineCallStatus.scheduled, source: GraineCallSource.app, reason: 'follow_up').
Errors — none.
GraineScheduledCall.toJson
Use it to turn a booked call into JSON — to cache it or send it to your own server.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
GraineCallStatus
Read it to show where a booked call stands, from scheduled to completed — or why it never rang.
enum GraineCallStatus
What to expect — scheduled → ringing → answered → completed; or declined (nothing rings that customer again for 6 hours), missed (rang out), failed, cancelled (called off before it rang), expired (its time passed while it could not ring: more than 10 minutes late, or no opening left in the calling hours), no_device (no device of the customer's seen in the last 30 days — a browser cannot ring). A status newer than this SDK arrives as unknown, carrying its word: give every switch a default.
| Case | Meaning |
|---|---|
scheduled('scheduled') | Booked, waiting for its time. |
ringing('ringing') | The device is ringing now. |
answered('answered') | The customer answered the ring; the conversation is under way. |
completed('completed') | The call took place and is over. |
declined('declined') | The customer declined the ring. Nothing rings them again for 6 hours. |
missed('missed') | Rang out with no answer. |
failed('failed') | The call could not be placed or connected. |
cancelled('cancelled') | Called off before it rang — by the customer, your app or the agent. |
expired('expired') | The booked time went by without the call being able to ring, either because it fell outside the calling hours or because it was held too long. |
noDevice('no_device') | No device of the user's could be rung. |
unknown('unknown') | A status that this build does not recognise; the call's statusName holds the actual word. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The word on the wire. |
bool get upcoming | bool | Still to come: it will ring, or is ringing. |
Its functions: GraineCallStatus, fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineCallStatus.GraineCallStatus
The enum's constructor; use the values (GraineCallStatus.scheduled, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The word on the wire. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
GraineCallStatus.fromWire
Use it to read a booked call's status from its word.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | Object? | required | The status's word, as Graine sent it; anything this build does not know reads as unknown. |
Returns — GraineCallStatus. Example value: GraineCallStatus.scheduled.
Errors — none.
GraineCallSource
Read it to show who booked a call: the agent, your app, your team in the dashboard, or your server.
enum GraineCallSource
What to expect — Who booked it: the agent in a conversation, your app (the word Graine sends is sdk), your team in the dashboard, or the API. A source newer than this SDK arrives as unknown, carrying its word.
| Case | Meaning |
|---|---|
agent('agent') | The agent, in a conversation. |
app('sdk') | The app, through this SDK. |
dashboard('dashboard') | Your team booked it in the dashboard. |
api('api') | Your own server booked it through Graine's API. |
unknown('unknown') | A source that this build does not recognise; the call's sourceName holds the actual word. |
| Property | Type | Meaning |
|---|---|---|
final String wire | String | The word on the wire. |
Its functions: GraineCallSource, fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineCallSource.GraineCallSource
The enum's constructor; use the values (GraineCallSource.app, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wire | String | required | The word on the wire. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire.
Errors — none.
GraineCallSource.fromWire
Use it to read who booked a call from its word.
Null for no source at all.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | Object? | required | The source's word (sdk is app); empty reads as null, anything unknown as unknown. |
Returns — GraineCallSource?. Example value: GraineCallSource.agent.
Errors — none.
GraineSchedulingRules
Read it to offer only times the agent allows, and to check a time before you book it.
class GraineSchedulingRules
What to expect — A property: no request. Read from the agent's settings when the session loads; before that the defaults hold, with booking off (iOS and Android use the last rules kept on the device). scheduleCall refuses on the device first — scheduling_off, too_soon (before earliest(now) or not in the future), too_far (after latest(now)) — with status 0; Graine then checks the calling hours and the calls already waiting. ringTimeoutSeconds is 20–60 (45 by default): every SDK holds a value outside that range to it.
| Property | Type | Meaning |
|---|---|---|
final bool usersCanBook | bool | scheduleCall is allowed at all. |
final int minLeadMinutes | int | The least notice a booking needs, in minutes (default 5; the dashboard allows 2–1440). earliest(now) is now plus this. |
final int maxDaysAhead | int | How far ahead a booking may be, in days (default 14; the dashboard allows 1–30). latest(now) is now plus this. |
final int maxPendingPerUser | int | How many booked calls one customer may have waiting at once (default 3; 1–10). One more is refused with tooManyPending. |
final int ringTimeoutSeconds | int | How long a ring lasts before it is missed. |
final String? callName | String? | The name the phone displays for the agent's calls; when null, the agent's name is shown. |
final bool hostedRinging | bool | True when Graine rings the devices of the workspace's users. |
final List<String> platforms | List<String> | Where it rings: ios, android. |
Its functions: GraineSchedulingRules, of, earliest, latest — each with its parameters, what it returns, the errors it raises and an example.
GraineSchedulingRules.GraineSchedulingRules
Use it to build rules by hand for a test or a preview; schedulingRules gives the agent's.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
usersCanBook | bool | false | scheduleCall is allowed at all. |
minLeadMinutes | int | 5 | The least notice a booking needs, in minutes (default 5; the dashboard allows 2–1440). earliest(now) is now plus this. |
maxDaysAhead | int | 14 | How far ahead a booking may be, in days (default 14; the dashboard allows 1–30). latest(now) is now plus this. |
maxPendingPerUser | int | 3 | How many booked calls one customer may have waiting at once (default 3; 1–10). One more is refused with tooManyPending. |
ringTimeoutSeconds | int | 45 | How long a ring lasts before it is missed. |
callName | String? | optional | The name the phone displays for the agent's calls; when null, the agent's name is shown. |
hostedRinging | bool | false | True when Graine rings the devices of the workspace's users. |
platforms | List<String> | const <String>[] | Where it rings: ios, android. |
Returns — a new GraineSchedulingRules.
Errors — none.
GraineSchedulingRules.of
Use it to read the rules from the session's call settings.
The rules in calls, the session's call settings; null (settings that say nothing) allows no booking.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
calls | CallsSetting? | required | The session's call settings (session?.calls); null, from an agent that says nothing, allows no booking. |
Returns — GraineSchedulingRules — the defaults (no booking) for anything the settings leave out.
Errors — none.
GraineSchedulingRules.earliest
Use it to get the soonest time a call can be booked for.
The soonest a call can be booked for: now plus minLeadMinutes.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | DateTime | required | The time now — pass DateTime.now(). |
Returns — DateTime.
Errors — none.
GraineSchedulingRules.latest
Use it to get the latest time a call can be booked for.
The latest a call can be booked for: now plus maxDaysAhead days.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | DateTime | required | The time now — pass DateTime.now(). |
Returns — DateTime.
Errors — none.
SchedulingSetting
Read it as what the dashboard lets customers book (Agent → Calls & scheduling).
class SchedulingSetting
What to expect — A property: no request. Read from the agent's settings when the session loads; before that the defaults hold, with booking off (iOS and Android use the last rules kept on the device). scheduleCall refuses on the device first — scheduling_off, too_soon (before earliest(now) or not in the future), too_far (after latest(now)) — with status 0; Graine then checks the calling hours and the calls already waiting. ringTimeoutSeconds is 20–60 (45 by default): every SDK holds a value outside that range to it.
| Property | Type | Meaning |
|---|---|---|
final bool usersCanBook | bool | scheduleCall is allowed at all. |
final int maxDaysAhead | int | How far ahead a booking may be, in days (default 14; read within 1–30). |
final int minLeadMinutes | int | The least notice a booking needs, in minutes (default 5; read within 2–1440). |
final int maxPendingPerUser | int | How many booked calls one customer may have waiting (default 3; read within 1–10). |
Its functions: SchedulingSetting, fromJson — each with its parameters, what it returns, the errors it raises and an example.
SchedulingSetting.SchedulingSetting
Use it to build the booking setting by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
usersCanBook | bool | false | scheduleCall is allowed at all. |
maxDaysAhead | int | 14 | How far ahead a booking may be, in days (default 14; read within 1–30). |
minLeadMinutes | int | 5 | The least notice a booking needs, in minutes (default 5; read within 2–1440). |
maxPendingPerUser | int | 3 | How many booked calls one customer may have waiting (default 3; read within 1–10). |
Returns — a new SchedulingSetting.
Errors — none.
SchedulingSetting.fromJson
Use it to read the booking setting from the session's JSON.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The value as decoded from JSON; anything that is not the expected object reads as null. |
Returns — SchedulingSetting?. Example value: null.
Errors — none.
Design
The design the brand chose in the Garage (Embed & Widgets → Appearance), resolved into light and dark tokens and carried by the session: colours, type, shapes, spacing, depth, motion, icons, the chat window and the call screen. The SDK's own views draw from it; read GraineInApp.instance.tokens to draw your own UI in the same design. A token that is missing or malformed draws as Graine Classic; a design that is not one at all leaves every surface on the dashboard's Appearance.
GraineInApp.loadDesignFonts
Call it to fetch a design's typefaces ahead of time — the SDK already does it when the session arrives.
Fetches and registers the faces design draws with. For the session's design the SDK takes care of this on its own; call it yourself for a design you pass straight to a widget. Any family named in GraineConfig.fonts belongs to the app, so it is never downloaded. Calling it more than once is safe, since no face is fetched twice.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
design | ResolvedDesign? | required | The design whose typefaces to fetch — usually GraineInApp.instance.design; null does nothing. |
Returns — nothing; it returns when done.
Errors — none.
ResolvedDesign
Read it as the brand's design with both its light and dark tokens — and pick the set to draw with.
class ResolvedDesign
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final Map<String, Object?> config | Map<String, Object?> | The brand's choices as the dashboard saved them. Only scheme is read; the rest is already applied to the tokens. |
final ThemeTokens light | ThemeTokens | The tokens to draw in light mode. |
final ThemeTokens dark | ThemeTokens | The tokens to draw in dark mode. |
String get scheme | String | Either "light" or "dark" if the brand set a fixed scheme, or "auto" (follow the device) if not. |
Its functions: ResolvedDesign, pick, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ResolvedDesign.ResolvedDesign
Use it to build a design by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
config | Map<String, Object?> | required | The brand's choices as the dashboard saved them. Only scheme is read; the rest is already applied to the tokens. |
light | ThemeTokens | required | The tokens to draw in light mode. |
dark | ThemeTokens | required | The tokens to draw in dark mode. |
Returns — a new ResolvedDesign.
Errors — none.
ResolvedDesign.pick
Use it to choose the token set to draw with: the brand's fixed scheme, else the device's light or dark.
Which set to draw.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
deviceDark | bool? | optional | Whether the device is in dark mode — MediaQuery.platformBrightnessOf(context) == Brightness.dark; null when unknown, read as light. |
scheme | String? | optional | Your own choice — light, dark or auto — over the brand's; the brand's when left out. |
Returns — ThemeTokens — its fields: ThemeTokens.
Errors — none.
ResolvedDesign.fromJson
Use it to read a design from the session's JSON.
Returns null for input that is not a design. An older server sends no design, and the SDK then keeps drawing from appearance as it used to.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The session's design, as decoded; anything that is not a design reads as null. |
Returns — ResolvedDesign?. Example value: null.
Errors — none.
ResolvedDesign.toJson
Use it to turn a design back into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeTokens
Use it to draw your own UI in the agent's design: everything a surface needs for one scheme, light or dark.
class ThemeTokens
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final int v | int | The tokens' format version (1). |
final String preset | String | The design the brand started from, by name. |
final String scheme | String | "light" or "dark". |
final ThemeColors colors | ThemeColors | Every colour a surface uses. |
final ThemeFont font | ThemeFont | Families, sizes, weights and spacing. |
final ThemeShape shape | ThemeShape | Corner radii, outline width and the launcher's shape. |
final ThemeSpacing spacing | ThemeSpacing | The base step, card padding and gaps. |
final ThemeElevation elevation | ThemeElevation | Shadows, or a solid offset. |
final ThemeMotion motion | ThemeMotion | How long transitions take and how they ease. |
final ThemeIcons icons | ThemeIcons | The icons' style and stroke, and the launcher's glyph. |
final ThemeGlass? glass | ThemeGlass? | Null: opaque surfaces. |
final String bubbles | String | One of Design.bubbleStyles. |
final String chrome | String | A value from Design.chromes. With "window", the chat window, the caption card and each component card open as desktop windows (the measurements are in WindowChrome); "none", which is also what an older server that never sends it means, gives a plain surface. |
final ThemeChat? servedChat | ThemeChat? | The chat window's tokens, unchanged from the session; null when the server is older than these tokens. |
final ThemeCall? servedCall | ThemeCall? | The call screen's tokens, unchanged from the session; null when the server is older than these tokens. |
bool get dark | bool | True for the dark set. |
bool get window | bool | True if the design's chrome is "window", so its surfaces open as desktop windows. |
ThemeChat get chat | ThemeChat | The tokens for the chat window: the session's when present, otherwise ones that reproduce the window as it looked before these tokens existed. |
ThemeCall get call | ThemeCall | The tokens for the call screen: the session's when present, otherwise the fixed dark screen. |
Its functions: ThemeTokens, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeTokens.ThemeTokens
Use it to build a token set by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
v | int | 1 | The tokens' format version (1). |
preset | String | required | The design the brand started from, by name. |
scheme | String | required | "light" or "dark". |
colors | ThemeColors | required | Every colour a surface uses. |
font | ThemeFont | required | Families, sizes, weights and spacing. |
shape | ThemeShape | required | Corner radii, outline width and the launcher's shape. |
spacing | ThemeSpacing | required | The base step, card padding and gaps. |
elevation | ThemeElevation | required | Shadows, or a solid offset. |
motion | ThemeMotion | required | How long transitions take and how they ease. |
icons | ThemeIcons | required | The icons' style and stroke, and the launcher's glyph. |
glass | ThemeGlass? | optional | Null: opaque surfaces. |
bubbles | String | required | One of Design.bubbleStyles. |
chrome | String | 'none' | A value from Design.chromes. With "window", the chat window, the caption card and each component card open as desktop windows (the measurements are in WindowChrome); "none", which is also what an older server that never sends it means, gives a plain surface. |
servedChat | ThemeChat? | optional | The chat window's tokens, unchanged from the session; null when the server is older than these tokens. |
servedCall | ThemeCall? | optional | The call screen's tokens, unchanged from the session; null when the server is older than these tokens. |
Returns — a new ThemeTokens.
Errors — none.
ThemeTokens.fromJson
Use it to read a token set from the design's JSON — the SDK does this when the session arrives.
One scheme's tokens. scheme names the slot the tokens came in, and applies when the tokens themselves do not specify one. Returns null if raw is not an object containing a colors object, since that is too little to count as a design.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | One scheme's tokens as decoded; null without a colors object. |
scheme | String | 'light' | The slot the tokens arrived in, light or dark, used when the tokens do not say. |
Returns — ThemeTokens?. Example value: null.
Errors — none.
ThemeTokens.toJson
Use it to turn a token set back into the design's JSON — to store it or compare it.
Writes the tokens back in the session's form, matching what fromJson read key by key.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeColors
Use it to colour your own UI like the agent's: every colour a surface uses.
class ThemeColors
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String background | String | Behind everything in the chat window. |
final String surface | String | The voice bar, the chat header, sheets. |
final String surfaceRaised | String | Cards, the composer field. |
final String text | String | The main text colour. |
final String textMuted | String | Secondary text: captions, status lines. |
final String border | String | Hairlines and outlines. |
final String accent | String | Applied to primary buttons, as well as the launcher and the send button. |
final String onAccent | String | What sits on accent. |
final String accentSoft | String | A faint version of the accent, for chips, selected rows and the focus halo. |
final String success | String | Good news: "Online", a done state. |
final String warning | String | Caution: a weak connection, a booking about to lapse. |
final String danger | String | The end-call button. |
final String userBubble | String | The customer's chat bubbles. |
final String userBubbleText | String | Text on the customer's bubbles. |
final String agentBubble | String | The agent's chat bubbles. |
final String agentBubbleText | String | Text on the agent's bubbles. |
final String scrim | String | Behind a modal sheet, at 40% opacity. |
Its functions: ThemeColors, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeColors.ThemeColors
Use it to build a colour set by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
background | String | required | Behind everything in the chat window. |
surface | String | required | The voice bar, the chat header, sheets. |
surfaceRaised | String | required | Cards, the composer field. |
text | String | required | The main text colour. |
textMuted | String | required | Secondary text: captions, status lines. |
border | String | required | Hairlines and outlines. |
accent | String | required | Applied to primary buttons, as well as the launcher and the send button. |
onAccent | String | required | What sits on accent. |
accentSoft | String | required | A faint version of the accent, for chips, selected rows and the focus halo. |
success | String | required | Good news: "Online", a done state. |
warning | String | required | Caution: a weak connection, a booking about to lapse. |
danger | String | required | The end-call button. |
userBubble | String | required | The customer's chat bubbles. |
userBubbleText | String | required | Text on the customer's bubbles. |
agentBubble | String | required | The agent's chat bubbles. |
agentBubbleText | String | required | Text on the agent's bubbles. |
scrim | String | required | Behind a modal sheet, at 40% opacity. |
Returns — a new ThemeColors.
Errors — none.
ThemeColors.fromJson
Use it to read a colour set from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
r | Map<String, Object?> | required | The JSON object to read. |
d | ThemeColors | required | The colours to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeColors.
Errors — none.
ThemeColors.toJson
Use it to turn a colour set back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeFont
Use it to set your own text like the agent's: families, sizes, weights and spacing.
class ThemeFont
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String body | String | Either "system", meaning the platform's UI font, or a family from the dashboard's list; the SDK downloads that family's faces on its own (see DesignFonts). |
final String heading | String | The titles' family: "system" or a family from the dashboard's list. |
final ThemeFontScale scale | ThemeFontScale | The sizes: caption, body, title, display. |
final ThemeFontWeights weights | ThemeFontWeights | The weights: body, strong, title. |
final ThemeFontPair letterSpacing | ThemeFontPair | In em: multiply by the size. |
final ThemeFontPair lineHeight | ThemeFontPair | Line height as a multiple of the size, for body and titles. |
Its functions: ThemeFont, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeFont.ThemeFont
Use it to build a type set by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | String | required | Either "system", meaning the platform's UI font, or a family from the dashboard's list; the SDK downloads that family's faces on its own (see DesignFonts). |
heading | String | required | The titles' family: "system" or a family from the dashboard's list. |
scale | ThemeFontScale | required | The sizes: caption, body, title, display. |
weights | ThemeFontWeights | required | The weights: body, strong, title. |
letterSpacing | ThemeFontPair | required | In em: multiply by the size. |
lineHeight | ThemeFontPair | required | Line height as a multiple of the size, for body and titles. |
Returns — a new ThemeFont.
Errors — none.
ThemeFont.fromJson
Use it to read a type set from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The type as decoded. |
d | ThemeFont | required | The type to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeFont.
Errors — none.
ThemeFont.toJson
Use it to turn a type set back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeFontScale
Use it to size your text like the agent's.
class ThemeFontScale
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double caption | double | The smallest size — timestamps, captions — in logical pixels. |
final double body | double | Body text, in logical pixels. |
final double title | double | Titles and headers, in logical pixels. |
final double display | double | The largest size — a call screen's name — in logical pixels. |
Its functions: ThemeFontScale, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeFontScale.ThemeFontScale
Use it to build a size scale by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
caption | double | required | The smallest size — timestamps, captions — in logical pixels. |
body | double | required | Body text, in logical pixels. |
title | double | required | Titles and headers, in logical pixels. |
display | double | required | The largest size — a call screen's name — in logical pixels. |
Returns — a new ThemeFontScale.
Errors — none.
ThemeFontScale.fromJson
Use it to read a size scale from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The sizes as decoded. |
d | ThemeFontScale | required | The sizes to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeFontScale.
Errors — none.
ThemeFontScale.toJson
Use it to turn a size scale back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeFontWeights
Use it to weight your text like the agent's.
class ThemeFontWeights
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final int body | int | Body text's weight, 100–900. |
final int strong | int | Emphasis's weight, 100–900. |
final int title | int | Titles' weight, 100–900. |
Its functions: ThemeFontWeights, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeFontWeights.ThemeFontWeights
Use it to build a weight set by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | int | required | Body text's weight, 100–900. |
strong | int | required | Emphasis's weight, 100–900. |
title | int | required | Titles' weight, 100–900. |
Returns — a new ThemeFontWeights.
Errors — none.
ThemeFontWeights.fromJson
Use it to read a weight set from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The weights as decoded. |
d | ThemeFontWeights | required | The weights to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeFontWeights.
Errors — none.
ThemeFontWeights.toJson
Use it to turn a weight set back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeFontPair
Use it to space your text like the agent's — letter spacing and line height, for body and titles.
class ThemeFontPair
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double body | double | The value for body text. |
final double title | double | The value for titles. |
Its functions: ThemeFontPair, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeFontPair.ThemeFontPair
Use it to build a body-and-title pair by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | double | required | The value for body text. |
title | double | required | The value for titles. |
Returns — a new ThemeFontPair.
Errors — none.
ThemeFontPair.fromJson
Use it to read a body-and-title pair from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The pair as decoded. |
d | ThemeFontPair | required | The values to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
min | double? | optional | The least value allowed; none when left out. |
Returns — ThemeFontPair.
Errors — none.
ThemeFontPair.toJson
Use it to turn a body-and-title pair back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeShape
Use it to shape your UI like the agent's: corner radii, outlines and the launcher's shape.
class ThemeShape
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final ThemeRadius radius | ThemeRadius | The four corner radii. |
final double borderWidth | double | The width of every outline. |
final String launcher | String | One of Design.launcherShapes. |
Its functions: ThemeShape, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeShape.ThemeShape
Use it to build a shape set by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
radius | ThemeRadius | required | The four corner radii. |
borderWidth | double | required | The width of every outline. |
launcher | String | required | One of Design.launcherShapes. |
Returns — a new ThemeShape.
Errors — none.
ThemeShape.fromJson
Use it to read a shape set from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The shape as decoded. |
d | ThemeShape | required | The shape to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeShape.
Errors — none.
ThemeShape.toJson
Use it to turn a shape set back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeRadius
Use it to round your corners like the agent's.
class ThemeRadius
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double sm | double | The smallest corner radius — chips, small buttons — in logical pixels. |
final double md | double | The middle radius — inputs, cards inside cards. |
final double lg | double | The large radius — cards and sheets. |
final double xl | double | The largest radius — the bar, the chat window, the booking sheet. |
Its functions: ThemeRadius, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeRadius.ThemeRadius
Use it to build a radius scale by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
sm | double | required | The smallest corner radius — chips, small buttons — in logical pixels. |
md | double | required | The middle radius — inputs, cards inside cards. |
lg | double | required | The large radius — cards and sheets. |
xl | double | required | The largest radius — the bar, the chat window, the booking sheet. |
Returns — a new ThemeRadius.
Errors — none.
ThemeRadius.fromJson
Use it to read a radius scale from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The radii as decoded. |
d | ThemeRadius | required | The radii to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeRadius.
Errors — none.
ThemeRadius.toJson
Use it to turn a radius scale back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeSpacing
Use it to space your UI like the agent's.
class ThemeSpacing
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double unit | double | The base spacing step, in logical pixels — every gap is a multiple of it. |
final double cardPadding | double | Padding inside cards, in logical pixels. |
final double gap | double | Between items. |
Its functions: ThemeSpacing, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeSpacing.ThemeSpacing
Use it to build a spacing set by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
unit | double | required | The base spacing step, in logical pixels — every gap is a multiple of it. |
cardPadding | double | required | Padding inside cards, in logical pixels. |
gap | double | required | Between items. |
Returns — a new ThemeSpacing.
Errors — none.
ThemeSpacing.fromJson
Use it to read a spacing set from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The spacing as decoded. |
d | ThemeSpacing | required | The spacing to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeSpacing.
Errors — none.
ThemeSpacing.toJson
Use it to turn a spacing set back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeElevation
Use it to give your UI the agent's depth: shadows, or a solid offset.
class ThemeElevation
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final ThemeShadow? card | ThemeShadow? | The shadow under cards; null for none. |
final ThemeShadow? floating | ThemeShadow? | The shadow under floating surfaces — the bar, sheets; null for none. |
final ThemeOffset? hardOffset | ThemeOffset? | A solid offset shadow drawn in the text colour; when set it replaces both shadows. |
Its functions: ThemeElevation, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeElevation.ThemeElevation
Use it to build an elevation by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
card | ThemeShadow? | optional | The shadow under cards; null for none. |
floating | ThemeShadow? | optional | The shadow under floating surfaces — the bar, sheets; null for none. |
hardOffset | ThemeOffset? | optional | A solid offset shadow drawn in the text colour; when set it replaces both shadows. |
Returns — a new ThemeElevation.
Errors — none.
ThemeElevation.fromJson
Use it to read an elevation from the design's JSON — the SDK does this when the session arrives.
A missing key takes the fallback's value; a key that is there, even if null, is taken from the design.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The elevation as decoded; a key that is present — null included — is the design's word. |
d | ThemeElevation | required | The elevation to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeElevation.
Errors — none.
ThemeElevation.toJson
Use it to turn an elevation back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeShadow
Use it to draw one of the design's shadows.
class ThemeShadow
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double y | double | How far down the shadow falls, in logical pixels. |
final double blur | double | How soft it is: the blur radius, in logical pixels (0 or more). |
final double spread | double | How far it grows beyond the surface, in logical pixels. |
final double opacity | double | 0–1, applied to color. |
final String color | String | The shadow's colour, #RRGGBB; opacity applies to it. |
Its functions: ThemeShadow, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeShadow.ThemeShadow
Use it to build a shadow by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
y | double | required | How far down the shadow falls, in logical pixels. |
blur | double | required | How soft it is: the blur radius, in logical pixels (0 or more). |
spread | double | required | How far it grows beyond the surface, in logical pixels. |
opacity | double | required | 0–1, applied to color. |
color | String | required | The shadow's colour, #RRGGBB; opacity applies to it. |
Returns — a new ThemeShadow.
Errors — none.
ThemeShadow.fromJson
Use it to read a shadow from the design's JSON — the SDK does this when the session arrives.
Returns null when given null (meaning no shadow) and when given anything that is not a shadow.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | One shadow as decoded; null for none. |
Returns — ThemeShadow?. Example value: null.
Errors — none.
ThemeShadow.toJson
Use it to turn a shadow back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeOffset
Use it to draw the design's solid offset shadow.
class ThemeOffset
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double x | double | How far right the solid shadow sits, in logical pixels. |
final double y | double | How far down the solid shadow sits, in logical pixels. |
Its functions: ThemeOffset, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeOffset.ThemeOffset
Use it to build an offset shadow by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
x | double | required | How far right the solid shadow sits, in logical pixels. |
y | double | required | How far down the solid shadow sits, in logical pixels. |
Returns — a new ThemeOffset.
Errors — none.
ThemeOffset.fromJson
Use it to read an offset shadow from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The offset as decoded; null for none. |
Returns — ThemeOffset?. Example value: null.
Errors — none.
ThemeOffset.toJson
Use it to turn an offset shadow back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeMotion
Use it to animate your UI at the design's pace.
class ThemeMotion
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final int durationMs | int | 0 means no transitions at all. |
final String easing | String | One of Design.easings. |
final double bounce | double | How far a spring goes past its target, from 0 (no overshoot) upward. |
bool get none | bool | True when there is no transition: the duration is zero, or the easing is none. |
Its functions: ThemeMotion, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeMotion.ThemeMotion
Use it to build a motion setting by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
durationMs | int | required | 0 means no transitions at all. |
easing | String | required | One of Design.easings. |
bounce | double | required | How far a spring goes past its target, from 0 (no overshoot) upward. |
Returns — a new ThemeMotion.
Errors — none.
ThemeMotion.fromJson
Use it to read a motion setting from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The motion as decoded. |
d | ThemeMotion | required | The motion to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeMotion.
Errors — none.
ThemeMotion.toJson
Use it to turn a motion setting back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeIcons
Use it to draw icons in the design's style and stroke, and to know the launcher's glyph.
class ThemeIcons
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String style | String | One of Design.iconStyles. |
final double stroke | double | How thick the lines are, in units of the glyph's 24-unit box. |
final LauncherGlyph? launcher | LauncherGlyph? | Null: the launcher shows the brand's logo. |
Its functions: ThemeIcons, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeIcons.ThemeIcons
Use it to build an icon setting by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
style | String | required | One of Design.iconStyles. |
stroke | double | required | How thick the lines are, in units of the glyph's 24-unit box. |
launcher | LauncherGlyph? | optional | Null: the launcher shows the brand's logo. |
Returns — a new ThemeIcons.
Errors — none.
ThemeIcons.fromJson
Use it to read an icon setting from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The icons as decoded. |
d | ThemeIcons | required | The icon setting to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeIcons.
Errors — none.
ThemeIcons.toJson
Use it to turn an icon setting back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
LauncherGlyph
Use it to draw the launcher's glyph — the mark that stands for the agent.
class LauncherGlyph
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String id | String | The glyph's name in the dashboard's set. |
final String path | String | Its SVG path data, in a 24 × 24 box. |
final bool stroke | bool | True: drawn as lines at icons.stroke; false: filled. |
Its functions: LauncherGlyph, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
LauncherGlyph.LauncherGlyph
Use it to build a glyph by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The glyph's name in the dashboard's set. |
path | String | required | Its SVG path data, in a 24 × 24 box. |
stroke | bool | required | True: drawn as lines at icons.stroke; false: filled. |
Returns — a new LauncherGlyph.
Errors — none.
LauncherGlyph.fromJson
Use it to read a glyph from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The glyph as decoded; null for none. |
Returns — LauncherGlyph?. Example value: null.
Errors — none.
LauncherGlyph.toJson
Use it to turn a glyph back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeGlass
Use it to draw translucent, blurred surfaces when the design has them.
class ThemeGlass
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final double blur | double | How strongly the content behind is blurred as it shows through, given as a standard deviation, the way CSS's blur() expects. |
final double surfaceOpacity | double | colors.surface at this opacity, 0–1. |
Its functions: ThemeGlass, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeGlass.ThemeGlass
Use it to build a glass setting by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
blur | double | required | How strongly the content behind is blurred as it shows through, given as a standard deviation, the way CSS's blur() expects. |
surfaceOpacity | double | required | colors.surface at this opacity, 0–1. |
Returns — a new ThemeGlass.
Errors — none.
ThemeGlass.fromJson
Use it to read a glass setting from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The glass as decoded; null for opaque surfaces. |
Returns — ThemeGlass?. Example value: null.
Errors — none.
ThemeGlass.toJson
Use it to turn a glass setting back into the design's JSON — to store it or compare it.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeChat
Use it to draw a chat window of your own like the agent's: its words, colours and which pieces it shows.
class ThemeChat
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const List<String> avatars | List<String> | What may stand for the agent in the header: logo, glyph, none. |
static const List<String> patterns | List<String> | The backgrounds behind the messages: none, dots. |
static const int maxSuggestions | int | The most conversation starters a chat shows. |
final String title | String | Title shown in the header; an empty string ("") means the dashboard's heading. |
final String subtitle | String | The line under the title while online; an empty string ("") means "Online". |
final String avatar | String | Which mark the header shows for the agent: logo, glyph or none. |
final String placeholder | String | Placeholder text in the composer; an empty string ("") means "Message…". |
final bool showTimestamps | bool | Show the time under each message. |
final List<String> suggestions | List<String> | Starters offered in a new chat, up to maxSuggestions of them. |
final String background | String | Behind the messages and the composer strip. |
final String pattern | String | With dots, a dot pattern in patternColor is drawn over background. |
final String patternColor | String | The dots' colour, when pattern is dots. |
final String headerBackground | String | The header's fill. |
final String headerText | String | The header's title. |
final String headerSubtext | String | The header's subtitle ("Online"). |
final String composerBackground | String | The message field's fill. |
final String composerText | String | What the customer types. |
final String composerPlaceholder | String | The field's placeholder. |
final String composerBorder | String | The field's outline. |
final GraineChatSize size | GraineChatSize | The size the window opens at (Window size in the dashboard); compact unless the design chooses another. |
final bool showUpcomingCalls | bool | Whether a card at the top of the chat lists the calls this user has booked (Booked calls in the dashboard). |
final String upcomingTitle | String | Title of the booked-calls card; an empty string ("") means "Upcoming call" / "Upcoming calls". |
final bool showHistory | bool | Whether the earlier conversation that was kept is shown on screen (Earlier messages). |
final bool newConversation | bool | Whether the header has its compose control, the New conversation button. |
Its functions: ThemeChat, fallback, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeChat.ThemeChat
Use it to build a set of chat window tokens by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
title | String | '' | Title shown in the header; an empty string ("") means the dashboard's heading. |
subtitle | String | '' | The line under the title while online; an empty string ("") means "Online". |
avatar | String | 'logo' | Which mark the header shows for the agent: logo, glyph or none. |
placeholder | String | '' | Placeholder text in the composer; an empty string ("") means "Message…". |
showTimestamps | bool | false | Show the time under each message. |
suggestions | List<String> | const <String>[] | Starters offered in a new chat, up to maxSuggestions of them. |
background | String | required | Behind the messages and the composer strip. |
pattern | String | 'none' | With dots, a dot pattern in patternColor is drawn over background. |
patternColor | String | required | The dots' colour, when pattern is dots. |
headerBackground | String | required | The header's fill. |
headerText | String | required | The header's title. |
headerSubtext | String | required | The header's subtitle ("Online"). |
composerBackground | String | required | The message field's fill. |
composerText | String | required | What the customer types. |
composerPlaceholder | String | required | The field's placeholder. |
composerBorder | String | required | The field's outline. |
size | GraineChatSize | GraineChatSize.compact | The size the window opens at (Window size in the dashboard); compact unless the design chooses another. |
showUpcomingCalls | bool | true | Whether a card at the top of the chat lists the calls this user has booked (Booked calls in the dashboard). |
upcomingTitle | String | '' | Title of the booked-calls card; an empty string ("") means "Upcoming call" / "Upcoming calls". |
showHistory | bool | true | Whether the earlier conversation that was kept is shown on screen (Earlier messages). |
newConversation | bool | true | Whether the header has its compose control, the New conversation button. |
Returns — a new ThemeChat.
Errors — none.
ThemeChat.fallback
Use it to get the chat window an agent with no chat tokens draws.
The chat an older server gets: the window drawn the way it was before these tokens, with the page, the surface header, the raised composer and the launcher's mark (which is the design's glyph when there is one).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
c | ThemeColors | required | The scheme's colours. |
dark | bool | required | The dark scheme. |
hasGlyph | bool | required | The design has a launcher glyph (the header shows it instead of the logo). |
Returns — ThemeChat — the chat window as it was drawn before chat tokens: the page background, the surface header, the raised composer, and the launcher's glyph (or the logo) in the header.
Errors — none.
ThemeChat.fromJson
Use it to read a set of chat window tokens from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
r | Map<String, Object?> | required | The JSON object to read. |
d | ThemeChat | required | The chat tokens to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeChat.
Errors — none.
ThemeChat.toJson
Use it to turn the chat window's tokens back into the design's JSON — to store them or compare them.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeCall
Use it to draw a call screen of your own (GraineCallScreen.app) in the agent's call-screen design.
class ThemeCall
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const List<String> avatars | List<String> | What may stand for the agent: logo, glyph, initials. |
static const List<String> avatarShapes | List<String> | The avatar's shapes: circle, squircle, rounded-square. |
static const List<String> endShapes | List<String> | The hang-up button's shapes: round, pill. |
static const List<String> ringtones | List<String> | The rings: system (the phone's own), graine, soft. |
static const List<String> allControls | List<String> | Every in-call button: mute, speaker, chat, end. |
static const List<String> defaultControls | List<String> | The buttons when the design says nothing: mute, speaker, chat, end. |
final String background | String | The fill, or a gradient's top. |
final String? backgroundTo | String? | The colour at the bottom of a gradient, or null for a single solid fill. |
final String text | String | The name and the status line. |
final String textMuted | String | Secondary text: the timer, the caption. |
final String avatar | String | What stands for the agent: logo, glyph or initials. |
final String avatarShape | String | The avatar's shape: circle, squircle or rounded-square. |
final String avatarFill | String | Behind the avatar. |
final String avatarText | String | The initials, on avatarFill. |
final String buttonFill | String | An in-call button's fill. |
final String buttonIcon | String | An in-call button's icon. |
final String buttonActiveFill | String | A button that is on (muted, speaker) — its fill. |
final String buttonActiveIcon | String | A button that is on — its icon. |
final String endFill | String | The hang-up button's fill. |
final String endIcon | String | The hang-up button's icon. |
final String endShape | String | The hang-up button's shape: round or pill. |
final String acceptFill | String | The answer button's fill, while it rings. |
final String acceptIcon | String | The answer button's icon. |
final String declineFill | String | The decline button's fill, while it rings. |
final String declineIcon | String | The decline button's icon. |
final String callbackFill | String | "Call back", on a missed call. |
final String callbackIcon | String | The "Call back" button's icon, on a missed call. |
final bool captions | bool | Show the line being said. |
final bool timer | bool | Show the call's running time. |
final List<String> controls | List<String> | The buttons shown during a call, in order; end is always included. |
final String ringtone | String | The ring: system, graine or soft (Ringtone.all has the notes). |
final ThemeCallStatusText statusText | ThemeCallStatusText | What the screen says at each moment, in the brand's words. |
Its functions: ThemeCall, fallback, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeCall.ThemeCall
Use it to build a set of call screen tokens by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
background | String | required | The fill, or a gradient's top. |
backgroundTo | String? | optional | The colour at the bottom of a gradient, or null for a single solid fill. |
text | String | required | The name and the status line. |
textMuted | String | required | Secondary text: the timer, the caption. |
avatar | String | 'logo' | What stands for the agent: logo, glyph or initials. |
avatarShape | String | 'circle' | The avatar's shape: circle, squircle or rounded-square. |
avatarFill | String | required | Behind the avatar. |
avatarText | String | required | The initials, on avatarFill. |
buttonFill | String | required | An in-call button's fill. |
buttonIcon | String | required | An in-call button's icon. |
buttonActiveFill | String | required | A button that is on (muted, speaker) — its fill. |
buttonActiveIcon | String | required | A button that is on — its icon. |
endFill | String | required | The hang-up button's fill. |
endIcon | String | required | The hang-up button's icon. |
endShape | String | 'round' | The hang-up button's shape: round or pill. |
acceptFill | String | required | The answer button's fill, while it rings. |
acceptIcon | String | required | The answer button's icon. |
declineFill | String | required | The decline button's fill, while it rings. |
declineIcon | String | required | The decline button's icon. |
callbackFill | String | required | "Call back", on a missed call. |
callbackIcon | String | required | The "Call back" button's icon, on a missed call. |
captions | bool | true | Show the line being said. |
timer | bool | true | Show the call's running time. |
controls | List<String> | defaultControls | The buttons shown during a call, in order; end is always included. |
ringtone | String | 'system' | The ring: system, graine or soft (Ringtone.all has the notes). |
statusText | ThemeCallStatusText | const ThemeCallStatusText() | What the screen says at each moment, in the brand's words. |
Returns — a new ThemeCall.
Errors — none.
ThemeCall.fallback
Use it to get the call screen an agent with no call tokens draws.
The call screen an older server gets: the fixed dark screen that the native SDKs drew before these tokens existed.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
c | ThemeColors | required | The scheme's colours. |
Returns — ThemeCall — the fixed dark call screen, with the accent on the avatar and the Call back button.
Errors — none.
ThemeCall.fromJson
Use it to read a set of call screen tokens from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
r | Map<String, Object?> | required | The JSON object to read. |
d | ThemeCall | required | The call tokens to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeCall.
Errors — none.
ThemeCall.toJson
Use it to turn the call screen's tokens back into the design's JSON — to store them or compare them.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
ThemeCallStatusText
Use it to say what your call screen says at each moment, in the brand's words.
class ThemeCallStatusText
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String ringing | String | While an agent's call rings (default "Incoming call"). |
final String scheduled | String | Shown when Graine rings at a booked time, whether the user or the agent made the booking. |
final String connecting | String | While the call connects (default "Connecting…"). |
final String ended | String | Once the call is over (default "Call ended"). |
final String missed | String | On a ring nobody answered (default "Missed call"). |
Its functions: ThemeCallStatusText, fromJson, toJson — each with its parameters, what it returns, the errors it raises and an example.
ThemeCallStatusText.ThemeCallStatusText
Use it to build a set of call screen words by hand — for a preview or a test; the session's design carries the real one.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
ringing | String | 'Incoming call' | While an agent's call rings (default "Incoming call"). |
scheduled | String | 'Scheduled call' | Shown when Graine rings at a booked time, whether the user or the agent made the booking. |
connecting | String | 'Connecting…' | While the call connects (default "Connecting…"). |
ended | String | 'Call ended' | Once the call is over (default "Call ended"). |
missed | String | 'Missed call' | On a ring nobody answered (default "Missed call"). |
Returns — a new ThemeCallStatusText.
Errors — none.
ThemeCallStatusText.fromJson
Use it to read a set of call screen words from the design's JSON — the SDK does this when the session arrives.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | The words as decoded. |
d | ThemeCallStatusText | required | The words to keep for anything the JSON leaves out or gets wrong — the scheme's defaults. |
Returns — ThemeCallStatusText.
Errors — none.
ThemeCallStatusText.toJson
Use it to turn the call screen's words back into the design's JSON — to store them or compare them.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
Ringtone
Use it to play the agent's ring on a call screen of your own.
class Ringtone
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final String label | String | The ring's name, as the dashboard shows it. |
final String wave | String | sine or triangle. |
final double gain | double | How loud, from 0 to 1 of full scale. |
final List<RingNote> notes | List<RingNote> | The notes, played once per ring. |
final int pauseMs | int | The silence after the notes, in milliseconds, before they play again. |
static const Map<String, Ringtone> all | Map<String, Ringtone> | The rings by their call.ringtone names. |
Its functions: Ringtone, toJson — each with its parameters, what it returns, the errors it raises and an example.
Ringtone.Ringtone
Use it to describe a ring of your own.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
label | String | required | The ring's name, as the dashboard shows it. |
wave | String | required | sine or triangle. |
gain | double | required | How loud, from 0 to 1 of full scale. |
notes | List<RingNote> | required | The notes, played once per ring. |
pauseMs | int | required | The silence after the notes, in milliseconds, before they play again. |
Returns — a new Ringtone.
Errors — none.
Ringtone.toJson
Use it to turn a ring into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
RingNote
Use it to play one note of a ring.
class RingNote
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final double hz | double | The note's frequency, in hertz; 0 is a rest. |
final int ms | int | How long it lasts, in milliseconds. |
Its functions: RingNote, toJson — each with its parameters, what it returns, the errors it raises and an example.
RingNote.RingNote
Use it to describe one note of a ring of your own.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hz | double | required | The note's frequency, in hertz; 0 is a rest. |
ms | int | required | How long it lasts, in milliseconds. |
Returns — a new RingNote.
Errors — none.
RingNote.toJson
Use it to turn a note into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
Design (class)
Use it to apply the rules every Graine surface shares: the allowed values, colours, fonts and the launcher's geometry.
abstract final class Design
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const List<String> schemes | List<String> | auto (the device), light, dark. |
static const List<String> launcherShapes | List<String> | circle, squircle, rounded-square, square, pill. |
static const List<String> bubbleStyles | List<String> | filled, outline, minimal. |
static const List<String> iconStyles | List<String> | outline, filled, duotone, sharp. |
static const List<String> easings | List<String> | standard, emphasized, spring, linear, none. |
static const List<String> chromes | List<String> | The ways a content surface can be framed: as a plain surface or as a desktop window. |
static const double launcherSize | double | Size of the launcher, 56 × 56; a pill launcher is 56 tall and as wide as its label. |
static const double launcherGlyphScale | double | The size of the glyph or logo inside the launcher, relative to the launcher's height. |
static const double squircleScale | double | The corner size of a squircle, expressed as a fraction of the squircle's size. |
static const int glyphAssetVersion | int | Raised whenever a glyph's path data changes, so an image cached for a year never pairs an outdated drawing with a new id. |
static const String defaultOrigin | String | Where glyph images come from when no base address is given: 'https://www.graine.ai'. |
Its functions: normaliseHex, mixHex, fontFamily, launcherRadius, glyphUrl — each with its parameters, what it returns, the errors it raises and an example.
Design.normaliseHex
Use it to read any hex colour as #RRGGBB.
Returns "#RRGGBB" for any hex colour (#rgb or #rrggbb, with the "#" or without it), and null for anything else.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
value | Object? | required | A colour: #rgb or #rrggbb, with or without the #. |
Returns — String?. Example value: '#33AAEE'.
Errors — none.
Design.mixHex
Use it to mix two colours, as the design system does.
The colour a fraction t of the way from a to b, channel by channel, as #RRGGBB. A colour that does not read counts as black.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
a | String | required | The colour to start from, #RRGGBB. |
b | String | required | The colour to move towards. |
t | double | required | How far, from 0 (all a) to 1 (all b). |
Returns — String. Example value: '#808080'.
Errors — none.
Design.fontFamily
Use it to pick the family to draw with from the fonts your app has.
The app's own copy of a family, in the app's spelling, or null. system always means the platform's font; any other family is the app's when it is listed in available (matched without regard to case) — and then that copy wins over the faces the SDK fetches.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
family | String? | required | The design's family (tokens.font.body or heading). |
available | Iterable<String> | required | The families your app bundles (GraineConfig.fonts). |
Returns — String?. Example value: 'Inter'.
Errors — none.
Design.launcherRadius
Use it to round the launcher like the design's shape.
Works out the launcher's corner radius for a given height: fully round for circle and pill, 30% of the size for squircle, radius.lg for rounded-square and radius.sm for square, capped at half the height.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
shape | String | required | The launcher's shape (tokens.shape.launcher). |
radius | ThemeRadius | required | The design's radii (tokens.shape.radius). |
height | double | required | The launcher's height, in logical pixels. |
Returns — double. Example value: 16.8.
Errors — none.
Design.glyphUrl
Use it to get the launcher glyph as an image — for a notification or a native view.
The address of the launcher glyph as an image, built as every Graine SDK builds it: the id lower-cased, the colour as upper-case hex without its #, the size clamped to 16–512 physical pixels (the logical size × the screen's scale, so the image is sharp on every screen), the stroke clamped to 0.5–4 in quarter steps, and the asset version.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
origin | String? | required | The agent's address; 'https://www.graine.ai' when null. |
id | String | required | The glyph's id (tokens.icons.launcher.id). |
color | String | required | The glyph's colour, #RRGGBB. |
sizePx | num | required | The image's size in physical pixels — the logical size times the screen's scale (16–512). |
stroke | num | 2 | The stroke width for a line glyph (0.5–4, in quarter steps); 2 when left out. |
Returns — String. Example value: 'https://www.graine.ai/api/embed/glyph?id=waveform&c=FFFFFF&s=96&w=2&v=2'.
Errors — none.
DesignFonts
Use it to find the font files for the agent's typefaces — the SDK fetches and registers them itself.
abstract final class DesignFonts
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const int assetVersion | int | Raised whenever a font file Graine serves changes, so no cache — on the device or in between — keeps an old file. Part of every font address. |
static const Map<String, List<int>> weights | Map<String, List<int>> | All the families the dashboard offers, each with the weights it actually comes in. A family missing here is drawn in the system font and never fetched. |
Its functions: key, nearestWeight, canonicalFamily, faceName, url, faceFor, facesFor, facesForDesign — each with its parameters, what it returns, the errors it raises and an example.
DesignFonts.key
Use it to look a family and weight up in GraineInApp.fontFaces.
family|weight — what a loaded face is looked up by in GraineInApp.fontFaces.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
family | String | required | The family, as the design spells it. |
weight | int | required | The weight the family really has. |
Returns — String. Example value: 'DM Sans|700'.
Errors — none.
DesignFonts.nearestWeight
Use it to pick the closest weight a family really has.
The weight in available nearest want; on a tie, the heavier — a 500 asked of a family with 400 and 600 is drawn at 600. Null when available is empty.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
available | List<int> | required | The weights the family has. |
want | int | required | The weight the design asks for. |
Returns — int?. Example value: 600 (a tie goes to the heavier).
Errors — none.
DesignFonts.canonicalFamily
Use it to match a family name to the one the SDK has files for.
Returns the family spelled the way this build spells it, matching first exactly and then ignoring case. Returns null for "system", for an empty value, and for a family this build has no files for.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
family | String? | required | A family name, in any case. |
Returns — String?. Example value: 'DM Sans'.
Errors — none.
DesignFonts.faceName
Use it to get the family name a face is registered under.
The name a face is registered under — Graine-, the family with only its letters and digits, -, and the weight — the same on every Graine SDK.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
family | String | required | The family. |
weight | int | required | The weight. |
Returns — String. Example value: 'Graine-IBMPlexSans-600'.
Errors — none.
DesignFonts.url
Use it to get the address of one face's font file.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
origin | String? | required | The agent's address; 'https://www.graine.ai' when null. |
family | String | required | The family, as this build spells it. |
weight | int | required | The weight the family really has. |
Returns — String. Example value: 'https://www.graine.ai/api/embed/font?f=DM%20Sans&w=700&v=1'.
Errors — none.
DesignFonts.faceFor
Use it to get the face to draw a family at a weight.
The face to draw family at weight with — at the nearest weight the family really has — or null when the family is the system font or one this build has no files for.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
family | String? | required | The design's family; system or one with no files gives null. |
weight | int | required | The weight the design asks for. |
origin | String? | optional | The agent's address. |
Returns — DesignFontFace? — its fields: DesignFontFace. Example value: null.
Errors — none.
DesignFonts.facesFor
Use it to list the faces one token set draws with.
Lists the faces a single token set uses — the body family at weights.body and weights.strong, and the heading family at weights.title and weights.strong — with no face repeated.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
t | ThemeTokens | required | One scheme's tokens. |
origin | String? | optional | The agent's address. |
Returns — List<DesignFontFace> — its fields: DesignFontFace. Example value: [].
Errors — none.
DesignFonts.facesForDesign
Use it to list the faces a whole design draws with, light and dark.
Lists all faces a design may use in either scheme. The SDK fetches these when a session brings the design, so switching to dark never has to wait.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
design | ResolvedDesign | required | The design. |
origin | String? | optional | The agent's address. |
Returns — List<DesignFontFace> — its fields: DesignFontFace. Example value: [].
Errors — none.
DesignFontFace
Read it as one typeface the SDK fetches and registers.
class DesignFontFace
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String family | String | The family name spelled as in the dashboard, for example "IBM Plex Sans". |
final int weight | int | The closest weight the family actually has to the one the design requested. |
final String name | String | The name the face is registered with as a family, such as Graine-IBMPlexSans-600. |
final String url | String | Where Graine serves the TTF. |
String get key | String | family|weight — what a loaded face is looked up by. |
Its functions: DesignFontFace, toJson — each with its parameters, what it returns, the errors it raises and an example.
DesignFontFace.DesignFontFace
Use it to describe a face by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
family | String | required | The family name spelled as in the dashboard, for example "IBM Plex Sans". |
weight | int | required | The closest weight the family actually has to the one the design requested. |
name | String | required | The name the face is registered with as a family, such as Graine-IBMPlexSans-600. |
url | String | required | Where Graine serves the TTF. |
Returns — a new DesignFontFace.
Errors — none.
DesignFontFace.toJson
Use it to turn a face into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
SdkIcons
Use it to draw the SDK's own icons — microphone, hang up, send, chat, call, chevron, close, compose, speaker — in your own UI.
abstract final class SdkIcons
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const SdkIcon mic | SdkIcon | The microphone: start a call, or unmute. |
static const SdkIcon micOff | SdkIcon | The microphone struck through: muted. |
static const SdkIcon end | SdkIcon | The handset turned down: hang up. |
static const SdkIcon send | SdkIcon | The paper plane: send a message. |
static const SdkIcon chat | SdkIcon | The speech bubble: open the chat. |
static const SdkIcon call | SdkIcon | The handset: call. |
static const SdkIcon chevron | SdkIcon | Drawn pointing UP; the chat header rotates it by 180°. |
static const SdkIcon close | SdkIcon | The cross: close. |
static const SdkIcon compose = | — | Icon used for "New conversation" in the header of a chat window; it pictures a page and a pen. |
static const SdkIcon speaker = | — | The loudspeaker icon of the call screen, for apps that draw their own call screen. |
static const Map<String, SdkIcon> all | Map<String, SdkIcon> | Every icon by name: mic, micOff, end, send, chat, call, chevron, close, compose, speaker. |
Its functions: treatment — each with its parameters, what it returns, the errors it raises and an example.
SdkIcons.treatment
Use it to know how an icon style strokes and fills.
How style draws an icon at stroke: outline — stroked, round caps and joins; sharp — stroked, square caps, mitred joins; filled — the body filled, stroked at 0.75 × the stroke (at least 1); duotone — the body filled at 28%, then stroked. A style this build does not know draws as outline.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
style | String | required | The design's icon style (tokens.icons.style); an unknown one draws as outline. |
stroke | double | required | The design's stroke width (tokens.icons.stroke), in the icon's 24-unit box. |
Returns — IconTreatment — its fields: IconTreatment.
Errors — none.
SdkIcon
Use it to draw one of the SDK's icons from its path data.
class SdkIcon
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final String? body | String? | A closed path that may be filled (24 × 24 SVG path data); null for a line-only icon. |
final String? lines | String? | Paths that are only ever stroked; null for a body-only icon. |
Its functions: SdkIcon, toJson — each with its parameters, what it returns, the errors it raises and an example.
SdkIcon.SdkIcon
Use it to describe an icon by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | String? | optional | A closed path that may be filled (24 × 24 SVG path data); null for a line-only icon. |
lines | String? | optional | Paths that are only ever stroked; null for a body-only icon. |
Returns — a new SdkIcon.
Errors — none.
SdkIcon.toJson
Use it to turn an icon into JSON.
Parameters — none.
Returns — Map<String, Object?>.
Errors — none.
IconTreatment
Read it to stroke and fill an icon in the design's style.
class IconTreatment
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final bool fillBody | bool | True when the body has a fill; it is stroked in every case. |
final double bodyFillOpacity | double | How opaque the body's fill is, measured as a share of the icon's colour. |
final double bodyStroke | double | How thick the body's outline is, measured in the icon's own 24-unit box. |
final double lineStroke | double | The stroke width of the icon's lines, in its 24-unit box. |
final bool square | bool | When true, lines have square caps and mitred joins for a sharp look; when false, caps and joins are round. |
Its functions: IconTreatment — each with its parameters, what it returns, the errors it raises and an example.
IconTreatment.IconTreatment
Use it to describe a treatment by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
fillBody | bool | required | True when the body has a fill; it is stroked in every case. |
bodyFillOpacity | double | required | How opaque the body's fill is, measured as a share of the icon's colour. |
bodyStroke | double | required | How thick the body's outline is, measured in the icon's own 24-unit box. |
lineStroke | double | required | The stroke width of the icon's lines, in its 24-unit box. |
square | bool | required | When true, lines have square caps and mitred joins for a sharp look; when false, caps and joins are round. |
Returns — a new IconTreatment.
Errors — none.
Appearance
Use it to read the dashboard's Appearance settings — for an agent with no design, or a surface of your own.
abstract final class Appearance
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const String defaultAccent | String | The accent used when the dashboard sets none: '#318CE7'. |
static const String defaultOrigin | String | Where pictures and glyphs are fetched from when no base address is given: 'https://www.graine.ai'. |
Its functions: resolve, isDark, palette, luminance, argb, tint, encodeURIComponent — each with its parameters, what it returns, the errors it raises and an example.
Appearance.resolve
Use it to read the dashboard's Appearance into what a phone draws.
The dashboard's values win, and the host app's values serve only as the fallback; the rule always runs in this one direction.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
appearance | Map<String, Object?>? | required | The dashboard's Appearance (session.appearance). |
accent | String | required | The accent to use when the dashboard sets none. |
heading | String | required | The heading to use when the dashboard sets none. |
radius | double? | optional | The corner radius to use when the dashboard sets none; 18 when left out. |
maxRadius | double? | optional | The most rounding your surface can draw; 48 when left out. |
origin | String? | optional | The agent's address, for the logo's address; 'https://www.graine.ai' when left out. |
Returns — NativeAppearance — its fields: NativeAppearance.
Errors — none.
Appearance.isDark
Use it to know whether to draw dark, from the dashboard's theme and the device.
Handles light, dark or "auto"; "auto" follows the device rather than the dashboard's own default.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
theme | String? | required | The dashboard's theme: light, dark or auto. |
deviceDark | bool? | required | Whether the device is in dark mode — MediaQuery.platformBrightnessOf(context) == Brightness.dark; null when unknown, read as light. |
Returns — bool. Example value: true.
Errors — none.
Appearance.palette
Use it to get the colours a component is drawn in.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
appearance | Map<String, Object?>? | required | The dashboard's Appearance, for its theme. |
deviceDark | bool? | optional | Whether the device is in dark mode — MediaQuery.platformBrightnessOf(context) == Brightness.dark; null when unknown, read as light. |
accent | String? | optional | The accent, to pick readable ink on it. |
Returns — WidgetPalette — its fields: WidgetPalette.
Errors — none.
Appearance.luminance
Use it to know how light a colour is.
Returns the WCAG relative luminance of a #rrggbb colour, or 0 for any other input.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hex | String | required | A colour as #RRGGBB. |
Returns — double. Example value: 0.25.
Errors — none.
Appearance.argb
Use it to turn #RRGGBB into a colour value Flutter takes.
Converts #rgb, #rrggbb or #aarrggbb (the "#" is optional) into a 32-bit ARGB value.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hex | String? | required | A colour as #RGB, #RRGGBB or #AARRGGBB, with or without the #. |
Returns — int?. Example value: 0xFF318CE7.
Errors — none.
Appearance.tint
Use it to make a colour see-through.
Returns a #rrggbb colour at reduced strength, as a 32-bit ARGB value, for badge and selection fills.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hex | String? | required | A colour as #RRGGBB; slate for anything else. |
alpha | double | required | How strong, from 0 to 1. |
Returns — int. Example value: 0x1F318CE7.
Errors — none.
Appearance.encodeURIComponent
Use it to put text in an address the way the SDK does.
Encodes text for an address exactly as Uri.encodeComponent does (a space as %20).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String | required | The text to put in an address. |
Returns — String. Example value: 'Order%20ORD%201234'.
Errors — none.
NativeAppearance
Read it as the dashboard's Appearance, translated for a phone.
class NativeAppearance
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String accent | String | Always a valid "#rgb" or "#rrggbb". |
final String heading | String | The heading of the panel, such as "Talk to our AI assistant"; this is NOT the assistant's name. |
final String? logoUrl | String? | Absolute, or null when no logo is set. |
final LogoPlate logoPlate | LogoPlate | The background under the logo when it replaces the launcher glyph: the accent or a white plate. |
final double radius | double | How rounded the corners are, limited to what the host app can draw. |
Its functions: NativeAppearance — each with its parameters, what it returns, the errors it raises and an example.
NativeAppearance.NativeAppearance
Use it to build an appearance by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
accent | String | required | Always a valid "#rgb" or "#rrggbb". |
heading | String | required | The heading of the panel, such as "Talk to our AI assistant"; this is NOT the assistant's name. |
logoUrl | String? | optional | Absolute, or null when no logo is set. |
logoPlate | LogoPlate | LogoPlate.accent | The background under the logo when it replaces the launcher glyph: the accent or a white plate. |
radius | double | required | How rounded the corners are, limited to what the host app can draw. |
Returns — a new NativeAppearance.
Errors — none.
WidgetPalette
Read it as the colours a component is drawn in.
class WidgetPalette
What to expect — How the SDK draws a component and reads the customer's answer to it. Public so a component view of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String surface | String | Behind the component, as #RRGGBB. |
final String border | String | Hairlines and chip fills, as #RRGGBB. |
final String text | String | Titles and prices, as #RRGGBB. |
final String muted | String | Subtitles, facts and secondary labels, as #RRGGBB. |
final String onAccent | String | A colour that stays legible ON the accent; it is picked by luminance, so labels still show on a yellow accent. |
final String mode | String | Either "light" or "dark", with "auto" already settled using the device's setting. |
Its functions: WidgetPalette — each with its parameters, what it returns, the errors it raises and an example.
WidgetPalette.WidgetPalette
Use it to build a palette by hand for a preview.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | String | required | Behind the component, as #RRGGBB. |
border | String | required | Hairlines and chip fills, as #RRGGBB. |
text | String | required | Titles and prices, as #RRGGBB. |
muted | String | required | Subtitles, facts and secondary labels, as #RRGGBB. |
onAccent | String | required | A colour that stays legible ON the accent; it is picked by luminance, so labels still show on a yellow accent. |
mode | String | required | Either "light" or "dark", with "auto" already settled using the device's setting. |
Returns — a new WidgetPalette.
Errors — none.
LogoPlate
Read it to know what the brand's logo sits on: the accent, or a white plate.
enum LogoPlate
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Case | Meaning |
|---|---|
accent | The logo sits on the shape's own fill; this suits a white or light logo meant for a coloured background. |
white | Puts the logo on a white plate with a hairline, suited to a coloured or dark logo or an opaque image — and most logo files are opaque images. |
| Property | Type | Meaning |
|---|---|---|
String get wire | String | The word on the wire. |
Its functions: from — each with its parameters, what it returns, the errors it raises and an example.
LogoPlate.from
Use it to read the plate from the dashboard's setting.
The dashboard's logoPlate as every Graine SDK reads it: exactly "white" is white; anything else — absent, "WHITE", a number — is the accent.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
value | Object? | required | The dashboard's logoPlate: exactly "white" is white; anything else is the accent. |
Returns — LogoPlate. Example value: LogoPlate.accent.
Errors — none.
LogoPlateLook
Read it to draw the plate under a logo: its fill and outline.
class LogoPlateLook
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
final String fill | String | A "#RRGGBB" colour, either the accent or BrandLogo.plateWhite. |
final double? outlineWidth | double? | Width of the hairline around a white plate, or null when there is none. |
final String? outlineColor | String? | The hairline's colour round a white plate; null for none. |
bool get hasOutline | bool | True when the plate has a hairline (the white plate). |
Its functions: LogoPlateLook — each with its parameters, what it returns, the errors it raises and an example.
LogoPlateLook.LogoPlateLook
Use it to describe a plate by hand.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
fill | String | required | A "#RRGGBB" colour, either the accent or BrandLogo.plateWhite. |
outlineWidth | double? | optional | Width of the hairline around a white plate, or null when there is none. |
outlineColor | String? | optional | The hairline's colour round a white plate; null for none. |
Returns — a new LogoPlateLook.
Errors — none.
BrandLogo
Use it to fit the brand's logo into the launcher, the bar's avatar or the chat header exactly as the SDK does.
abstract final class BrandLogo
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const String plateWhite | String | The white plate. |
static const String labelOnWhite | String | Colour of a pill launcher's label on the white plate — an ink that reads well on white. |
Its functions: box, outlineWidth, plateLook — each with its parameters, what it returns, the errors it raises and an example.
BrandLogo.box
Use it to get the square a logo is fitted into.
The square a logo is fitted into — whole, proportions kept, centred, never cropped — inside a shape size across (a pill: pass its height and circle). A circle or squircle holds 70% of its size, a rounded square or square 80%; rounded down, so a corner never pokes out.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
shape | String | required | The shape the logo sits in: circle, squircle, rounded-square, square (a pill: pass circle). |
size | double | required | The shape's size across, in logical pixels (a pill: its height). |
Returns — int. Example value: 39.
Errors — none.
BrandLogo.outlineWidth
Use it to get the white plate's outline width.
Width of the white plate's hairline, max(1, borderWidth). Even a design with no outlines needs it; otherwise a white plate disappears against a white bar.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
borderWidth | double | required | The design's outline width. |
Returns — double. Example value: 1.0.
Errors — none.
BrandLogo.plateLook
Use it to get the plate's fill and outline.
The plate's fill and outline.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
plate | LogoPlate | required | The plate the logo needs. |
accent | String | required | The accent, #RRGGBB. |
border | String | required | The design's border colour, for the white plate's hairline. |
borderWidth | double | 1 | The design's outline width; 1 when left out. |
Returns — LogoPlateLook — its fields: LogoPlateLook.
Errors — none.
WindowChrome
Use it to draw the design's desktop-window title bar (chrome: "window") on a surface of your own.
abstract final class WindowChrome
What to expect — Resolved from the agent's design in the Garage when the session loads; before that, and from an older server, every field holds its default. A missing or malformed value falls back on its own; reading these never throws. Most apps never need them: the SDK's own views draw from them.
| Property | Type | Meaning |
|---|---|---|
static const double lightsInset | double | How far the three lights sit in from the surface's left edge, inside its outline: 12. |
static const double lightsGap | double | Between one light and the next. |
static const List<String> lights | List<String> | Always the same three — close, minimise and zoom — in every design, because they are window controls rather than brand colours. |
static const double onlineDot | double | Used for the success dot ahead of the chat's title while online, and for the gap between that dot and the heading. |
static const double onlineDotGap | double | The space between the online dot and the title: 6. |
static const double chevronIcon | double | The collapse chevron at the right end of the chat window's bar: an 18-point glyph inside a 30-point target inset by 6, which puts the glyph itself 12 in — the same inset as the lights, on the opposite side. |
static const double chevronBox | double | The chevron's tap target: 30. |
static const double chevronInset | double | How far the chevron's target sits in from the right edge: 6. |
static const double titleGap | double | How much room separates the title from the lights (or from the chevron). |
static const String monospace | String | The family name for monospaced text: monospace works on Android, which defines it; iOS does not, so there use Menlo. |
static const List<String> monospaceFallback | List<String> | Where to look for a monospaced face when the platform names none: Menlo, Roboto Mono, monospace. |
static const String captionTitle | String | The caption card's title. |
Its functions: barHeight, lightSize, lightsWidth, titleInset, title, innerRadius — each with its parameters, what it returns, the errors it raises and an example.
WindowChrome.barHeight
Use it to get the title bar's height on a surface.
Height of the title bar including its bottom outline — 32 for the chat window and components, 24 for the caption card.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | ChromeSurface | required | Which surface: chat, caption or component. |
Returns — double. Example value: 3.
Errors — none.
WindowChrome.lightSize
Use it to get the size of each of the three lights.
The diameter of each light: 10, or 8 on the caption card.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | ChromeSurface | required | Which surface. |
Returns — double. Example value: 3.
Errors — none.
WindowChrome.lightsWidth
Use it to get the width of the three lights.
The three lights, edge to edge.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | ChromeSurface | required | Which surface. |
Returns — double. Example value: 3.
Errors — none.
WindowChrome.titleInset
Use it to keep the title clear of the lights and the chevron.
The distance the title stays from each end of the bar, so it is centred across the full bar and never runs under the lights or the chevron.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | ChromeSurface | required | Which surface. |
chevron | bool | false | The bar has the collapse chevron at its right end (the chat window). |
Returns — double. Example value: 3.
Errors — none.
WindowChrome.title
Use it to get the title a surface's bar shows.
Gives the title in lower case: the heading on the chat window, "captions" on the caption card, and a component card's own title — empty when a component has none, leaving only the lights on its bar.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
surface | ChromeSurface | required | Which surface. |
heading | String | '' | The chat window's heading. |
componentTitle | String | '' | A component's own title. |
Returns — String. Example value: 'help desk'.
Errors — none.
WindowChrome.innerRadius
Use it to round the title bar's top corners inside the surface's outline.
The radius of a surface's top corner inside its outline, which is what the title bar's corners use.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
radius | double | required | The surface's corner radius. |
borderWidth | double | required | The surface's outline width. |
Returns — double. Example value: 23.0.
Errors — none.
ChromeSurface
Use it to say which surface wears the title bar: the chat window, the caption card or a component.
enum ChromeSurface { chat, caption, component }
What to expect — Only matters when the design's chrome is "window"; the caption card's bar is the small one.
| Case | Meaning |
|---|---|
chat | The chat window: a 32-high bar with the lights, the heading and the collapse chevron. |
caption | The caption card: a 24-high bar titled "captions". |
component | A component card: a 32-high bar with the component's own title. |
Going live
Before the store build: the publishable key is the live one, app:// is in the agent's Allowed domains (Embed & Widgets), the microphone and notification permissions are asked for, and the native call engine is in the build (adding or updating graine_inapp needs a new store build). Turn the logs on while you test, and off for release.
Debug logging
Turn it on while you build and test, to see everything the SDK and the call engine do; turn it off for release.
Two switches, both off by default — turn them on in debug builds, for example with Flutter's kDebugMode:
| Switch | What it logs |
|---|---|
GraineConfig(debug: true) | Every message between the SDK and the page that carries the voice call, both ways, the chat's frames, and the page's console, prefixed [Graine]. Outgoing variables and screen context are logged by key names and screen id only; incoming messages are cut to 600 characters. On Android the page becomes inspectable at chrome://inspect, on iOS in Safari's Web Inspector. |
GraineCallsOptions(debug: true) | The native call engine's log, in Xcode's console or logcat: how each call connected, what its audio did, and why one did not (on iOS, CallKit starting and stopping the call's audio too). Read once at launch: a change takes effect at the next launch. |
"The agent did not speak" is answered in one read of these logs, and cannot be answered without them. They never show the customer anything.
GraineVersion
Read it to report which version of the package an app runs — in your logs, or when you ask for support.
abstract final class GraineVersion
What to expect — The SDK's version, as a constant: include it when you ask for support.
| Property | Type | Meaning |
|---|---|---|
static const String name | String | The package's version, as in its pubspec.yaml — '0.10.3' in this release. |
Events and listeners
Everything an agent reports — its session arriving, the call's state, captions, components, the network, actions, friction, the agent speaking up in the chat, and errors — through one listener you register. Every callback is optional and runs on the main isolate.
GraineInApp.addListener
Call it to hear what the agent reports: register your listener once, usually at launch.
Adds a listener for this agent's events. It is kept until removed; adding the same object twice has no further effect. A listener that throws is logged and does not stop the others.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
l | GraineListener | required | The listener. |
Returns — nothing; it returns when done.
Errors — none.
GraineInApp.removeListener
Call it when a listener should stop hearing from the agent — when its screen goes away.
Removes a listener.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
l | GraineListener | required | The listener. |
Returns — nothing; it returns when done.
Errors — none.
GraineListener
Implement it to hear what the agent reports; override only the callbacks you need.
Everything an agent reports. An abstract mixin class: use it with extends or with; every method has an empty default, so override only what you use. Register it with GraineInApp.addListener. Delivered on the main isolate.
What to expect — Implement only the callbacks you need; the others do nothing. Called on the main thread.
Its functions: onSessionReady, onCallState, onCaption, onWidget, onWidgetPending, onEnded, onMicDenied, onQuality, onNetwork, onReconnecting, onTransport, onConnectivity, onActionRequested, onActionCompleted, onFriction, onAgentVolunteered, onError — each with its parameters, what it returns, the errors it raises and an example.
GraineListener.onSessionReady
Override it to act once the agent's settings have arrived — to show your own button only when they allow it.
The agent's configuration has loaded.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
session | SessionConfig | required | The agent's settings. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onCallState
Override it to follow the voice call connecting, connected and ending.
The voice call connected, started connecting, or stopped. Also fires when a connect attempt ends because nothing could carry the call.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
connected | bool | required | The call is connected. |
connecting | bool | required | A call is being placed. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onCaption
Override it to follow what is said on the call, as it is said.
A line of the voice call: repeated with live: true as it fills in, then once settled. The chat's lines are in GraineChatSession.turns.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
role | Role | required | Who said it: Role.agent or Role.customer. |
text | String | required | The words so far. |
live | bool | required | Still being said or recognised; the same line arrives again, fuller, until it settles. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onWidget
Override it to hear when the agent draws a component — if you draw components yourself.
The agent drew a component, in the call or the chat, as Graine sent it. GraineComponents already holds it for GraineWidgetView; an app drawing its own answers it with GraineVoice.answerWidget (call) or GraineChatSession.answerWidget (chat).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widget | Map<String, Object?> | required | The component as Graine sent it; GraineWidget.adopt reads it. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onWidgetPending
Override it to hear that a component is on its way.
A component is on its way and its content is loading; the hint carries its widget_id and kind when Graine gives them.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hint | Map<String, Object?> | required | What is known of the coming component — its id and kind. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onEnded
Override it to hear that a call ended.
The voice call is over, however it ended (including a hang-up the engine never confirmed). Once per call.
Parameters — none.
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onMicDenied
Override it to tell the customer the call needs the microphone.
The microphone was refused: "NotAllowedError" when requestMicrophone answered false (or the engine asked for it after that), otherwise the engine's reason, such as "NotFoundError".
| Parameter | Type | Default | Meaning |
|---|---|---|---|
reason | String | required | NotAllowedError (refused) or NotFoundError (no usable microphone). |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onQuality
Override it to follow the call's connection quality.
One word for the connection; fires only when the word changes. lost when the network goes; unknown when a call ends.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
quality | ConnectionQuality | required | The connection now, in one word. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onNetwork
Override it to hear when the device goes offline or comes back.
The engine page's view of the network changed.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
online | bool | required | true when the device came back online, false when it went offline. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onReconnecting
Override it to hear that the network interrupted the call and it is being re-established.
The network interrupted the call and it is being re-established (true), or that is over (false). Not an end.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
active | bool | required | true while the call is being re-established, false once it is back. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onTransport
Override it to learn which way the call's audio really travels, and why it moved.
Which transport carries the call, which was asked for, and why they differ. With reason "not_configured", message is also reported to onError and held as GraineVoice.error.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
transport | Transport | required | The way the audio really travels. |
requested | Transport | required | The way that was asked for. |
reason | String? | required | Why they differ, in one word (not_configured when high-quality audio is not enabled for the workspace); null when they do not. |
message | String? | required | Why, in a sentence for you; null when nothing went wrong. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onConnectivity
Override it to follow the page that carries the call loading, retrying and failing.
The engine page is loading, ready, retrying or has failed. attempt is the number of reloads so far; reason is a short word such as "stalled", "boot_timeout", "load_cap" or "session".
| Parameter | Type | Default | Meaning |
|---|---|---|---|
state | GraineConnectivity | required | Where the page is: loading, ready, retrying or failed. |
attempt | int | required | How many reloads have been scheduled so far. |
reason | String? | required | Why it is retrying or failed, in one word (stalled, boot_timeout, load_cap, session, or the page's error); null otherwise. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onActionRequested
Override it to hear that the agent asked your app to do something.
The agent asked the app to run an action; fires before the handler runs.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name, as registered. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onActionCompleted
Override it to hear what an action answered.
The answer the agent was given for that action.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name, as registered. |
result | ActionResult | required | What it answered — what the agent was told. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onFriction
Override it to hear that a customer looks stuck — to open the bar, say.
The customer looks stuck on a step (stalled_on_step): on one screen, with a field outstanding, through a stretch of a live conversation. The conversation is told at the same moment; this is for the app — badge a control, count it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
signal | FrictionSignal | required | The friction signal. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onAgentVolunteered
Override it to hear that the agent spoke up in the chat unasked — to show a badge or a notification.
In the chat, the agent spoke without being asked — its welcome, or something it noticed on screen; text is the turn's first words. Open the chat if it is closed.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String | required | What the agent said. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
GraineListener.onError
Override it to log what went wrong; the customer never sees these.
Something your team must fix, for your logs and never shown to the customer: the agent's configuration could not load, a call was started with no GraineEngine for the agent, a call was started while a native call holds the line, the engine page could not load after every retry, or a transport is not configured.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | String | required | What went wrong, in a sentence for you — never shown to the customer. |
Returns — your implementation returns nothing; the SDK calls it on the main thread when it happens, with the parameters above as its payload.
Errors — none.
Errors
A request to Graine that is refused, or cannot be made, fails with one error type, GraineException, carrying a typed GraineErrorCode. Branch on the code; show the message, which is written for the customer and never carries the identifier, traits or a push token.
GraineException
Catch it around any call that asks Graine — memory, booking — and branch on its code.
What a request to Graine fails with: a typed code, a sentence written for whoever has to fix it, and, with a rate limit, how long to wait. Implements Exception; thrown by the memory and scheduling methods of GraineInApp.
What to expect — Thrown or passed by every method that asks Graine. Branch on code, and show message — a sentence fit for the customer that never carries the identifier, traits or a push token. retryAfterSeconds comes with rate_limited when Graine said how long. A refusal made on the device before any request has status 0.
| Field | Type | Default | Meaning |
|---|---|---|---|
final String message | String | required | The sentence Graine (or the SDK) gave, written for whoever has to fix it. |
final GraineErrorCode code | GraineErrorCode | GraineErrorCode.unknown | Why — branch on this. network when Graine could not be reached; unknown for a code this build does not know (see codeName). |
final String? codeName | String? | null | The code as Graine said it, including a newer one this build does not know. Null when it said none. |
final int? statusCode | int? | null | The refusal's HTTP status, or null when there was none. |
final int? retryAfterSeconds | int? | null | With rateLimited: how long Graine asked the app to wait, from the Retry-After header. |
@override String toString() | String | — | The message. |
Its functions: GraineException — each with its parameters, what it returns, the errors it raises and an example.
GraineException.GraineException
Use it to build an error by hand for a test or a fake.
The constructor; the SDK builds these.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | String | required | The sentence Graine (or the SDK) gave, written for whoever has to fix it. |
code | GraineErrorCode | GraineErrorCode.unknown | Why — branch on this. network when Graine could not be reached; unknown for a code this build does not know (see codeName). |
codeName | String? | optional | The code as Graine said it, including a newer one this build does not know. Null when it said none. |
statusCode | int? | optional | The refusal's HTTP status, or null when there was none. |
retryAfterSeconds | int? | optional | With rateLimited: how long Graine asked the app to wait, from the Retry-After header. |
Returns — a new GraineException.
Errors — none.
GraineErrorCode
Branch on it to handle why Graine said no — and show the message.
Why Graine said no: the codes Graine sends, typed, plus network and unknown. When a refusal carries no code, the HTTP status decides: 400 invalidRequest, 401 invalidKey, 403 originRefused, 404 notFound, 429 rateLimited, 503 unavailable, anything else unknown.
What to expect — invalid_key · origin_refused · rate_limited · invalid_request · identity_required · device_limit · scheduling_off · too_soon · too_far · outside_window · too_many_pending · not_found · unavailable · network (no answer came back) · unknown, which carries a code newer than this SDK. Error codes and their fixes says when each happens and how to fix it.
| Field | Type | Default | Meaning |
|---|---|---|---|
final String wire | String | — | The word on the wire, as listed above. |
Its functions: invalidKey, originRefused, rateLimited, invalidRequest, identityRequired, deviceLimit, schedulingOff, tooSoon, tooFar, outsideWindow, tooManyPending, notFound, unavailable, network, unknown, fromWire — each with its parameters, what it returns, the errors it raises and an example.
GraineErrorCode.invalidKey
Branch on it to handle the case where the publishable key was rejected.
The publishable key was rejected. Check it against Embed & Widgets in the dashboard.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'invalid_key'.
Errors — none.
GraineErrorCode.originRefused
Branch on it to handle the case where the agent does not accept connections from this app.
The agent does not accept connections from a mobile app: add app:// to its Allowed domains.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'origin_refused'.
Errors — none.
GraineErrorCode.rateLimited
Branch on it to handle the case where there were too many requests.
Too many requests. Wait retryAfterSeconds when given.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'rate_limited'.
Errors — none.
GraineErrorCode.invalidRequest
Branch on it to handle the case where a request was missing something or malformed.
A field is missing or malformed. Also raised on the device for a booking reason over 120 characters and for an empty id to cancel.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'invalid_request'.
Errors — none.
GraineErrorCode.identityRequired
Branch on it to handle the case where the call needs an identified customer.
Nobody is identified. Raised on the device by memories and forgetMemory, and by Graine.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'identity_required'.
Errors — none.
GraineErrorCode.deviceLimit
Branch on it to handle the case where this device is not one of the customer's allowed devices.
This install is not one of the user's devices.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'device_limit'.
Errors — none.
GraineErrorCode.schedulingOff
Branch on it to handle the case where the agent takes no bookings from the app.
The agent does not take bookings from the app. Checked on the device.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'scheduling_off'.
Errors — none.
GraineErrorCode.tooSoon
Branch on it to handle the case where a booking was too soon.
Earlier than schedulingRules.earliest(now). Checked on the device.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'too_soon'.
Errors — none.
GraineErrorCode.tooFar
Branch on it to handle the case where a booking was too far ahead.
Later than schedulingRules.latest(now). Checked on the device.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'too_far'.
Errors — none.
GraineErrorCode.outsideWindow
Branch on it to handle the case where a booking falls outside the agent's calling hours.
Outside the agent's calling window.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'outside_window'.
Errors — none.
GraineErrorCode.tooManyPending
Branch on it to handle the case where the customer already has the most calls waiting.
The user already has the most calls waiting that the agent allows.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'too_many_pending'.
Errors — none.
GraineErrorCode.notFound
Branch on it to handle the case where the booking is not this customer's, or no longer exists.
No such booking for this user or install.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'not_found'.
Errors — none.
GraineErrorCode.unavailable
Branch on it to handle the case where Graine could not answer just now.
Graine could not answer just now. Try again with backoff.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'unavailable'.
Errors — none.
GraineErrorCode.network
Branch on it to handle the case where no answer came back.
Graine could not be reached: offline, timed out, or the agent's configuration could not be loaded.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'network'.
Errors — none.
GraineErrorCode.unknown
Branch on it to handle the case where the code is newer than this SDK.
A code this build does not know (its word is in GraineException.codeName), or an unexpected answer.
Parameters — none.
Returns — the value to compare GraineException.code with; its wire is 'unknown'.
Errors — none.
GraineErrorCode.fromWire
Use it to read an error code from its word.
The value for a wire word (trimmed, any case); unknown for anything else.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String? | required | The code's word, as Graine sent it; anything this build does not know reads as unknown. |
Returns — GraineErrorCode.
Errors — none.
EmbedRefusal
Use it to turn a refused answer from Graine into the code and sentence the SDK reports.
class EmbedRefusal
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final String message | String | The sentence for whoever has to act on it — the customer, or you, for a key or a domain to fix. |
final GraineErrorCode code | GraineErrorCode | The code from the wire as a typed value. It is GraineErrorCode.unknown if the server sent a code this build does not recognise (see codeName), or when no code came and the status does not imply one. |
final String? codeName | String? | The server's own word for the code, or null if it sent no code. |
final int? statusCode | int? | The HTTP status of the refusal. |
final int? retryAfterSeconds | int? | The wait before trying again, taken from the Retry-After header. |
Its functions: EmbedRefusal, of — each with its parameters, what it returns, the errors it raises and an example.
EmbedRefusal.EmbedRefusal
Use it to build a refusal by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | String | required | The sentence for whoever has to act on it — the customer, or you, for a key or a domain to fix. |
code | GraineErrorCode | required | The code from the wire as a typed value. It is GraineErrorCode.unknown if the server sent a code this build does not recognise (see codeName), or when no code came and the status does not imply one. |
codeName | String? | optional | The server's own word for the code, or null if it sent no code. |
statusCode | int? | optional | The HTTP status of the refusal. |
retryAfterSeconds | int? | optional | The wait before trying again, taken from the Retry-After header. |
Returns — a new EmbedRefusal.
Errors — none.
EmbedRefusal.of
Use it to read a refusal from an answer's status, body and Retry-After.
Null for a 2xx.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
status | int | required | The answer's HTTP status; a 2xx gives null. |
body | Map<String, Object?> | required | Its body, decoded from JSON. |
retryAfter | String? | optional | Its Retry-After header, in seconds; null when absent. |
Returns — EmbedRefusal?. Example value: null.
Errors — none.
Error codes and their fixes
Use it to look up any code: what it means, which calls raise it, and what to do.
A method that asks Graine on the customer's behalf fails with one error type carrying a code. Branch on the code; show the message, which is written for the customer. Errors never carry the identifier, traits or a push token.
| Code | In this SDK | HTTP | Means | Raised by | Fix |
|---|---|---|---|---|---|
invalid_key | invalidKey | 401 | The publishable key is not one, or belongs to no agent | Every request to Graine | Copy the key again from Agent → Embed & Widgets → Install |
origin_refused | originRefused | 403 | The app or site is not allowed: app:// (apps) or the site's host is missing from Allowed domains | Every request | Add app://, or the exact host |
rate_limited | rateLimited | 429 | Too many requests from this install, key or address | Every request | Wait retryAfterSeconds (the Retry-After header), then retry |
invalid_request | invalidRequest | 400 | A field is missing or malformed — a time without its offset, a reason over 120 characters | scheduleCall, device registration | Fix the request (Flutter refuses a long reason on the device) |
identity_required | identityRequired | 400 | No customer is identified, or the identifier is a placeholder | memories, forgetMemory, bookings that need a customer | identify() with the identifier first |
device_limit | deviceLimit | 403 | This install is not one of the customer's allowed devices | memories, forgetMemory, newConversation, scheduleCall | Sign out on another device, raise Devices per user, or Reset devices for the customer |
scheduling_off | schedulingOff | 403 (0 on the device) | Users, from your app is off | scheduleCall | Turn it on, or hide booking when usersCanBook is false |
too_soon | tooSoon | 400 (0 on the device) | Earlier than earliest(now) | scheduleCall | Offer times from earliest(now) |
too_far | tooFar | 400 (0 on the device) | Later than latest(now) | scheduleCall | Offer times up to latest(now) |
outside_window | outsideWindow | 400 | Outside the agent's Calling Window (or, for agent and team bookings, inside quiet hours), in the customer's time zone | scheduleCall, agent and dashboard bookings | Show the message (it names a time that works); offer another time |
too_many_pending | tooManyPending | 409 | The customer already has the most calls waiting | scheduleCall | Cancel one first |
not_found | notFound | 404 | No such booking for this customer or install | cancelScheduledCall | Refresh scheduledCalls() |
unavailable | unavailable | 503 (504 on a timeout) | Graine could not answer just now — including a booking refused because the agent is switched off or out of credit | Every request | Retry with backoff; check the agent is on and the workspace has credit |
network | network | — | No answer came back: offline, or the connection dropped | Every request | Retry when online |
unknown | unknown | other | A code newer than the SDK, or an unexpected answer (carrying its word) | Every request | Log the code and message; show the message |
When the bar or the chat cannot start, the reason reaches GraineListener.onError as a sentence for you, never as a coded exception and never shown to the customer: a key Graine rejected ("Publishable key was rejected. Check it against Embed & Widgets in the dashboard."), an agent that does not accept the app ("This agent does not accept connections from a mobile app yet. Add "app://" to its Allowed domains in the dashboard, under Embed & Widgets."), Graine out of reach ("Could not reach the agent — the request timed out. Check the connection and baseUrl."), high-quality audio not enabled for the workspace (the call falls back to the standard path), "A call is already in progress." while a native call is live, or a start with no GraineEngine on screen. A refused microphone arrives as onMicDenied('NotAllowedError') (NotFoundError for no usable microphone). Native calls configured wrongly fail GraineCalls.configure with an ArgumentError, or a PlatformException with the code invalid_options naming the option.
Rate limits and quotas
Use it to know the limits a busy app or customer can reach, and where each applies.
| Limit | Value | Where it applies |
|---|---|---|
| Bookings from one install | 10 an hour | scheduleCall, and the agent's bookings in that install's conversations |
| Bookings in a workspace | 1,000 an hour | All in-app bookings |
| Calls waiting per customer | 3 by default (1–10) | At most this many upcoming calls per user |
| Devices per customer | 2 by default (1–5) | Devices per user; idle devices free their place after 30 days |
| Rings per customer per day | 3 by default (1–10) | Ring each user at most, in the customer's own day |
| Quiet period after a decline | 6 hours | No ring for that customer |
| Notice and horizon | 5 minutes (2–1440) · 14 days (1–30) | With at least this much notice · Booked at most this far ahead |
| Ring time · re-ring | 45 s (20–60) · once after 10 min (0–120) | Ring for · After a missed call, ring once more after |
| Lateness | 10 minutes | A booked call more than 10 minutes late is not rung; credit and agent holds last at most 10 minutes |
| Booking reason · variables | 120 characters · 12 variables, about 1 KB — past that, the biggest are left off first, who_called and call_reason last | Bookings and calls |
| Memories listed | At most 100, newest first | memories() |
| Conversation kept | 50 messages, 7 days after the last | Conversations continue (since 0.7.0) |
| Requests per key and address, per minute | Starting a conversation 30 (and 300 per key); high-quality audio sessions 10 (120 per key); booking, listing, cancelling, device registration, memory list and sign-out 30 (300 per key); call outcomes 60 (600 per key); forgetting memory 10 (120 per key); listing memories also 30 per install | Answered rate_limited with Retry-After |
| Action handlers · component data | 6 seconds · 8 seconds | After that, the agent is told the action did not finish; a component shows its authored content |
Lower-level building blocks
Exports an integration rarely needs: the engine page and its messages, the chat connection and its frames, the context the agent reads, and the helpers the SDK's own views are built from. They are public so a fully custom surface, or a test, can reuse exactly what the SDK does — each with the same rules as every other Graine SDK.
GraineEnginePage
Implement it only to carry the voice call in a page of your own; GraineEngine builds the SDK's.
abstract class GraineEnginePage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
Its functions: bind, load, reload, run, dispose — each with its parameters, what it returns, the errors it raises and an example.
GraineEnginePage.bind
Called once by the call, before anything else, with where to report what happens to the page.
GraineVoice.attach calls this once, ahead of everything else; from then on the page reports everything that happens to it through sink.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
sink | GraineEngineSink | required | Where to report what happens to the page. |
Returns — nothing; it returns when done.
Errors — none.
GraineEnginePage.load
Called by the call to load the engine page.
Load the engine page.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
url | String | required | The engine page's address (Protocol.engineUrl). |
Returns — nothing; it returns when done.
Errors — none.
GraineEnginePage.reload
Called by the call to reload the engine page.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineEnginePage.run
Called by the call to run a script in the page.
Evaluate JavaScript in the page.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
javaScript | String | required | The script to run (Protocol.deliver builds one). |
Returns — nothing; it returns when done.
Errors — none.
GraineEnginePage.dispose
Called by the call to tear the page down.
Tears the page down, after which nothing the page does reaches the call.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineEngineSink
Use it, in a page of your own, to report everything that happens to the page to the call.
class GraineEngineSink
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
Its functions: pageStarted, progress, pageFinished, mainFrameError, message, microphoneRequested — each with its parameters, what it returns, the errors it raises and an example.
GraineEngineSink.pageStarted
Call it when the page starts loading.
A navigation began (a load, or a reload).
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineEngineSink.progress
Call it as the page downloads.
Download progress, 0–100.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
percent | int | required | How much has downloaded, 0–100. |
Returns — nothing; it returns when done.
Errors — none.
GraineEngineSink.pageFinished
Call it when the page has downloaded.
The document finished downloading.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineEngineSink.mainFrameError
Call it when the page could not load.
Reports that the main frame did not load — because of a network error, an HTTP error or a renderer that crashed.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
reason | String | required | Why the page could not load, in a few words. |
Returns — nothing; it returns when done.
Errors — none.
GraineEngineSink.message
Call it with every message the page sends.
Receives a message the page posted to window.ReactNativeWebView, one at a time.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | String? | required | The message, as the page posted it. |
Returns — nothing; it returns when done.
Errors — none.
GraineEngineSink.microphoneRequested
Call it when the page asks for the microphone, to know whether to grant it.
The page asks for capture devices.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
onlyMicrophone | bool | required | The page asked for the microphone alone (not the camera) — the only request ever granted. |
Returns — bool. Example value: true.
Errors — none.
WebViewEnginePage
Use it as the engine page built on webview_flutter — what GraineEngine uses.
class WebViewEnginePage implements GraineEnginePage
What to expect — Built by GraineEngine — build one yourself only for an engine of your own. It never navigates away from Graine's host, grants the page the microphone only when the app holds it, and with debug logs the page's console.
| Property | Type | Meaning |
|---|---|---|
late final WebViewController controller | WebViewController | The WebView's controller, for WebViewWidget. |
Its functions: WebViewEnginePage — each with its parameters, what it returns, the errors it raises and an example.
WebViewEnginePage.WebViewEnginePage
Use it to make the engine page yourself, for an engine of your own.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
baseUrl | String | required | Graine's address (GraineConfig.baseUrl); the page never navigates away from its host. |
debug | bool | false | Log the page's console (prefixed [Graine] page console) and make the page inspectable in the platform's web inspector. |
Returns — a new WebViewEnginePage.
Errors — none.
Protocol
Use it to speak to the engine page exactly as the SDK does: its address, its messages and the variables it carries.
abstract final class Protocol
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
static const String bridgeName | String | The name the page looks for. |
static const int actionDeadlineMs | int | The time an action handler has to finish; after it, the agent hears the action was not done. |
static const int ticketMaxKeys | int | Caps on the variables a ticket can carry, needed because the ticket is sent in a subprotocol header. |
static const int ticketMaxKeyLength | int | A variable's name is cut to 40 characters on a ticket. |
static const int ticketMaxValueLength | int | A variable's value is cut to 200 characters on a ticket. |
static const int ticketMaxBytes | int | A ticket carries about 1 KB of variables; past that, the biggest are left off first, one at a time, ticketFirstKeys last. |
static const List<String> ticketFirstKeys | List<String> | ['who_called', 'call_reason'] — why a call is happening. A ticket carries them first, and leaves them off last when the variables pass its kilobyte. New in 0.9.0. |
Its functions: engineUrl, deliver, out, toJson, parse, decodeJson, contextToken, ticketMetadata, trimTrailingSlashes — each with its parameters, what it returns, the errors it raises and an example.
Protocol.engineUrl
Use it to get the engine page's address for an agent.
The engine page's URL.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
baseUrl | String | required | "https://www.graine.ai" unless your workspace is self-hosted. |
voiceAgentId | String | required | The agent's ID for calls. |
transport | Transport | required | How a call's audio travels: the standard path or high quality (WebRTC); left out, the dashboard decides. |
cacheKey | String | required | The cache key. |
idle | bool | required | Whether it is idle. |
publishableKey | String | required | The agent's publishable key, pk_live_…, from Agent → Embed & Widgets → Install. |
accent | String? | optional | The accent colour, #RRGGBB. |
Returns — String. Example value: 'https://www.graine.ai/embed/agent_123_web?mode=voice&branding=0&embed=1&transport=ws&b=1&idle=1&pk=pk_live_…'.
Errors — none.
Protocol.deliver
Use it to get the script that hands the page one message.
Builds the JavaScript that hands a single message to the page.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | Map<String, Object?> | required | The message (Protocol.out builds one). |
Returns — String. Example value: 'window.postMessage({"type":"graine:set-muted","muted":true}, "*"); true;'.
Errors — none.
Protocol.out
Use it to build one message for the page.
Assembles a message to send, shaped {type, ...fields}, after making each value safe for JSON.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
type | String | required | The message's type (ProtocolOut.startCall, …). |
fields | Map<String, Object?> | const <String, Object?>{} | Its other fields, made JSON-safe. |
Returns — Map<String, Object?>. Example value: {'type': 'graine:set-muted', 'muted': true}.
Errors — none.
Protocol.toJson
Use it to turn any value into what JSON can carry, as the SDK does.
Dart values → JSON values, recursively.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
v | Object? | required | Any value. |
Returns — Object?. Example value: null.
Errors — none.
Protocol.parse
Use it to read one message from the page.
Parse one message from the page.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | String? | required | One message, as the page posted it. |
Returns — PageMessage? — its fields: PageMessage. Example value: null.
Errors — none.
Protocol.decodeJson
Use it to read JSON the way the SDK does.
Decodes a socket frame, given as text or UTF-8 bytes, into JSON.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | Text, or UTF-8 bytes. |
Returns — Object?. Example value: null.
Errors — none.
Protocol.contextToken
Use it to build the variables' token a direct connection carries in its address.
The variables as a connection without a ticket carries them, in its address (?context_token=): base64 of the UTF-8 JSON of the values — nulls, maps and lists dropped, everything else as text — with call_type added at the top and again under recipient_data. Null when there is nothing to carry. A ticketed connection never carries it: its variables ride the ticket (ticketMetadata) — since 0.8.0 for the chat too.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
variables | Map<String, Object?>? | required | The prompt variables. |
callType | String | 'webcall' | What the conversation is filed under: webcall for a call, text_chat for the chat. |
Returns — String?. Example value: 'eyJwbGFuIjoiUHJvIiwiY2FsbF90eXBlIjoidGV4dF9jaGF0IiwicmVjaXBpZW50X2RhdGEiOnsicGxhbiI6IlBybyIsImNhbGxfdHlwZSI6InRleHRfY2hhdCJ9fQ=='.
Errors — none.
Protocol.ticketMetadata
Use it to get the variables that ride a ticket, cut to the ticket's limits.
The variables a ticket carries: the first 12 usable values — who_called and call_reason (ticketFirstKeys) first, then the rest in order — names cut to 40 characters and values to 200, trimmed to fit a kilobyte (counted in UTF-8 bytes): the biggest are left off first, one at a time (the later of two the same size), and who_called and call_reason only when nothing else is left. Null when nothing is left to carry. Until 0.9.0 a set over the kilobyte lost every variable. A call's and, since 0.8.0, a chat's variables reach a ticketed connection this way only; they are no longer added to its address.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
variables | Map<String, Object?>? | required | The prompt variables. |
Returns — Map<String, String>?. Example value: {'plan': 'Pro'} (a list is dropped).
Errors — none.
Protocol.trimTrailingSlashes
Use it to drop the slashes at the end of an address.
baseUrl without its trailing slashes.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
s | String | required | An address. |
Returns — String. Example value: 'https://www.graine.ai'.
Errors — none.
ProtocolOut
Use its names for the messages the SDK sends into the engine page.
abstract final class ProtocolOut
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
static const String startCall | String | 'graine:start-call' — start the call. |
static const String endCall | String | 'graine:end-call' — hang up. |
static const String setMuted | String | 'graine:set-muted' — mute or unmute. |
static const String warm | String | 'graine:warm' — get ready, so a tap starts the call at once. |
static const String variables | String | 'graine:variables' — the prompt variables. |
static const String appContext | String | 'graine:app-context' — the screen context. |
static const String appActionResult | String | 'graine:app-action-result' — the answer to an action. |
static const String appEvent | String | 'graine:app-event' — something the agent may speak up about. |
static const String widgetResult | String | 'graine:widget-result' — the answer to a component. |
static const String identity | String | 'graine:identity' — who the customer is, for the tickets the page asks for: {value, installId, memory, timezone}, value null for an anonymous customer. |
ProtocolIn
Use its names for the messages the engine page sends out.
abstract final class ProtocolIn
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
static const String ready | String | 'graine:ready' — the page is ready to start a call. |
static const String call | String | 'graine:call' — the call connected, is connecting or ended. |
static const String muted | String | 'graine:muted' — muted or unmuted. |
static const String caption | String | 'graine:caption' — a caption line. |
static const String widget | String | 'graine:widget' — a component the agent drew. |
static const String widgetPending | String | 'graine:widget-pending' — a component on its way. |
static const String appAction | String | 'graine:app-action' — an action the agent asks for. |
static const String ended | String | 'graine:ended' — the call ended. |
static const String micDenied | String | 'graine:mic-denied' — the microphone was refused. |
static const String transport | String | 'graine:transport' — which way the audio travels. |
static const String quality | String | 'graine:quality' — a connection measurement. |
static const String network | String | 'graine:network' — online or offline. |
static const String reconnecting | String | 'graine:reconnecting' — the call is being re-established. |
static const String progress | String | 'graine:progress' — where a connect is: {stage} — registering, dialling, retrying, switching, or failed. |
PageMessage
Read it as one message from the engine page, typed — Protocol.parse makes them.
sealed class PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
Its functions: PageMessage — each with its parameters, what it returns, the errors it raises and an example.
PageMessage.PageMessage
The base constructor of the page's messages; you never call it directly.
Parameters — none.
Returns — nothing you call directly: PageMessage is sealed: messages come from Protocol.parse.
Errors — none.
PageReady
Read it as the page's word that it is ready to start a call.
final class PageReady extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
Its functions: PageReady — each with its parameters, what it returns, the errors it raises and an example.
PageReady.PageReady
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
Parameters — none.
Returns — a new PageReady.
Errors — none.
PageCall
Read it as the page's word that the call connected, started connecting, or ended.
final class PageCall extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final bool connected | bool | The call is connected. |
final bool connecting | bool | The call is connecting. |
Its functions: PageCall — each with its parameters, what it returns, the errors it raises and an example.
PageCall.PageCall
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
connected | bool | required | The call is connected. |
connecting | bool | required | The call is connecting. |
Returns — a new PageCall.
Errors — none.
PageMuted
Read it as the page's word that the call was muted or unmuted.
final class PageMuted extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final bool muted | bool | True: muted. |
Its functions: PageMuted — each with its parameters, what it returns, the errors it raises and an example.
PageMuted.PageMuted
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
muted | bool | required | True: muted. |
Returns — a new PageMuted.
Errors — none.
PageCaption
Read it as one caption line from the page.
final class PageCaption extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final Role role | Role | Who said it. |
final String text | String | The words so far. |
final bool live | bool | Still being said or recognised. |
Its functions: PageCaption — each with its parameters, what it returns, the errors it raises and an example.
PageCaption.PageCaption
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
role | Role | required | Who said it. |
text | String | required | The words so far. |
live | bool | required | Still being said or recognised. |
Returns — a new PageCaption.
Errors — none.
PageWidget
Read it as a component the agent drew, from the page.
final class PageWidget extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final Map<String, Object?> widget | Map<String, Object?> | The component as sent; GraineWidget.adopt reads it. |
Its functions: PageWidget — each with its parameters, what it returns, the errors it raises and an example.
PageWidget.PageWidget
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widget | Map<String, Object?> | required | The component as sent; GraineWidget.adopt reads it. |
Returns — a new PageWidget.
Errors — none.
PageWidgetPending
Read it as the page's word that a component is on its way.
final class PageWidgetPending extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final Map<String, Object?> widget | Map<String, Object?> | What is known of the coming component. |
Its functions: PageWidgetPending — each with its parameters, what it returns, the errors it raises and an example.
PageWidgetPending.PageWidgetPending
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widget | Map<String, Object?> | required | What is known of the coming component. |
Returns — a new PageWidgetPending.
Errors — none.
PageAppAction
Read it as an action the agent asks your app to do, from the page.
final class PageAppAction extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final String actionId | String | The request's id; the answer carries it back. |
final String name | String | The action's name, as you registered it. |
final Map<String, Object?> arguments | Map<String, Object?> | The action's arguments. |
Its functions: PageAppAction — each with its parameters, what it returns, the errors it raises and an example.
PageAppAction.PageAppAction
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
actionId | String | required | The request's id; the answer carries it back. |
name | String | required | The action's name, as you registered it. |
arguments | Map<String, Object?> | required | The action's arguments. |
Returns — a new PageAppAction.
Errors — none.
PageEnded
Read it as the page's word that the call ended.
final class PageEnded extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
Its functions: PageEnded — each with its parameters, what it returns, the errors it raises and an example.
PageEnded.PageEnded
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
Parameters — none.
Returns — a new PageEnded.
Errors — none.
PageMicDenied
Read it as the page's word that the microphone was refused.
final class PageMicDenied extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final String reason | String | NotAllowedError (refused) or NotFoundError (no usable microphone). |
Its functions: PageMicDenied — each with its parameters, what it returns, the errors it raises and an example.
PageMicDenied.PageMicDenied
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
reason | String | required | NotAllowedError (refused) or NotFoundError (no usable microphone). |
Returns — a new PageMicDenied.
Errors — none.
PageTransport
Read it as the page's word on which way the audio travels, and why.
final class PageTransport extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final Transport transport | Transport | The way the audio really travels. |
final Transport requested | Transport | The way that was asked for. |
final String? reason | String? | Why they differ, in one word; null when they do not. |
final String? message | String? | Why, in a sentence; null when nothing went wrong. |
Its functions: PageTransport — each with its parameters, what it returns, the errors it raises and an example.
PageTransport.PageTransport
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
transport | Transport | required | The way the audio really travels. |
requested | Transport | required | The way that was asked for. |
reason | String? | optional | Why they differ, in one word; null when they do not. |
message | String? | optional | Why, in a sentence; null when nothing went wrong. |
Returns — a new PageTransport.
Errors — none.
PageQuality
Read it as one connection measurement from the page.
final class PageQuality extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final double? rttMs | double? | Round-trip time, in ms; null when not measured. |
final double? jitterMs | double? | Jitter, in ms; null when not measured. |
final double? loss | double? | Packet loss as a fraction (0.02 is 2%); null when not measured. |
Its functions: PageQuality — each with its parameters, what it returns, the errors it raises and an example.
PageQuality.PageQuality
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
rttMs | double? | optional | Round-trip time, in ms; null when not measured. |
jitterMs | double? | optional | Jitter, in ms; null when not measured. |
loss | double? | optional | Packet loss as a fraction (0.02 is 2%); null when not measured. |
Returns — a new PageQuality.
Errors — none.
PageNetwork
Read it as the page's word that the device went offline or came back.
final class PageNetwork extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final bool online | bool | True: the device is online. |
Its functions: PageNetwork — each with its parameters, what it returns, the errors it raises and an example.
PageNetwork.PageNetwork
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
online | bool | required | True: the device is online. |
Returns — a new PageNetwork.
Errors — none.
PageReconnecting
Read it as the page's word that the call is being re-established, or is back.
final class PageReconnecting extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final bool active | bool | True while the call is being re-established. |
Its functions: PageReconnecting — each with its parameters, what it returns, the errors it raises and an example.
PageReconnecting.PageReconnecting
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
active | bool | required | True while the call is being re-established. |
Returns — a new PageReconnecting.
Errors — none.
PageProgress
Read it as the page's word on where a call being placed is.
final class PageProgress extends PageMessage
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
final String stage | String | The stage as sent: registering, dialling, retrying, switching or failed. |
bool get failed | bool | True when no transport could carry the call, so connecting should stop. |
Its functions: PageProgress — each with its parameters, what it returns, the errors it raises and an example.
PageProgress.PageProgress
Use it to build the message by hand for a test; Protocol.parse makes the real ones.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
stage | String | required | The stage as sent: registering, dialling, retrying, switching or failed. |
Returns — a new PageProgress.
Errors — none.
LoadWatchdog
Use it to tell a slow engine page from a stuck one, as the SDK does.
class LoadWatchdog
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final int stallMs | int | How long nothing may arrive before the load is stalled, in ms. |
final int bootMs | int | How long a downloaded page may take to be ready, in ms. |
final int hardCapMs | int | The ceiling on one load, in ms. |
Its functions: LoadWatchdog, start, progress, loaded, check, nextCheckInMs — each with its parameters, what it returns, the errors it raises and an example.
LoadWatchdog.LoadWatchdog
Use it to make a watchdog with its three limits.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
stallMs | int | 15000 | How long nothing may arrive before the load is stalled, in ms. |
bootMs | int | 15000 | How long a downloaded page may take to be ready, in ms. |
hardCapMs | int | 120000 | The ceiling on one load, in ms. |
Returns — a new LoadWatchdog.
Errors — none.
LoadWatchdog.start
Call it when a load starts.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
LoadWatchdog.progress
Call it as the page downloads.
Progress 0–100 from the WebView.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
percent | int | required | How much has downloaded, 0–100. |
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
LoadWatchdog.loaded
Call it when the page has downloaded.
Marks the page as downloaded; from now on it is starting up rather than fetching.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — nothing; it returns when done.
Errors — none.
LoadWatchdog.check
Call it to know whether to keep waiting.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — LoadVerdict — its fields: LoadVerdict. Example value: LoadVerdict.wait.
Errors — none.
LoadWatchdog.nextCheckInMs
Use it to know when to check again.
How soon to check again — whichever of the two limits comes first.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
now | int | required | The time now, in milliseconds since the epoch — DateTime.now().millisecondsSinceEpoch; a test passes its own. |
Returns — int. Example value: 3.
Errors — none.
LoadVerdict
Read it as what the load watchdog concluded.
enum LoadVerdict
What to expect — Give every switch over it a default case.
| Case | Meaning |
|---|---|
wait('wait') | Still moving: keep waiting. |
stalled('stalled') | Nothing has arrived for stallMs: a dead connection — reload. |
bootTimeout('boot_timeout') | Everything arrived but the page never said it was ready within bootMs: broken, not slow — reload. |
loadCap('load_cap') | The load ran past hardCapMs however steadily it arrived — reload. |
| Property | Type | Meaning |
|---|---|---|
final String reason | String | The verdict as one word, as onConnectivity reports it. |
Its functions: LoadVerdict — each with its parameters, what it returns, the errors it raises and an example.
LoadVerdict.LoadVerdict
The enum's constructor; use the values (LoadVerdict.wait, …).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
reason | String | required | The verdict as one word, as onConnectivity reports it. |
Returns — nothing you call: an enum's constructor runs once for each value. Use the values; each carries its word in wire (here reason).
Errors — none.
RetryLadder
Use it to space out reloads of a page that failed, and to know when to stop.
class RetryLadder
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
int get attempt | int | Reloads scheduled so far. |
bool get exhausted | bool | True once every delay is spent: stop and say so. |
Its functions: RetryLadder, next, reset — each with its parameters, what it returns, the errors it raises and an example.
RetryLadder.RetryLadder
Use it to make a ladder with its delays.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
delaysMs | List<int> | const <int>[1000, 2000, 4000, 8000, 15000, 15000] | The waits between reloads, in ms; each is jittered by ±25%, and their number is how many reloads are tried. |
random | double Function()? | optional | Where the jitter comes from, 0–1; the platform's random when left out. |
Returns — a new RetryLadder.
Errors — none.
RetryLadder.next
Use it to get the wait before the next attempt.
Returns how long to wait before the next try, or null once all attempts are used up.
Parameters — none.
Returns — int?. Example value: 3.
Errors — none.
RetryLadder.reset
Call it to start the ladder over.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineChatSocket
Implement it only to carry the chat on a connection of your own.
abstract class GraineChatSocket
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
Stream<Object?> get frames | Stream<Object?> | Each frame as it comes in; the stream completes when the socket closes. |
Its functions: send, close — each with its parameters, what it returns, the errors it raises and an example.
GraineChatSocket.send
Called by the chat to send one frame.
Put one text frame on the wire.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | String | required | One frame, as JSON text. |
Returns — nothing; it returns when done.
Errors — none.
GraineChatSocket.close
Called by the chat to close the connection.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
GraineChatConnector
Implement it only to open the chat's connection yourself — for a test.
typedef GraineChatConnector = Future<GraineChatSocket> Function(Uri url, List<String>? protocols);
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
ChatWire
Use its constants and frames to speak the chat's protocol exactly as the SDK does.
abstract final class ChatWire
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
static const String subprotocol | String | The subprotocol a ticketed chat connection asks for: 'graine.embed.v1'. The ticket travels beside it, never in the address. |
static const int pingMs | int | How often the chat sends a keep-alive, in ms: 25 000. |
static const int openTimeoutMs | int | If the socket is not open within this time, the attempt is abandoned. |
static const int stopGraceMs | int | The time allowed for stop to be sent before the socket is closed. |
static const String client | String | Who this client is, in the chat's first frame: 'graine-flutter-sdk', filed with the conversation. |
static const String defaultWsHost | String | Where a direct chat connects when the session names no host: 'wss://ws.graine.ai'. |
static const String callType | String | The call_type value under which a text conversation is recorded. |
static const Map<String, Object?> ping | Map<String, Object?> | The keep-alive frame: {'type': 'ping'}. |
static const Map<String, Object?> stop | Map<String, Object?> | The frame that hangs up properly, so the record shows the conversation ended instead of being abandoned. |
Its functions: directUrl, withContextToken, init, text, widgetResult, actionResult, appContext, appEvent — each with its parameters, what it returns, the errors it raises and an example.
ChatWire.directUrl
Use it to get the address of a chat that connects directly, without a ticket.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
wsHost | String? | required | The session's host (session.wsHost); the default host when null. |
agentId | String | required | The agent's id. |
Returns — String. Example value: 'wss://ws.graine.ai/chat/v1/agent_123?text_chat=1'.
Errors — none.
ChatWire.withContextToken
Use it to add the variables' token to a direct chat's address.
url with the variables' context_token added, when there is one. Since 0.8.0 only a chat without a ticket uses it: a ticketed chat's variables ride its ticket.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
url | String | required | A direct chat's address. |
token | String? | required | The variables' token (Protocol.contextToken); null leaves the address as it is. |
Returns — String. Example value: 'wss://ws.graine.ai/chat/v1/agent_123?text_chat=1&context_token=eyJwbGFuIjoiUHJvIiwiY2FsbF90eXBlIjoidGV4dF9jaGF0IiwicmVjaXBpZW50X2RhdGEiOnsicGxhbiI6IlBybyIsImNhbGxfdHlwZSI6InRleHRfY2hhdCJ9fQ%3D%3D'.
Errors — none.
ChatWire.init
Use it to build the chat's first frame.
Builds the opening frame — a start — which carries the variables for the record.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
variables | Map<String, String> | required | The prompt variables, already merged and masked. |
Returns — a new ChatWire.
Errors — none.
ChatWire.text
Use it to build one message from the customer.
One customer turn.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
data | String | required | The customer's message. |
Returns — Map<String, Object?>. Example value: {'type': 'text', 'data': 'Where is my order?'}.
Errors — none.
ChatWire.widgetResult
Use it to build the answer to a component.
The structured answer to a component.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widgetId | String | required | The component answered. |
data | Map<String, Object?> | required | The structured answer. |
Returns — Map<String, Object?>.
Errors — none.
ChatWire.actionResult
Use it to build the answer to an action.
The answer to an app_action, always given.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
actionId | String | required | The request's id (ChatAction.actionId). |
r | ActionResult | required | What the action answered. |
Returns — Map<String, Object?>.
Errors — none.
ChatWire.appContext
Use it to build the screen context for the chat.
A context frame — {context, availableActions?, seq}, as the SDK builds it — in the chat's own spelling (available_actions).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
frame | Map<String, Object?> | required | The screen context (ContextFrame.build). |
Returns — Map<String, Object?>.
Errors — none.
ChatWire.appEvent
Use it to build an event the agent may speak up about.
Builds an event the agent might want to comment on, or, when it is quiet, only needs to know about.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The event's name. |
detail | String? | optional | A sentence about it; null for none. |
data | Map<String, Object?> | const <String, Object?>{} | Facts about it. |
Returns — Map<String, Object?>.
Errors — none.
AgentChunk
Read it as one piece of the agent's words, and what it says about the agent's turn.
class AgentChunk
What to expect — The SDK sends and reads these for you; they are public so a custom UI can reuse them.
| Property | Type | Meaning |
|---|---|---|
static const String streamStart | String | The marker that opens an agent's turn: '<beginning_of_stream>'. It is never shown. |
static const String streamEnd | String | The marker that ends an agent's turn: '<end_of_stream>'. A reply ends there — one bubble per reply. |
final String text | String | What the customer should see. |
final bool startsTurn | bool | The frame opened the agent's turn. |
final bool endsTurn | bool | The frame ended the agent's turn: the next words open a new bubble. |
Its functions: AgentChunk, read — each with its parameters, what it returns, the errors it raises and an example.
AgentChunk.AgentChunk
Use it to build a piece by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String | required | What the customer should see. |
startsTurn | bool | false | The frame opened the agent's turn. |
endsTurn | bool | false | The frame ended the agent's turn: the next words open a new bubble. |
Returns — a new AgentChunk.
Errors — none.
AgentChunk.read
Use it to read one text frame into the words to show and the turn markers.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | One text frame's data, as received. |
Returns — AgentChunk.
Errors — none.
ChatFrame
Read it as one frame from the chat's connection, typed.
sealed class ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
Its functions: ChatFrame, parse — each with its parameters, what it returns, the errors it raises and an example.
ChatFrame.ChatFrame
The base constructor of the chat's frames; you never call it directly.
Parameters — none.
Returns — nothing you call directly: ChatFrame is sealed: frames come from ChatFrame.parse.
Errors — none.
ChatFrame.parse
Use it to read one frame from the chat's connection.
Parses a single socket frame, returning null for anything that is not one of the chat's own frames.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | Object? | required | One frame, as received (text or UTF-8 bytes). |
Returns — ChatFrame?. Example value: null.
Errors — none.
ChatText
Read it as the agent's words, or a turn marker.
final class ChatText extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final AgentChunk chunk | AgentChunk | The words, with the turn markers already taken out. |
Its functions: ChatText — each with its parameters, what it returns, the errors it raises and an example.
ChatText.ChatText
Use it to build a text frame by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
chunk | AgentChunk | required | The words, with the turn markers already taken out. |
Returns — a new ChatText.
Errors — none.
ChatWidget
Read it as a component the agent drew in the chat.
final class ChatWidget extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final Map<String, Object?> widget | Map<String, Object?> | The component as Graine sent it; GraineWidget.adopt reads it. |
Its functions: ChatWidget — each with its parameters, what it returns, the errors it raises and an example.
ChatWidget.ChatWidget
Use it to build a component frame by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
widget | Map<String, Object?> | required | The component as Graine sent it; GraineWidget.adopt reads it. |
Returns — a new ChatWidget.
Errors — none.
ChatWidgetPending
Read it as a component on its way.
final class ChatWidgetPending extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final Map<String, Object?> hint | Map<String, Object?> | What is known of the coming component — its id and kind. |
Its functions: ChatWidgetPending — each with its parameters, what it returns, the errors it raises and an example.
ChatWidgetPending.ChatWidgetPending
Use it to build a component-on-its-way frame by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
hint | Map<String, Object?> | required | What is known of the coming component — its id and kind. |
Returns — a new ChatWidgetPending.
Errors — none.
ChatAction
Read it as something the agent asks your app to do in the chat.
final class ChatAction extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final String actionId | String | The request's id; the answer (ChatWire.actionResult) carries it back. |
final String name | String | The action's name, as you registered it. |
final Map<String, Object?> arguments | Map<String, Object?> | The action's arguments, as JSON values. |
Its functions: ChatAction — each with its parameters, what it returns, the errors it raises and an example.
ChatAction.ChatAction
Use it to build an action frame by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
actionId | String | required | The request's id; the answer (ChatWire.actionResult) carries it back. |
name | String | required | The action's name, as you registered it. |
arguments | Map<String, Object?> | required | The action's arguments, as JSON values. |
Returns — a new ChatAction.
Errors — none.
ChatStream
Read it as an explicit start or end of the agent's turn.
final class ChatStream extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final bool start | bool | True for the start of the agent's turn, false for its end. |
Its functions: ChatStream — each with its parameters, what it returns, the errors it raises and an example.
ChatStream.ChatStream
Use it to build a turn marker by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
start | bool | required | True for the start of the agent's turn, false for its end. |
Returns — a new ChatStream.
Errors — none.
ChatClear
Read it as the agent's turn being cut off.
final class ChatClear extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
Its functions: ChatClear — each with its parameters, what it returns, the errors it raises and an example.
ChatClear.ChatClear
Use it to build a cut-off frame by hand for a test.
Parameters — none.
Returns — a new ChatClear.
Errors — none.
ChatHistory
Read it as the earlier conversation the chat restores when an identified customer comes back.
final class ChatHistory extends ChatFrame
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final List<GraineChatTurn> turns | List<GraineChatTurn> | The restored messages, oldest first — possibly none. Each is restored, delivered and never live. |
Its functions: ChatHistory — each with its parameters, what it returns, the errors it raises and an example.
ChatHistory.ChatHistory
Use it to build a restored conversation by hand for a test.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
turns | List<GraineChatTurn> | required | The restored messages, oldest first — possibly none. Each is restored, delivered and never live. |
Returns — a new ChatHistory.
Errors — none.
ChatHistoryReader
Use it to read a restored conversation exactly as the SDK does.
abstract final class ChatHistoryReader
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
Its functions: read, time — each with its parameters, what it returns, the errors it raises and an example.
ChatHistoryReader.read
Use it to read the turns of a restored conversation.
The turns a restored-conversation frame holds, oldest first, or null when its turns is not a list.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
frame | Map<String, Object?> | required | A restored-conversation frame. |
Returns — List<GraineChatTurn>?. Example value: [].
Errors — none.
ChatHistoryReader.time
Use it to read one turn's time.
Reads an ISO-8601 time that has a zone, with or without fractions of a second, and returns it in UTC; the server writes UTC with a Z.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
raw | String | required | A time with its zone, ISO-8601. |
Returns — DateTime?. Example value: null.
Errors — none.
ChatTranscript
Use it to turn the chat's frames into its turns exactly as the SDK does — one bubble per agent reply.
class ChatTranscript
What to expect — The chat's framing, as the SDK's own chat window uses it. Public so a chat window of your own can reuse it.
| Property | Type | Meaning |
|---|---|---|
final int max | int | The number of turns kept; when full, the oldest are dropped first. |
List<GraineChatTurn> get turns | List<GraineChatTurn> | Every turn kept, oldest first (at most max). Unmodifiable. |
List<Caption> get messages | List<Caption> | Each turn as a Caption, for windows built to show captions. |
bool get agentTyping | bool | True while the agent is preparing an answer and has not yet said any of it. |
List<GraineChatTurn> get pending | List<GraineChatTurn> | The user's turns that have not been sent yet (still sending, or failed), oldest first. |
Its functions: agent, ChatTranscript, customer, sent, failPending, retryFailed, expectReply, turnStarted, component, turnEnded, closed, clear, opened, restore — each with its parameters, what it returns, the errors it raises and an example.
ChatTranscript.agent
Call it with each piece of the agent's words.
Words of the agent's turn.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
words | String | required | The words that arrived. |
at | DateTime | required | When. |
Returns — bool. Example value: true.
Errors — none.
ChatTranscript.ChatTranscript
Use it to make a transcript that keeps at most max turns.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
max | int | 200 | The number of turns kept; when full, the oldest are dropped first. |
Returns — a new ChatTranscript.
Errors — none.
ChatTranscript.customer
Call it when the customer sends a message.
The customer said text: whatever the agent was saying is over. With pending it is not on the wire yet — sent marks it when it goes.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String | required | What the customer typed. |
at | DateTime | required | When. |
pending | bool | false | Not sent yet (the chat is not connected); sent marks it when it goes. |
Returns — GraineChatTurn — its fields: GraineChatTurn.
Errors — none.
ChatTranscript.sent
Call it when a waiting message went out.
Marks the queued turn id as sent, so the agent now owes it an answer.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
id | String | required | The waiting message's id. |
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.failPending
Call it when the chat gave up connecting.
Called when the chat stops trying to connect; every turn waiting to go is marked as not sent, for now.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.retryFailed
Call it when the chat tries again.
Starts another attempt, putting every unsent turn back on its way.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.expectReply
Call it when the customer answered a component.
Records that the user answered a component, with the answer's sentence sent as their turn; the agent now owes a reply and is no longer in the middle of a turn.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.turnStarted
Call it when the agent's turn begins.
Handles the agent's start marker: a turn has begun and its words are coming.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.component
Call it when the agent drew a component.
Adds a component the agent drew. It joins the agent's turn in progress, or the last turn if that one is the agent's; otherwise it becomes a separate turn.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
c | GraineComponent | required | The component the agent drew. |
at | DateTime | required | When. |
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.turnEnded
Call it when the agent's turn is over.
Marks the agent's turn as finished; this happens on its end marker, on an explicit end, or when it is interrupted.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.closed
Call it when the connection closed.
Handles the socket closing: nothing more will arrive and no answer is owed.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.clear
Call it to forget everything.
Clears everything, for a different user or a deliberately started new conversation.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.opened
Call it when the connection opened.
Called when the connection opens, before any waiting turns are sent; whatever is settled at this point is what the next history will replace.
Parameters — none.
Returns — nothing; it returns when done.
Errors — none.
ChatTranscript.restore
Call it with a restored conversation.
Restores an earlier conversation: first its turns, then, in order, every turn the history does not include yet — those still sending or failed, and those said since the connection opened.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
restored | List<GraineChatTurn> | required | The restored messages, oldest first. |
Returns — bool. Example value: true.
Errors — none.
ContextFrame
Use it to build the screen context the agent reads, exactly as the SDK does.
abstract final class ContextFrame
What to expect — Built by the SDK every time the screen changes and masked before it leaves the device; public so a custom surface can send exactly what the agent reads.
Its functions: build, availableActions — each with its parameters, what it returns, the errors it raises and an example.
ContextFrame.build
Use it to build the context for a screen.
Returns the frame {context, availableActions?}, or null if there is nothing worth sending.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
screen | GraineScreen? | required | The screen now (setScreen); null for none. |
screenSinceMs | int | required | When the customer reached it, in ms since the epoch. |
nowMs | int | required | The time now, in ms since the epoch. |
identity | Map<String, String> | const <String, String>{} | The identity settings. |
appVersion | String? | optional | Your app's version; it lands on the call record. |
recentEvents | List<Map<String, Object?>> | const <Map<String, Object?>>[] | What the customer did lately (track, taps), newest last. |
registeredActions | List<String>? | optional | The actions this build registered; null sends the screen's list as stated. |
Returns — Map<String, Object?>?. Example value: null.
Errors — none.
ContextFrame.availableActions
Use it to work out which actions a screen offers the agent.
The actions a frame offers — see build.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
stated | List<String>? | required | The screen's own list (GraineScreen.availableActions); null for none. |
registered | List<String>? | required | The actions this build registered; null for no narrowing. |
Returns — List<String>?. Example value: [].
Errors — none.
ActionRegistry
Use it to register and run actions exactly as the SDK does — always answering the agent.
class ActionRegistry
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
final Duration deadline | Duration | The time a handler has to finish; after it, the agent hears the action was not done. |
List<String> get names | List<String> | Registered names, in registration order. |
Its functions: ActionRegistry, register, has, execute, describeError — each with its parameters, what it returns, the errors it raises and an example.
ActionRegistry.ActionRegistry
Use it to make a registry with its deadline.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
deadline | Duration | const Duration(milliseconds: Protocol.actionDeadlineMs) | How long a handler may take before the agent is told it was not done; 6 seconds by default. |
Returns — a new ActionRegistry.
Errors — none.
ActionRegistry.register
Use it to register an action.
Registers handler under name; the returned function unregisters it (only if it is still the one registered).
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name, as the dashboard declares it. |
handler | GraineActionHandler | required | What runs it. |
Returns — void Function().
Errors — none.
ActionRegistry.has
Use it to ask whether an action is registered.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name. |
Returns — bool. Example value: true.
Errors — none.
ActionRegistry.execute
Use it to run one action and get its answer.
Run one action.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
name | String | required | The action's name. |
args | Map<String, Object?> | required | Its arguments. |
onRequested | void Function(String name)? | optional | Called first, with the name. |
onCompleted | void Function(String name, ActionResult result)? | optional | Called once, with the answer the agent is given. |
Returns — Future<ActionResult> — its fields: ActionResult.
Errors — none.
ActionRegistry.describeError
Use it to turn an exception into the sentence the agent is given.
Turns an exception into the sentence passed to the agent.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
e | Object | required | What the handler threw. |
Returns — String. Example value: 'The coupon has expired.'.
Errors — none.
deepEquals
Use it to compare two JSON-like values by what they hold.
Compares JSON-like values (maps, lists and scalars) by structure.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
a | Object? | required | One value. |
b | Object? | required | The other. |
Returns — bool. Example value: true.
Errors — none.
deepHash
Use it to hash a JSON-like value consistently with deepEquals.
A hash consistent with deepEquals.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
v | Object? | required | A JSON-like value. |
Returns — int. Example value: 3.
Errors — none.
VariableStore
Use it to merge prompt variables from every place they come from, exactly as the SDK does.
class VariableStore
What to expect — Public so a custom UI can reuse it; an integration does not need it.
Its functions: VariableStore, setDashboardDefaults, setRuntime, setIdentity, identity, merged, flatten, flattenOne — each with its parameters, what it returns, the errors it raises and an example.
VariableStore.VariableStore
Use it to make a store with your build's variables.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
buildTime | Map<String, Object?> | const <String, Object?>{} | Your build's variables (GraineConfig.variables). |
Returns — a new VariableStore.
Errors — none.
VariableStore.setDashboardDefaults
Call it with the dashboard's defaults.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
values | Map<String, Object?> | required | The dashboard's defaults (session.variables). |
Returns — nothing; it returns when done.
Errors — none.
VariableStore.setRuntime
Call it with the app's runtime variables.
Merged over what is there.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
values | Map<String, Object?>? | required | The variables to merge in; a null value removes its variable, null clears them all. |
Returns — nothing; it returns when done.
Errors — none.
VariableStore.setIdentity
Call it with the customer's traits.
Who is signed in.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
traits | Map<String, Object?>? | required | The customer's traits; null on sign-out. |
Returns — nothing; it returns when done.
Errors — none.
VariableStore.identity
Use it to get the customer's traits as variables.
Who is signed in, masked.
Parameters — none.
Returns — Map<String, String>.
Errors — none.
VariableStore.merged
Use it to get every variable, merged.
Every variable, in precedence order.
Parameters — none.
Returns — Map<String, String>.
Errors — none.
VariableStore.flatten
Use it to turn values into the text variables carry.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
values | Map<String, Object?> | required | The values to turn into text. |
Returns — Map<String, String>. Example value: {'items': '3', 'total': '42'}.
Errors — none.
VariableStore.flattenOne
Use it to turn one value into the text a variable carries.
Converts a single value into the string a prompt will substitute, or returns null to leave it out.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
v | Object? | required | One value. |
Returns — String?. Example value: '42'.
Errors — none.
ScheduledCalls
Use it to read and write booked calls exactly as the SDK does.
abstract final class ScheduledCalls
What to expect — Public so a custom UI can reuse it; an integration does not need it.
| Property | Type | Meaning |
|---|---|---|
static const int maxReasonLength | int | The longest reason a booking carries. |
Its functions: atWire, parseTime, oneFrom, listFrom, statusAfterCancel — each with its parameters, what it returns, the errors it raises and an example.
ScheduledCalls.atWire
Use it to write a time as a booking sends it.
A time as a booking sends it: ISO-8601 with the device's own offset, to the second — 2026-10-14T18:00:00+05:30 (Z where the offset is zero), as every Graine SDK writes it.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
at | DateTime | required | The time to write. |
offset | Duration? | optional | The offset to write it with; the device's when left out. |
Returns — String. Example value: '2026-10-14T18:00:00+05:30' on a device in India.
Errors — none.
ScheduledCalls.parseTime
Use it to read a time Graine sent.
Parses an ISO-8601 string (or an epoch in milliseconds) into UTC, reading a string that has no zone as UTC; returns null for anything else.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
v | Object? | required | An ISO-8601 time with its zone, or milliseconds since the epoch. |
Returns — DateTime?. Example value: null.
Errors — none.
ScheduledCalls.oneFrom
Use it to read the booked call a booking answered with.
The booking a booking request answered with: {call: {...}}, or the call itself.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | Object? | required | A booking's answer, decoded. |
Returns — GraineScheduledCall? — its fields: GraineScheduledCall. Example value: GraineScheduledCall(id: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44', at: 2026-10-15 12:30:00.000Z, status: GraineCallStatus.scheduled, source: GraineCallSource.app, reason: 'follow_up').
Errors — none.
ScheduledCalls.listFrom
Use it to read the booked calls a list answered with.
The bookings a list request answered with — {calls: [...]} or a bare list — in Graine's order (upcoming first). Entries that are not calls are skipped.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | Object? | required | A list's answer, decoded. |
Returns — List<GraineScheduledCall> — its fields: GraineScheduledCall. Example value: [GraineScheduledCall(id: '6f1c2a9e-7d1b-4c47-9a6e-2f0d8b1c5e44', at: 2026-10-15 12:30:00.000Z, status: GraineCallStatus.scheduled, source: GraineCallSource.app, reason: 'follow_up')].
Errors — none.
ScheduledCalls.statusAfterCancel
Use it to read a booked call's status after a cancel.
A cancel's answer, {ok, status?}: the call's status afterwards — GraineCallStatus.cancelled when Graine does not say.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
body | Object? | required | A cancel's answer, decoded. |
Returns — GraineCallStatus — its fields: GraineCallStatus. Example value: GraineCallStatus.scheduled.
Errors — none.
Sha256
Use it to hash bytes with SHA-256 on the device, with no dependency.
abstract final class Sha256
What to expect — Public so a custom UI can reuse it; an integration does not need it.
Its functions: hash, ofText, hex — each with its parameters, what it returns, the errors it raises and an example.
Sha256.hash
Use it to hash bytes.
The 32-byte SHA-256 digest of message.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
message | List<int> | required | The bytes to hash. |
Returns — List<int>. Example value: [].
Errors — none.
Sha256.ofText
Use it to hash text.
The SHA-256 digest of text's UTF-8 bytes.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
text | String | required | The text, hashed as UTF-8. |
Returns — List<int>. Example value: [].
Errors — none.
Sha256.hex
Use it to write bytes as hex.
bytes as lower-case hex.
| Parameter | Type | Default | Meaning |
|---|---|---|---|
bytes | List<int> | required | The bytes to write. |
Returns — String. Example value: 'ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad'.
Errors — none.
What's new in 0.9.0
- WebRTC calls. Turn them on in the app's build —
ENV['GRAINE_WEBRTC'] = '1'inios/Podfile,graineWebRtc=trueinandroid/gradle.properties— and native calls, the ones the customer places and the ones Graine rings, carry their audio over WebRTC: steadier on a weak network, with the same ring, call screen and outcomes.GraineCallsOptions(callTransport:)chooses (GraineCallTransport);GraineCallSnapshot.transportandtransportFallbackReasonsay which one carried a call (WebRTC calls). chat.reconnecting: true while a dropped chat — or a first try to open it that failed — is being made again, until it is back, gives up (failed) or is closed. Say "Reconnecting…" then, not "Offline" (GraineChatSession).- The captions switch:
voice.captionsOn(on by default),setCaptionsOn(on)andclearCaptions()(GraineCaptionsSwitch).GraineAgentBarshows its caption only while the switch is on; what was said stays incaptionseither way. - Variables over a conversation's kilobyte are trimmed to fit, not all dropped:
who_calledandcall_reasonride first (Protocol.ticketFirstKeys) and the biggest of the rest are left off, one at a time — the same rule on every SDK. scheduleCall's own refusals say the booking sheet's words: "Booking a call isn't available right now", "Pick a time at least 5 minutes from now" ("1 minute" for one), "Pick a time within 14 days".- The full list of changes is in the Changelog.
What's new in 0.8.0
- Booking a call from your app, drawn by the SDK.
GraineBooking.show(context, app:, reason:)opens the booking sheet in the agent's design — a sheet on a phone, a centred panel on a tablet — and completes with the bookedGraineScheduledCall, ornullwhen the customer closed it.GraineBookingSheetis the same sheet as a widget. See Booking with the SDK's sheet. bookingAvailableon each agent, withbookingBlocker,bookingListenableanddeviceTimezone: show your own "Call me" button only when Graine rings this phone, the agent lets customers book, and the customer is identified.- The chat window offers Book a call under the booked calls in its Upcoming calls card, or on its own in the card's place when none are booked — never when the design hides the booked-calls card (
ChatPieces.book).Bookingholds the rules and the words, andChatTime.daywrites a day the way the sheet does. - Every piece of the chat is set in the dashboard (Embed & Widgets → Appearance → Chat window): the booked-calls card and its title, earlier messages and the New conversation button (
ThemeChat.showUpcomingCalls,upcomingTitle,showHistory,newConversation;ChatPiecesfor a chat of your own). The bar's sheet, panel and full screen offer New conversation as the compact window does. - Several agents in one app:
GraineInApp.init(config, name:),GraineInApp.named,all,defaultNameand each agent'sname; the views takeapp:; native calls takestartCall(agent:)and say which agent each call is with. - The native call engine's 0.8.0 fixes: a call starts at once on the configuration already kept on the device; on iOS one 20-second deadline before the conversation opens ("The call could not connect within 20 seconds.") and "The call's audio could not start." when the call's audio never arrives; on Android a dead connection ends the call after 50 seconds with nothing arriving, a slow network no longer freezes a call, and hanging up lets go of the microphone at once. See Calls the user places.
- The chat's variables ride its ticket and are no longer added to the ticketed connection's address, which never read them; the direct connection still carries them.
- A multi-select answers with its button's label, then the names — "Taken: Morning and Evening".
- A full-screen
GraineChatclosing while aGraineAgentBaris on screen no longer trips Flutter's locked-tree assertion.
Every change, on every platform: Changelog.
Every symbol, A to Z
Every public symbol of the Flutter SDK — 1733 in all — by name, each linked to where this page documents it: a type or function first, then its members.
ActionRegistry—ActionRegistry·deadline·describeError·execute·has·names·registerActionResult—ActionResult·data·error·message·ok·refused·statusActionStatus—ActionStatus·error·ok·refused·wireagentBarStatusAgentChunk—AgentChunk·endsTurn·read·startsTurn·streamEnd·streamStart·textAgentSurface—chat·voiceAppearance—argb·defaultAccent·defaultOrigin·encodeURIComponent·isDark·luminance·palette·resolve·tintBarStatus—BarStatus·label·meter·text·waitingBooking—about·available·blocker·book·bounds·callName·clamp·dayLabel·days·done·doneLine·errorLine·onDay·reasonMax·roundMinutes·subtitle·title·web·zoneLineBookingBounds—BookingBounds·earliest·latestBookingDay—BookingDay·first·key·label·lastBrandLogo—box·labelOnWhite·outlineWidth·plateLook·plateWhitecallPhaseCallPhase—connecting·idle·listening·reconnecting·speaking·thinkingCallsSetting—callName·CallsSetting·fromJson·hosted·platforms·ringTimeoutSeconds·schedulingCaption—Caption·live·role·settled·textCaptions—fold·historyChatAction—actionId·arguments·ChatAction·nameChatClear—ChatClearChatDay—date·today·yesterdayChatDayRow—at·ChatDayRow·contractKey·date·dayChatFrame—ChatFrame·parseChatHistory—ChatHistory·turnsChatHistoryReader—read·timeChatPieces—book·newConversation·of·ofChat·starters·turns·upcoming·upcomingTitleChatRow—ChatRow·keyChatRows—build·callLabel·callSpoken·dayLabel·offersNewConversation·offersStartersChatStream—ChatStream·startChatText—ChatText·chunkChatTime—booked·clock·dayChatTranscript—agent·agentTyping·ChatTranscript·clear·closed·component·customer·expectReply·failPending·max·messages·opened·pending·restore·retryFailed·sent·turnEnded·turns·turnStartedChatTurnRow—ChatTurnRow·index·turnChatVoiceRow—at·ChatVoiceRow·first·id·lastChatWidget—ChatWidget·widgetChatWidgetPending—ChatWidgetPending·hintChatWire—actionResult·appContext·appEvent·callType·client·defaultWsHost·directUrl·init·openTimeoutMs·ping·pingMs·stop·stopGraceMs·subprotocol·text·widgetResult·withContextTokenChromeSurface—caption·chat·componentconnectingLookConnectionQuality—classify·excellent·good·lost·poor·unknownConnectProgress—couldNotConnect·slowConnectMs·stillConnectingConnectStage—dialling·from·registering·retrying·switching·wireContextFrame—availableActions·builddeepEqualsdeepHashDesign—bubbleStyles·chromes·defaultOrigin·easings·fontFamily·glyphAssetVersion·glyphUrl·iconStyles·launcherGlyphScale·launcherRadius·launcherShapes·launcherSize·mixHex·normaliseHex·schemes·squircleScaleDesignFontFace—DesignFontFace·family·key·name·toJson·url·weightDesignFonts—assetVersion·canonicalFamily·faceFor·faceName·facesFor·facesForDesign·key·nearestWeight·url·weightsEmbedRefusal—code·codeName·EmbedRefusal·message·of·retryAfterSeconds·statusCodeFieldStatus—empty·FieldStatus·filled·fromWire·invalid·locked·pending·wireFriction—resolveFrictionConfig—cooldownMs·cooldownSeconds·enabled·FrictionConfig·fromJson·idleAfterMs·maxPerSession·message·openLauncher·requireOutstandingField·screensFrictionDetector—configure·fill·FrictionDetector·idleDueIn·onCall·onIdle·onInteraction·onScreen·outstanding·rulesFrictionForScreen—FrictionForScreen·idleAfterMs·ignore·messageFrictionRules—cooldownMs·cooldownSeconds·enabled·forScreen·FrictionRules·idleAfterMs·maxPerSession·message·openLauncher·requireOutstandingField·screensFrictionScreenRule—FrictionScreenRule·idleAfterMs·ignore·messageFrictionSignal—cooldownSeconds·data·detail·FrictionSignal·maxPerSession·name·openLauncher·screenGraineActionHandlerGraineAgentBar—accent·app·avatarKey·avatarUrl·barKey·bottomInset·builtInChat·call·callButtonKey·captionKey·chat·chatKey·closeButtonKey·components·design·draggable·GraineAgentBar·horizontalInset·initialOffset·keyboardAware·meterKey·muteButtonKey·name·onClose·onPlacementChange·onSurfaceChange·radius·scheme·showCaptions·showComponents·statusKey·surface·switchButtonKey·topMarginGraineBooking—showGraineBookingSheet—aboutKey·app·bookKey·closeKey·dayKey·doneKey·GraineBookingSheet·lineKey·now·onBooked·onClose·reason·sheet·sheetKey·timeKey·zoneKeyGraineCallCaption—GraineCallCaption·live·role·textGraineCallDirection—incoming·outgoingGraineCallFault—errorGraineCallOutcome—agent·callId·durationSeconds·endReason·error·fromMap·GraineCallOutcome·hosted·kind·outcome·reason·wireGraineCallOutcomeKind—answered·declined·ended·failed·missed·ringingGraineCallPermission—fullScreen·GraineCallPermission·microphone·notifications·wireGraineCallPermissions—allGranted·fromMap·fullScreen·GraineCallPermissions·microphone·notificationsGraineCallPermissionStatus—blocked·denied·fromWire·GraineCallPermissionStatus·granted·isSatisfied·notNeeded·wireGraineCalls—answer·attach·callPermissions·callSetupProblems·configure·decline·enableVoIPPushes·end·handlePush·incomingCalls·instance·isSupported·openCallSettings·outcomes·registerPushToken·requestCallPermissions·setMuted·setSpeaker·startCallGraineCallScreen—app·sdkGraineCallSetupProblem—code·GraineCallSetupProblem·messageGraineCallSnapshot—agent·agentSpeaking·callerName·callId·caption·connectedAt·direction·error·fromMap·GraineCallSnapshot·idle·muted·reason·speakerOn·status·transport·transportFallbackReasonGraineCallsOptions—androidSmallIcon·appVersion·baseUrl·callScreen·callTransport·debug·displayName·GraineCallsOptions·iosIconTemplate·iosIncludesCallsInRecents·publishableKey·ringTimeout·ringtoneSound·toMapGraineCallSource—agent·api·app·dashboard·fromWire·GraineCallSource·unknown·wireGraineCallState—agentSpeaking·appearance·caption·captions·connected·connecting·connectivity·end·micDenied·muted·online·quality·ready·reconnecting·retry·setMuted·startGraineCallStatus—answered·cancelled·completed·declined·expired·failed·fromWire·GraineCallStatus·missed·noDevice·ringing·scheduled·unknown·upcoming·wireGraineCallTransport—auto·fromWire·GraineCallTransport·webrtc·websocket·wireGraineCaptionsSwitch—captionsOn·clearCaptions·setCaptionsOnGraineChat—accent·app·chat·components·design·GraineChat·name·onClose·open·scheme·screenKey·showComponentsGraineChatChannel—chat·voiceGraineChatConnection—close·connecting·openGraineChatConnectorGraineChatDelivery—failed·sending·sentGraineChatRole—agent·userGraineChatSession—answerWidget·app·cancelStateOf·cancelUpcoming·clear·error·failed·isOpen·newConversation·reconnecting·refreshUpcoming·turns·upcomingCallsGraineChatSize—compact·fromWire·full·large·wireGraineChatSocket—close·frames·sendGraineChatState—connected·messages·sendGraineChatTurn—at·caption·channel·component·copyWith·delivery·GraineChatTurn·id·live·proactive·restored·role·textGraineChatTyping—agentTypingGraineComponentGraineComponents—answer·answered·app·awaitingReply·closed·content·dismiss·fromChat·GraineComponents·loading·look·onAction·onAnswer·onReport·present·presentPending·reopen·reset·widgetGraineConfig—appVersion·baseUrl·captureTaps·chatSize·debug·endOnBackground·fonts·friction·GraineConfig·publishableKey·requestMicrophone·timing·transport·variablesGraineConnectivity—failed·loading·ready·retryingGraineConnectProgress—callFailed·connectStage·slowConnectGraineEngine—app·child·GraineEngine·voiceGraineEnginePage—bind·dispose·load·reload·runGraineEngineSink—mainFrameError·message·microphoneRequested·pageFinished·pageStarted·progressGraineErrorCode—deviceLimit·fromWire·GraineErrorCode·identityRequired·invalidKey·invalidRequest·network·notFound·originRefused·outsideWindow·rateLimited·schedulingOff·tooFar·tooManyPending·tooSoon·unavailable·unknown·wireGraineException—code·codeName·GraineException·message·retryAfterSeconds·statusCodeGraineField—error·GraineField·label·name·optional·status·valueGraineInApp—addListener·all·bookingAvailable·bookingBlocker·bookingListenable·cancelScheduledCall·captureTap·chat·checkActions·clearPendingWidget·clearScreen·components·config·configureFriction·currentVariables·defaultName·design·deviceTimezone·executeAction·fontFaces·foreground·forgetMemory·frictionRules·identify·init·installId·instance·loadDesignFonts·loadSession·maybeInstance·memories·memoryEnabled·name·named·noteInteraction·pendingWidget·registerAction·removeField·removeListener·scheduleCall·scheduledCalls·schedulingRules·session·sessionListenable·setMemory·setScreen·setVariables·tap·tokens·tokensListenable·track·updateField·voiceGraineIncomingCall—agent·callerName·callId·GraineIncomingCall·hosted·reasonGraineJourney—GraineJourney·name·next·of·stepGraineLauncher—app·call·design·GraineLauncher·label·launcherKey·onPressed·schemeGraineListener—onActionCompleted·onActionRequested·onAgentVolunteered·onCallState·onCaption·onConnectivity·onEnded·onError·onFriction·onMicDenied·onNetwork·onQuality·onReconnecting·onSessionReady·onTransport·onWidget·onWidgetPendingGraineLoaderView—color·GraineLoaderView·label·labelColor·labelStyle·logoUrl·look·size·stacked·trackColorGraineMemory—createdAt·fromJson·GraineMemory·id·listFrom·text·toJson·updatedAtGraineNativeCallStatus—active·connecting·ended·fromWire·GraineNativeCallStatus·idle·isLive·ringing·wireGraineScheduledCall—at·canCancel·fromJson·GraineScheduledCall·id·isUpcoming·reason·source·sourceName·status·statusName·statusWire·toJsonGraineSchedulingRules—callName·earliest·GraineSchedulingRules·hostedRinging·latest·maxDaysAhead·maxPendingPerUser·minLeadMinutes·of·platforms·ringTimeoutSeconds·usersCanBookGraineScreen—availableActions·copyWith·data·error·fields·GraineScreen·journey·screen·title·withField·withoutFieldGraineTiming—bootMs·endWatchdogMs·GraineTiming·hardCapMs·retryDelaysMs·slowConnectMs·stallMsGraineTranscriptView—app·bubbleKey·call·design·GraineTranscriptView·headerKey·maxHeight·scheme·showHeader·titleGraineUpcomingCancel—cancelling·failed·noneGraineVersion—nameGraineVoice—answerWidget·app·attach·attached·config·detach·detachPage·phase·reportEvent·transport·viewClosed·viewOpenedGraineWidget—adopt·data·fallbackText·GraineWidget·id·kind·onSelect·styleGraineWidgetTheme—border·GraineWidgetTheme·muted·onAccent·surface·textGraineWidgetView—accent·app·appearance·components·design·GraineWidgetView·maxHeight·radius·scheme·themeIconTreatment—bodyFillOpacity·bodyStroke·fillBody·IconTreatment·lineStroke·squareIdentity—defaultField·maxValueLength·memoryKey·normaliseField·normaliseInstallId·normaliseTimezone·normaliseValue·pick·placeholders·requestFields·serverLowercase·serverTrim·uuidV4·valueOf·withoutIdentityIdentitySetting—devicesPerUser·field·fromJson·IdentitySetting·standardKeyboardLift—liftForLauncherGlyph—fromJson·id·LauncherGlyph·path·stroke·toJsonLoaderLook—color·kind·LoaderLook·periodMs·px·skeleton·textLoaders—defaultKind·defaultText·kinds·moments·normalise·resolve·resolveStyle·sizes·speeds·textMaxLoaderStyle—color·kind·LoaderStyle·size·skeleton·speed·text·toMapLoaderText—component·connecting·forMoment·isEmpty·LoaderText·reconnecting·thinking·toMapLoadVerdict—bootTimeout·loadCap·LoadVerdict·reason·stalled·waitLoadWatchdog—bootMs·check·hardCapMs·loaded·LoadWatchdog·nextCheckInMs·progress·stallMs·startLogoPlate—accent·from·white·wireLogoPlateLook—fill·hasOutline·LogoPlateLook·outlineColor·outlineWidthMasking—addRule·clearCustomRules·deep·expandReplacement·maskMemorySetting—enabled·fromJson·MemorySettingNativeAppearance—accent·heading·logoPlate·logoUrl·NativeAppearance·radiusPageAppAction—actionId·arguments·name·PageAppActionPageCall—connected·connecting·PageCallPageCaption—live·PageCaption·role·textPageEnded—PageEndedPageMessage—PageMessagePageMicDenied—PageMicDenied·reasonPageMuted—muted·PageMutedPageNetwork—online·PageNetworkPageProgress—failed·PageProgress·stagePageQuality—jitterMs·loss·PageQuality·rttMsPageReady—PageReadyPageReconnecting—active·PageReconnectingPageTransport—message·PageTransport·reason·requested·transportPageWidget—PageWidget·widgetPageWidgetPending—PageWidgetPending·widgetPlacement—clampOffset·dragSlop·isTap·offsetDuringDragPlacementBounds—barHeight·baseBottom·PlacementBounds·topMargin·windowHeightPlatformGrammar—buttonRadius·chipOutlined·chipRadius·grabberHeight·grabberWidth·padBoost·pillButtons·PlatformGrammar·radius·separatorInset·titleWeightProtocol—actionDeadlineMs·bridgeName·contextToken·decodeJson·deliver·engineUrl·out·parse·ticketFirstKeys·ticketMaxBytes·ticketMaxKeyLength·ticketMaxKeys·ticketMaxValueLength·ticketMetadata·toJson·trimTrailingSlashesProtocolIn—appAction·call·caption·ended·micDenied·muted·network·progress·quality·ready·reconnecting·transport·widget·widgetPendingProtocolOut—appActionResult·appContext·appEvent·endCall·identity·setMuted·startCall·variables·warm·widgetResultResolvedDesign—config·dark·fromJson·light·pick·ResolvedDesign·scheme·toJsonRetryLadder—attempt·exhausted·next·reset·RetryLadderRingNote—hz·ms·RingNote·toJsonRingtone—all·gain·label·notes·pauseMs·Ringtone·toJson·waveRole—agent·customerScheduledCalls—atWire·listFrom·maxReasonLength·oneFrom·parseTime·statusAfterCancelSchedulingSetting—fromJson·maxDaysAhead·maxPendingPerUser·minLeadMinutes·SchedulingSetting·usersCanBookSdkIcon—body·lines·SdkIcon·toJsonSdkIcons—all·call·chat·chevron·close·compose·end·mic·micOff·send·speaker·treatmentSelectCall—args·name·SelectCallSessionConfig—accent·agentId·appearance·calls·declaredActions·design·errorFor·friction·fromJson·identity·identitySetting·memory·pageVersion·preferredTransport·SessionConfig·variables·webcallAgentId·wsHostSha256—hash·hex·ofTextSurfacePolicy—allowed·canSwitch·start·SurfacePolicySurfaces—resolveThemeCall—acceptFill·acceptIcon·allControls·avatar·avatarFill·avatars·avatarShape·avatarShapes·avatarText·background·backgroundTo·buttonActiveFill·buttonActiveIcon·buttonFill·buttonIcon·callbackFill·callbackIcon·captions·controls·declineFill·declineIcon·defaultControls·endFill·endIcon·endShape·endShapes·fallback·fromJson·ringtone·ringtones·statusText·text·textMuted·ThemeCall·timer·toJsonThemeCallStatusText—connecting·ended·fromJson·missed·ringing·scheduled·ThemeCallStatusText·toJsonThemeChat—avatar·avatars·background·composerBackground·composerBorder·composerPlaceholder·composerText·fallback·fromJson·headerBackground·headerSubtext·headerText·maxSuggestions·newConversation·pattern·patternColor·patterns·placeholder·showHistory·showTimestamps·showUpcomingCalls·size·subtitle·suggestions·ThemeChat·title·toJson·upcomingTitleThemeColors—accent·accentSoft·agentBubble·agentBubbleText·background·border·danger·fromJson·onAccent·scrim·success·surface·surfaceRaised·text·textMuted·ThemeColors·toJson·userBubble·userBubbleText·warningThemeElevation—card·floating·fromJson·hardOffset·ThemeElevation·toJsonThemeFont—body·fromJson·heading·letterSpacing·lineHeight·scale·ThemeFont·toJson·weightsThemeFontPair—body·fromJson·ThemeFontPair·title·toJsonThemeFontScale—body·caption·display·fromJson·ThemeFontScale·title·toJsonThemeFontWeights—body·fromJson·strong·ThemeFontWeights·title·toJsonThemeGlass—blur·fromJson·surfaceOpacity·ThemeGlass·toJsonThemeIcons—fromJson·launcher·stroke·style·ThemeIcons·toJsonThemeMotion—bounce·durationMs·easing·fromJson·none·ThemeMotion·toJsonThemeOffset—fromJson·ThemeOffset·toJson·x·yThemeRadius—fromJson·lg·md·sm·ThemeRadius·toJson·xlThemeShadow—blur·color·fromJson·opacity·spread·ThemeShadow·toJson·yThemeShape—borderWidth·fromJson·launcher·radius·ThemeShape·toJsonThemeSpacing—cardPadding·fromJson·gap·ThemeSpacing·toJson·unitThemeTokens—bubbles·call·chat·chrome·colors·dark·elevation·font·fromJson·glass·icons·motion·preset·scheme·servedCall·servedChat·shape·spacing·ThemeTokens·toJson·v·windowTransport—from·Transport·webrtc·websocket·wireVariableStore—flatten·flattenOne·identity·merged·setDashboardDefaults·setIdentity·setRuntime·VariableStorevoiceBarStatusVoiceMeter—barWidth·gap·height·heights·legMs·low·scale·staggerMs·stillWebViewEnginePage—controller·WebViewEnginePageWidgetAnswer—data·summary·WidgetAnswerWidgetAnswered—data·summary·widget·WidgetAnsweredWidgetChip—id·label·WidgetChipWidgetContent—chips·closeLabel·days·drawable·isCalendar·isChips·isProducts·isQuickActions·many·manyButtonLabel·note·pick·pickChip·pickMany·pickSlot·prompt·rows·selectLabel·surface·title·toggle·widget·WidgetContentWidgetDay—label·slots·WidgetDayWidgetDismissal—eventData·kind·title·toolName·WidgetDismissalWidgetFlow—answered·awaitingReply·baseUrl·closed·dismiss·loading·nextDeadline·onAgentStarted·onPending·onWidget·reopen·reset·seed·submit·tick·widget·WidgetFlowWidgetLook—accent·button·columns·density·facts·imageSize·maxSelect·platform·preset·radius·select·surface·toMap·WidgetLookWidgetPalette—border·mode·muted·onAccent·surface·text·WidgetPaletteWidgetPending—id·kind·WidgetPendingWidgetRow—facts·id·image·price·selectLabel·subtitle·title·unavailable·WidgetRowWidgets—awaitingReplyMs·buttons·defaultPreset·densities·fillSelectArgs·fillSelectTemplate·grammar·imageSizes·manySummary·maxSelectDefault·minLoaderMs·navigateAction·normaliseSelectAction·normaliseStyle·pendingWidgetMs·platforms·presets·resolveImages·resolveLook·resolvePlatform·selectArgMax·selectCall·selects·selectValueMax·surface·surfaceChoicesWidgetSelectAction—action·args·isEmpty·path·say·toMap·WidgetSelectActionWidgetStyle—accent·button·columns·density·facts·imageSize·maxSelect·platform·preset·radius·select·surface·toMap·WidgetStyleWidgetSubmission—action·data·summary·widgetId·WidgetSubmissionWindowChrome—barHeight·captionTitle·chevronBox·chevronIcon·chevronInset·innerRadius·lights·lightsGap·lightsInset·lightSize·lightsWidth·monospace·monospaceFallback·onlineDot·onlineDotGap·title·titleGap·titleInset

