Reference

Flutter SDK reference

The public classes you use day to day, what each is for, and the one thing about it that surprises people.

The public API you use day to day. If you find yourself importing from src/, tell us what you needed and we will export it properly.

Full generated dartdoc lands on pub.dev with the first published release. This page is the map.

You rarely write these calls yourself: each task opens with the prompt that has your coding agent write them. This page is what they rely on.

Rendel

The facade. One init per app run.

MemberSignatureNotes
initFuture<void> init({required String appKey, RendelTheme? theme, List<RendelAction> actions, RendelConfig config})Awaited. A key that does not start with rd_pk_ asserts in debug and reports through onLog in release, then disables the copilot for the run — a typo used to cost a silent afternoon.
openFuture<void> open(BuildContext context)Presents the copilot as a full-height sheet. While it is already up, or shrunk to the bubble after a screen it opened, it returns or restores that one rather than stacking a second (0.38). Returns without presenting when the copilot is disabled.
closevoid close(BuildContext context)—
resetvoid reset()Call on logout. Clears the conversation and the user, so the next turn is anonymous. Safe to call while the sheet is up.
registerActionvoid registerAction(RendelAction action)Re-syncs the manifest.
registerRoutevoid registerRoute(String name, {required String title, required String description, Map<String, RendelRouteParam> params, required RendelRouteOpener open})A screen of your app the copilot may offer on a screens card. name is snake_case. title (1-60 characters) is your app's own name for the screen, drawn under the model's title. description (1-300) tells the model when it is the right screen. Up to 8 params, 50 routes per app. open runs your own navigation once the sheet is out of the way, with the copilot waiting in a bubble. Re-syncs the manifest. Safe before init.
addContextProvidervoid addContextProvider(String key, Future<Map<String, dynamic>> Function() provider)Called per turn, with a timeout. A slow provider costs its own context, never the turn.
identifyFuture<void> identify({required String userId, Map<String, dynamic>? traits, String? userHmac})See Context.
pairFuture<RendelPairResult> pair(String code)Lets the console watch this device's conversation, read only, for two hours. Test keys only; a code works once, for ten minutes. Never throws: the result carries a sentence to show. Safe before init. See Pair a test app.
refreshConfigFuture<void> refreshConfig()Re-reads the published appearance. The SDK does not hook the app lifecycle itself; call this on foreground if you want a publish to land without a relaunch.
eventsStream<RendelEvent>Broadcast.
theme / configRendelTheme / RendelConfigThe effective values, after any published config is layered over yours.
stringsRendelStringsThe words the SDK is drawing in: yours, or the shipped set for the answer language.
configRevisionValueNotifier<int>Ticks when a published config lands and changes what is on screen.
isEnabledboolFalse when you turned it off in code or the console published a kill switch.
isInitializedbool—
deviceIdString?The anonymous per-install id this run is sending. Null before init completes. It is what Support asks for.

RendelConfig

Everything that is your choice rather than the protocol's. Every field is also the floor for anything published from the console.

FieldDefaultNotes
apiBaseUrlhttps://api.rendel.ai—
userTokennullFuture<String?> Function(): the signed-in person's current token from your own sign-in. Asked for before every question and never stored. See Signed-in user.
requestTimeout30 sNon-streaming calls.
streamIdleTimeout45 sHow long a turn may go without a single server event. Server pings every 15 s, and the SDK counts them.
sdkVersionflutter/<package version> (flutter/0.46.3 today)Sent as client.sdk.
languages[]The languages this app is willing to be answered in, in preference order — ['tr', 'en', 'ru']. The device picks from among them; one speaking none of them gets the first, so the order is a decision. Empty hands the choice to the list published from the console, and absent that the copilot answers in whatever it is addressed in. Different from locale, which is one device's setting.
localedevice's ownBCP-47 (tr, pt-BR). The language the copilot answers in, and the one confirmTemplates is matched on. A message written in another language is still answered in that one. See Locales.
assistantNameCopilotThe name at the top of the copilot's sheet.
launcherLabelAskThe word on the launcher.
suggestions[]Opening prompts. Name things this app can do, in the user's words.
emptyStateTitlenullThe headline shown before the first question, in your own words. Null keeps the SDK's, translated into the language the copilot answers in. Publishable from Appearance.
emptyStateBodynullThe line under that headline, shown before the first question.
composerHintnullThe words in the empty message box. Null uses RendelStrings.composerHint, which is translated. Publishable.
attachIcon / voiceIcon / sendIconplus / microphone / arrowUpRendelAttachIcon (paperclip, image, plus, off), RendelVoiceIcon (microphone, waveform, off), RendelSendIcon (arrowUp, paperPlane, arrowRight). off removes that control. Publishable.
enabledtrueThe kill switch in code. Setting it false wins over anything published. Not a security control — the API enforces suspension server-side.
remoteConfigtrueFalse pins the copilot to exactly what this object says.
configStorenullWhere the last good published config is kept between launches.
deviceIdStorenullWhere the device id is kept between launches. Use a different key from configStore — both sides read and write one string.
onPickAttachmentbuilt inReturns an RendelAttachment (bytes, name, media type) from your own picker, replacing the SDK's Photos, Camera and Files; the "+" then opens yours directly. Null uses the built-in. attachIcon: RendelAttachIcon.off removes the control.
onStopDictatingnullEnds a dictation when the user presses the microphone again. Without it the control cannot be pressed mid-session and the recogniser ends the session itself.
onDictatebuilt inReturns recognised speech as text from your own recogniser, replacing the SDK's speech_to_text; it is handed an onPartial callback to feed the composer while somebody is still speaking. Return null when nobody spoke and throw when the recogniser failed: the SDK words the two differently and logs the error. Null uses the built-in. voiceIcon: RendelVoiceIcon.off removes the control.
onOpenUrlnullNull opens a card's link in an in-app browser, so the user comes back to the conversation when they close it. Set it to route links yourself, for example to your own product screen.
bubbleOffset104Logical pixels above the bottom edge for the bubble while a screen the copilot opened is showing, so it clears your bottom bar. Never less than the safe area.
stringsby localeEvery word the SDK puts on screen that is not your app's or the model's. Null takes them from locale — Türkçe, Deutsch, Français, Español, العربية, English elsewhere. Set it and you own every word. RendelStrings.forLocale('tr').copyWith(...) changes only the words you name and keeps the rest of that language (before 0.44.1 it returned most words in English).
onLognullPoint it at your crash reporter.
httpClientnullTest seam: pass a MockClient from package:http/testing.dart to run manifest sync, turns and action dispatch offline. Leave it null in production.

