Skip to main content

kletso_flutter 0.1.0 copy "kletso_flutter: ^0.1.0" to clipboard
kletso_flutter: ^0.1.0 copied to clipboard

Embeddable Kletso AI chat for Flutter: streaming chat widget, launcher, server-driven UI (kletso.ui/v1) with host-registered components and the Kletso design tokens as a ThemeExtension. Pure Dart, Wasm-ready.

kletso_flutter #

Embeddable Kletso AI chat for Flutter apps: a streaming chat widget, a floating launcher, and server-driven UI (kletso.ui/v1) rendered through your own widgets. Pure Dart, no platform channels, works on Android, iOS, web (JS and Wasm) and desktop. One dependency.

20-line quick start #

import 'package:flutter/material.dart';
import 'package:kletso_flutter/kletso_flutter.dart';

Future<void> main() async {
  await Kletso.init(KletsoConfig(publishableKey: 'kl_pub_…', agentId: 'agt_…'));
  await Kletso.instance.identifyAnonymous();              // or authenticate(token: jwt)
  Kletso.instance
    ..registerComponent('acme.productCard', (ctx, node) => ProductCard(
          name: node.string('name'),
          price: node.number('price'),
          onView: () => ctx.executeAction('view'),
        ))
    ..registerAction('open_product', (args, ctx) =>
        Navigator.of(ctx.context).pushNamed('/product/${args['sku']}'))
    ..onOpenUrl = (uri) => launchUrl(uri);                  // url_launcher, or your router
  runApp(const MyApp());
}

// anywhere in the tree:
//   KletsoLauncher()                          floating bubble → opens the chat sheet
//   Kletso.instance.open(context)             open programmatically
//   KletsoChat()                              embed the chat in your own page

Try it without a backend:

final backend = KletsoFakeBackend(scenario: const KletsoFakeScenario.demo());
await Kletso.init(config, api: backend, transport: backend);

What you get #

widget purpose
KletsoChat header, connection banner, reverse message list, streaming bubbles, tool-call chips, rendered surfaces, typing indicator, composer
KletsoLauncher floating bubble with unread dot; open() shows a sheet (phone) or a docked panel (wide screens) or a full-screen route
KletsoSurfaceView renders one kletso.ui/v1 surface; use it to preview surfaces or embed them outside the chat
KletsoConversationList the user's conversations with a "new conversation" row
KletsoTheme ThemeExtension generated from the Kletso design tokens; KletsoTheme.fromServer(bootstrap.theme) applies your dashboard branding

Custom components #

The agent decides what to show; your app decides how. Register a builder per type; the SDK resolves { "path": … } bindings, enforces limits (≤ 500 components, depth ≤ 16, ≤ 256 KB) and falls back to plain text for anything unknown, so a model mistake never crashes your app.

Kletso.instance.registerComponent(productCardSpec.type, (ctx, node) => ProductCard(
  sku: node.string('sku'),                 // typed getters never throw
  price: node.number('price'),
  inStock: node.boolean('inStock'),
  onView: () => ctx.executeAction('view'), // local  → your registerAction handler
  onAdd:  () => ctx.executeAction('add'),  // agent  → posted back as the user's next turn
), spec: productCardSpec);

Declare the props schema once as a KletsoComponentSpec in lib/kletso_components.dart (import package:kletso_core only, no Flutter) and run dart run kletso_flutter:sync to produce kletso.components.json for the dashboard, so the model's render_ui tool schema always matches your widgets.

Built-ins shipped (30): text, markdown, card, row, column, divider, image, avatar, button, list, table, chart (bar/line/pie, no dependency), carousel, form, input, select, confirm, loading, error, badge, link, map (schematic map with markers and route), video and audio (poster/waveform, open through onOpenUrl), rating (interactive stars), steps (timeline), accordion, tabs, countdown (live), progress. Host builders may override any of them by name: the example app swaps map for flutter_map tiles and video/audio for video_player, so the agent emits the same JSON and the app decides how rich it looks.