RendelAction

What the copilot is allowed to do.

FieldTypeNotes
nameStringsnake_case, asserted. One camelCase name used to reject the entire manifest.
descriptionStringThe model reads this to decide when to call it. Write it for a colleague, not for a compiler.
paramsRendelSchemaValidated server-side before an invocation exists.
riskRendelRiskread runs silently; write and destructive get a server-built confirmation card.
handlerRendelHandler?Future<RendelResult> Function(Map<String, dynamic> params)
onInvokeRendelInvocationHandler?Future<RendelResult> Function(RendelInvocation) — the same thing plus the invocation's id and risk, for idempotency on your side.
confirmTemplateString?Overrides the server's sentence on the confirm card.
confirmTemplatesMap<String, String>?The same sentence per language, keyed by BCP-47 tag: {'tr': '{order_id} numaralı siparişi iptal edelim mi?'}. Matched on the locale the SDK sends: the exact tag, then the language, then confirmTemplate. Sixteen at most.
timeoutDurationDefault 15 s, capped at 120 s.
sandboxResultMap<String, dynamic>?Returned instead of running the handler on a test key.

RendelSchema

Parameter shapes, without hand-writing JSON Schema.

RendelSchema.object({
  'order_id': RendelSchema.string(description: 'The order number'),
  'reason': RendelSchema.enumOf(['damaged', 'wrong_item', 'other']).optional,
  'quantity': RendelSchema.integer().optional,
  'tags': RendelSchema.list(RendelSchema.string()),
})

string, number, integer, boolean, enumOf, list, object, and raw for anything the helpers do not cover. .optional (or .orAbsent) on any of them.

RendelResult

RendelResult.ok(Map<String, dynamic> data) or RendelResult.fail(String error). The failure string reaches the model, so write it as something the model can act on: "no order with that number" beats "404".

RendelRisk

read, write, destructive. See Actions and risk levels.

RendelInvocation

id, name, params, risk. The id is stable across a retry of the same turn, so it is the natural idempotency key for whatever your handler does.

Take it with onInvoke when running an action twice would be worse than not running it: an app killed between running the handler and reporting the outcome leaves the server without a result, and the model may propose the same thing again.

Rendel.registerAction(RendelAction(
  name: 'refund_order',
  description: 'Refund an order to the original payment method',
  params: RendelSchema.object({'order_id': RendelSchema.string()}),
  risk: RendelRisk.destructive,
  confirmTemplate: 'Refund order {order_id}? This cannot be undone.',
  onInvoke: (invocation) async {
    // The same id comes back if the turn is resumed after a dropped stream.
    if (await refunds.alreadyProcessed(invocation.id)) {
      return RendelResult.ok({'status': 'already_refunded'});
    }
    return RendelResult.ok(await refunds.create(
      orderId: invocation.params['order_id'] as String,
      idempotencyKey: invocation.id,
    ));
  },
));

RendelRouteParam

RendelRouteParam.string(), .number(), .boolean(), each taking description, required and fromActions. With fromActions: true the value must be one an action returned in this conversation, so a guessed order id never opens the screen.

Rendel.registerRoute(
  'order_detail',
  title: 'My orders › Order',
  description: 'One order: its items, delivery and payment.',
  params: {'order_id': RendelRouteParam.string(required: true, fromActions: true)},
  open: (p) => navigatorKey.currentState!.pushNamed('/orders/${p['order_id']}'),
);

open is a RendelRouteOpener, FutureOr<void> Function(Map<String, Object?> params), and gets the params the server checked.

RendelLauncher

RendelLauncher({String? label}). Draws nothing when the copilot is uninitialised or disabled, so you can leave it in the tree unconditionally.

RendelTheme

See Theming. Built with RendelTheme.fromTokens(...), which derives readable text and border roles from your four colours rather than trusting them — a themeable SDK that does not do this ships unreadable badges.

RendelTheme.paper() and RendelTheme.deep() are the two built-in themes; fromTokens(...) builds yours. RendelThemeScope.of(context) reads the theme inside a custom component. contrastRatio and auditContrast check your colours.

RendelConfigStore

abstract class RendelConfigStore {
  Future<String?> read();
  Future<void> write(String value);
}

One interface, two uses: RendelConfig.configStore and RendelConfig.deviceIdStore. By default both are kept in the app's preferences (shared_preferences). RendelMemoryConfigStore is the in-memory option, and the default under flutter test.

RendelLogRecord, RendelLogLevel, RendelLog

Where the SDK reports what it could not tell you any other way.

codeWhen
invalid_keyappKey does not start with rd_pk_ (or nc_pk_, a key made before the rename).
handler_failedAn action handler threw.
handler_timeoutA handler passed its timeout.
context_provider_timeoutA context provider missed its 300 ms budget.
context_provider_failedA context provider threw.
manifest_sync_failedThe server rejected the manifest. The message carries the field and the reason.
transport_failedA network call failed.
config_unreadableA published config could not be parsed, or was not legible on this device.
config_cache_write_failedThe config store threw on write.
device_id_ephemeralNo deviceIdStore is set, so the device id is new each launch. Debug level, once.
device_id_store_failedThe store threw or hung.
usage_description_missingInfo.plist lacks NSMicrophoneUsageDescription or NSSpeechRecognitionUsageDescription, so the built-in microphone is not drawn, or NSCameraUsageDescription, so the "+" offers no Camera. iOS would close the app the first time either was used.
user_store_failedThe signed-in user could not be stored or read back, so a relaunch starts signed out until the next identify.
call_failed / mail_failed / copy_failed / calendar_failedThe dialler, mail app, clipboard or calendar editor could not be opened for a call, email, copy or add_to_calendar tap.
open_url_failed / open_external_failedA link could not be opened in the in-app browser, or could not be handed to the system.
route_open_failedA registered route's open threw.
dictation_failedThe recogniser failed: your onDictate threw, or the built-in one could not start.
user_token_faileduserToken threw; the turn went without a token.
surface_staleDebug: a block arrived for a surface_id with a revision no newer than the one on screen, and was dropped.
pairedDebug: pair was accepted; the console watches until the time in the message.
pair_test_only / pair_not_found / pair_rate_limited / pair_failedWhy pair did not pair: a live key; a wrong, used or expired code; too many tries in a minute; anything else. The web SDK uses the same codes.

code is stable and safe to switch on; message is for humans and may be reworded.

RendelEvent

opened, closed, messageSent, actionExecuted. For your own analytics.

Rendering your own component

ComponentRegistry.register(String type, ComponentBuilder builder) puts a widget of yours in the catalog's place. ComponentBuilder is Widget Function(BuildContext context, WireBlock block, RendelDispatcher dispatch). RendelActionButton, RendelChip, RendelControlShell, RendelOverline, RendelPressable, RendelPulse and RendelSwap are exported so your component presses, encloses and breathes like a built-in rather than like Material.

RendelDispatcher

How your component talks back. The SDK hands one to your builder; you never construct it. A member that is null means this build cannot do that, so draw that part as content.

MemberSignatureNotes
onActionFuture<bool> Function(UIAction)Fires a tap; resolves false when the tap was dropped.
canHandlebool Function(UIAction)Ask before drawing a tap surface; false means draw it as content.
onSubmitFormFuture<RendelSubmitOutcome> Function(String formId, Map<String, Object> values)Values are String, num, bool or List<String>.
onSelectFuture<bool> Function(WireBlock, String id, String shown)?A variant_picker or datetime_slots pick, sent as a selection. Null where nothing can be picked.
onChooseFuture<bool> Function(WireBlock, List<String> ids, String shown, {String? otherText, Duration lit})?A choice answer: ids, or otherText, or nothing for skip.
onRateFuture<bool> Function(WireBlock, int score, {String? comment})?A rating score and optional comment, posted to /v1/ratings with no turn.
onPickFileFuture<RendelAttachment?> Function(RendelAttachSource)?A form upload field's picker. Resolves null when the user backs out.
fileSourcesList<RendelAttachSource>Where onPickFile can pick from.
onUploadFuture<String> Function(RendelAttachment)?The upload that resolves an upload id. Throws an exception whose toString() is the server's sentence.
routeTitleString? Function(String route)?The app's title for a registered route, for screens.

UIAction

A sealed union: ReplyAction, OpenUrlAction, NavigateAction, CallAction, EmailAction, CopyAction, AddToCalendarAction, ConfirmAction, CancelAction, AppActionRef. New kinds arrive in minor releases, so give any switch over it a wildcard (_ =>) case.

Names from before 0.32.0

Every NC*, NeonCopilot and Copilot* name is a deprecated typedef of its Rendel* replacement, and each goes at 1.0.