Every interaction direction #

direction how
app → Kletso track, screen, setContext/updateContext, open, close, useAgent, logout, pause/resume
Kletso → app UI streamed text, ui.render surfaces, proactive trigger turns
user in chat → agent agent/submit/confirm/workflow actions and text
user in chat → your app local actions → registerAction handler (navigate, add to cart, ctx.client!.close()); echoed to the runtime as analytics only
both in one tap your builder changes app state and calls ctx.executeAction('add'); or a local handler calls ctx.client!.send(...)
agent → your app, no tap app.command → your registered handler, only with KletsoConfig(allowServerCommands: true) and client.ui.contextProvider set; outcomes on client.ui.commandResults
silent app event → proactive UI track('geofence_entered') → server rule → app.notify → KletsoNotificationHost banner/toast/alert (or your OS tray via onSystemNotification); tap opens the chat and/or runs a local/url/agent action
runtime → device while backgrounded push: registerPushToken(KletsoPushToken(...)) once, then handlePushPayload(message.data) from your push plugin; same rendering and dedupe as live

Triggers: track('cart_abandoned') and screen('checkout') let the agent speak first. A trigger that opens a new conversation still reaches the device (session-level events), lights the launcher's unread dot, and open() lands on that conversation.

Proactive notifications #

MaterialApp(
  navigatorKey: navigatorKey,
  builder: (context, child) =>
      KletsoNotificationHost(client: Kletso.instance, child: child!),
);
Kletso.instance.ui.contextProvider = () => navigatorKey.currentContext;
// optional: OS tray for `system` notifications (your plugin, not ours)
Kletso.instance.onSystemNotification = (n) async {
  await localNotifications.show(/* n.title, n.payload.body, payload: n.id */);
  return true; // false → the SDK shows its banner instead
};
// on OS-notification tap: Kletso.instance.ui.openNotification(n)
// push while backgrounded:
await Kletso.instance.registerPushToken(
  KletsoPushToken(platform: KletsoPushPlatform.fcm, token: fcmToken),
);
FirebaseMessaging.onMessage.listen((m) => Kletso.instance.handlePushPayload(m.data));

Channels: banner (top card, auto-dismiss), toast (bottom pill), alert (dialog), system (your tray, banner fallback), silent (no UI: just open the chat / run the action). Payloads may carry an inline kletso.ui/v1 surface and a tap action. Outcomes stream on client.ui.notificationResults.

Security defaults #

  • Only the publishable key ships in the app; user identity is a host-signed token.
  • Markdown renders links only; no inline HTML. Links, images and url actions pass the session's host allowlist; javascript:/data:/http: never open.
  • Payload size, depth and count limits are enforced before anything is built.

Markdown #

KletsoPlainMarkdownRenderer (default) covers headings, emphasis, code, lists, quotes, rules and links with zero dependencies and is Wasm-clean. Pass another KletsoMarkdownRenderer (e.g. wrapping gpt_markdown) to KletsoChat if you need tables or LaTeX.

Dependencies #

flutter, kletso_core, kletso_ui_schema, meta. Fonts: Plus Jakarta Sans (OFL) bundled; KletsoTheme.light(useHostFont: true) to inherit yours.

0
likes
0
points
700
downloads

Publisher

verified publisherkletso.ai

Weekly Downloads

Embeddable Kletso AI chat for Flutter: streaming chat widget, launcher, server-driven UI (kletso.ui/v1) with host-registered components and the Kletso design tokens as a ThemeExtension. Pure Dart, Wasm-ready.

Homepage
Repository (GitHub)
View/report issues

Topics

#ai #chat #chatbot #sdk #generative-ui

License

unknown (license)

Dependencies

flutter, kletso_core, kletso_ui_schema, meta

More

Packages that depend on kletso_flutter