Skip to main content

embed_flutter 0.4.0 copy "embed_flutter: ^0.4.0" to clipboard
embed_flutter: ^0.4.0 copied to clipboard

PlatformAndroidiOS
unlisted

A powerful Flutter SDK that provides a powerful voice-enabled AI-agent functionality with real-time widget tree monitoring for screen context fetching and realtime voice communication.

Changelog #

0.4.0 #

React Native parity, the click-naming convention shared with Android, RN and web, call-safety fixes, and an SDK that handles its own Android permissions. Minor version bump: click event names change, the signed-in user is kept until clearUserSession(), and the package is now a Flutter plugin (Android native part, iOS Dart-only) — hosts add no permissions.

Call safety #

  • A reconnect no longer turns the microphone back on. LiveKit fires "room connected" again after a full reconnect (for example a switch between Wi-Fi and mobile data). That was handled as a new call: a mic the user muted — or that an agent pause muted — was re-enabled while the UI still showed it muted, the AI runtime restarted (dropping a running mission), "call started" was sent twice and a workflow avatar reopened. A repeat now only restores the mic as it was, re-routes audio, re-asserts a pause and re-sends the screen (React Native parity).
  • Headsets keep call audio. The SDK no longer forces the loudspeaker: a connected Bluetooth or wired headset is used, otherwise the user's speaker choice, and a device change no longer switches the speaker back on. Before livekit_client 2.9, forcing the speaker on Android routed audio away from a connected headset.
  • The SDK handles Android permissions itself; hosts add nothing. It now ships a small Android plugin whose manifest declares every permission a call needs (INTERNET, ACCESS_NETWORK_STATE, RECORD_AUDIO, MODIFY_AUDIO_SETTINGS, WAKE_LOCK, BLUETOOTH_CONNECT, and BLUETOOTH up to Android 11), merged into the host app at build time. At call start it requests BLUETOOTH_CONNECT (Android 12+) itself, only when a Bluetooth headset is connected; a denial never blocks the call (React Native parity). The README no longer lists the non-existent android.permission.MICROPHONE.
  • No hidden live calls. Leaving the screen (or the widget hiding) while a call is still connecting now cancels it. It used to finish connecting and go live with the mic on and no End button.
  • A failed token no longer hides the widget. A token failure when the user taps Start now shows "Couldn't connect — tap to retry" instead of removing the widget. A failed pre-call prep (a network blip at sign-in) is retried with backoff (2 s → 30 s, up to 5 times) instead of waiting for the next screen change.

Behaviour changes #

  • Click analytics now use the naming convention shared with Android 1.2.3, React Native 1.2.0 and web.
    • event_name is <name>_<suffix> (pressed / toggled / selected / opened). It no longer ends in _<screen>; the screen stays in context.screen.
    • The name is the control's ValueKey<String>, its Semantics(identifier:), then its tooltip or visible text (slugged), then — for a control with no text — the image / SVG file name or common icon it draws (React Native's rule), then its role. A control with no key is no longer named by a random hashCode.
    • data carries Android's keys: element_id, type, kind, role, checked, source, click_sequence, component, legacy_event_name. The Flutter-only buttonId, formState, clickedAt and lastClickedAt are gone. When a keyed Material button had a pre-0.4.0 name, it is sent as legacy_event_name so old dashboards can be mapped.
  • Every tappable control is tracked, not only ElevatedButton, TextButton, OutlinedButton, FloatingActionButton and IconButton: the tapped control is found in the semantics tree, so GestureDetector, InkWell, ListTile, checkboxes, switches, radios and tabs report too. Checkbox / switch / radio clicks carry their state after the tap.
  • No more lost clicks. One 500 ms debounce timer used to be shared by all buttons, so tapping two buttons quickly dropped the first. Now only the same name repeated within 300 ms is dropped. Drags beyond touch slop are not clicks.
  • Clicks need a user. A click before USER_DATA sets app_user_id is not sent (React Native parity).
  • EmbedTracker.attachButton and EmbedTracker.onButtonClicked are deprecated no-ops.

React Native parity: agent, identity and events #

  • Touching the app stops the agent. A user touch while the agent runs a mission or highlight (running or queued) ends it with mission_status cancelled, failure_reason: user_interrupted; the highlight box and glow are removed, and a user_interaction frame is sent (at most one per second). Touches on the SDK's own widget and the agent's own taps never count.
  • The signed-in user is kept across app restarts until a logout (EmbedWidget.clearUserSession() or embedClearStorageCache()) — 0.2.0 and 0.3.0 forgot it at every launch. Token fetch, route catalog, UI-graph sync and events work from cold boot; USER_DATA still sets or replaces the user. Hosts must call EmbedWidget.clearUserSession() on logout.
  • EmbedWidget.clearUserSession() is now a full logout (RN EmbedLogout): it ends the call, wipes the on-device UI-graph cache and typed form values, then forgets the user in memory and on disk — also with no widget mounted. Config and API key are kept. Each step is isolated, here and in embedClearStorageCache().
  • EmbedWidget.initializeLiveKit() is idempotent: it does nothing during a call (re-preparing used to orphan the live call) or when already prepared.
  • Events go out whenever a user is signed in, whatever the widget is doing (hidden, delayed, excluded route, config still loading, not mounted). With no user they are not sent and embedEvent returns false (as in RN); a blank USER_DATA id and an empty analytics event_name are rejected. SCREEN_STATE is no longer dropped before config loads.
  • Failed analytics are retried one per event, oldest first, from a persisted queue (at most 100) — identical events are no longer merged. The queue drains on resume, config load and a signed-in USER_DATA. /user-context/update has a 15 s timeout and never sends without an app_user_id. event_id / session_id are UUID v4 (they were millisecond stamps that could collide).
  • embedOnAgent receives every React Native agent event: agent_visible, agent_tap_to_open, agent_tap_to_close, gen_tool_triggered, popup_message_visible, the mic permission events and the conversation start/end — listeners first, even before USER_DATA, then the backend. rage_click and screen_view are analytics only (observe them with embedOn), as in RN. A throwing listener is logged and skipped; a listener may trigger SDK events. Popup and mic payloads carry RN's fields.
  • embedCollapseWidget() reports agent_tap_to_close. agent_visible fires when the FAB really shows (it also fired while hidden). Every connected call reports agent_conversation_ended exactly once.
  • Deprecated: EventHelper.flushPendingEvents() (use flushAnalyticsEventQueue()), EventHelper.clearPendingEvents() and PendingEventSender — nothing is held for widget state any more.

React Native parity: widget, accessibility, privacy, networking #

  • Widget config. colorPalette.gradientColors (2+ stops), the 17 named gradientPresets, a lone grad1 / grad2 (RN's darken / accent rules), fillType horizontal / vertical gradient direction and solid / flat / color fills, position.leftPadding / topPadding (vertical insets mirror; negatives clamp to 0; the drag stays inside the insets), collapsedView.viewCloseDelay (ms) and snake_case keys / numeric strings everywhere. borderRadius rounds the open card only (default 20); the collapsed FAB stays round. An unknown widgetPosition is bottom-right.
  • Dashboard widget changes show on the next launch, not the one after. At launch the widget draws the config saved by the previous launch while /initialize is in flight; it was only refreshed when other_data changed, so a palette, direction, position or text edit appeared one launch late. A changed widget_config now refreshes it too, silently — no loading flash, and an open card stays open.
  • colorPalette.borderColor borders the Start call button, 1 px, and only when set (Android ExpandedCard, RN). It used to border the open card, which now has no border; the card no longer defaults to a white 20 % edge.
  • Call status line: rotating phrases per state, ..... while muted (with a 2 s "Speaking" hold), "Connecting..." and "Couldn't connect — tap to retry".
  • Captions grow and scroll instead of being cut at 3 lines, following the newest words unless the user scrolls back.
  • Accessibility: screen-reader labels on the FAB ("Voice assistant", expanded state), Start call, Mute / Unmute microphone, Show / Hide captions, End call and Close; the nudge and captions are live regions.
  • pauseAgent() / resumeAgent() / isAgentPaused (and embed… helpers): pause the agent without ending the call (backend agent_control RPC), muting the microphone; re-asserted after a reconnect.
  • Privacy: Semantics(identifier: 'embed-redact…') hides a node's content — and everything inside it — from capture, cache and click names; the agent can still act on it.
  • Networking: /initialize and /token time out (15 s; token 6 s + one 8 s retry on a network failure); a failed /initialize is retried with backoff (2 s → 30 s) unless refused with a 4xx; every request sends X-Revrag-App-Version. Events carry top-level app_version and data.screen_name.
  • The tooltip is a diagonal gradient and the CC icon takes the palette text colour.

0.3.0 #

Tree-capture hardening, Android/backend wire parity, and multi-step mission parity. Verified against the revrag-core wire contract. Minor version bump: capture semantics, defaults and stable IDs change (see Behaviour changes).

Requires Flutter >= 3.29 / Dart >= 3.7 (SemanticsData.role).

Behaviour changes #

  • Missions no longer depend on dataCapture, widget visibility or the route allowlist. Mission captures and responses (find / verify / info queries / candidates) are blocked only by explicit host exclusions (disabledRoutes, an open excluded popup), as on Android. flags.dataCapture: false stops telemetry pushes only. A refused mission response is replaced by a failure frame (screen_not_capturable / payload_too_large) instead of being dropped.
  • transmitOnHiddenWidget defaults to on (Android parity). Only an explicit false under flags or treePush turns it off.
  • Named popup routes in disabledRoutes block capture while open, but no longer hide the FAB (popups don't change the page route). Their route-change analytics are restored.
  • Screen names prefer the route name (or host-provided name) over widget inference; tabs of an IndexedStack / PageView shell are named route/tab from stable signals (ValueKey<String>, Semantics identifier, heading). Class names are never used in release builds, so --obfuscate no longer scrambles screen names, stable-ID prefixes or cache keys.
  • Stable IDs changed (number-led label words no longer enter IDs and collisions get content-derived suffixes; tappable images are buttons; full-screen labelled wrappers are groups; overlay nodes live under screen.overlay.*; role and screen-name changes below). The on-device cache format is bumped to schemaVersion: 2; older screen files are discarded locally and never uploaded.
  • The stale-node prune is new: a node is dropped only after it has been absent from eligible changing captures spanning 14 days; a quiet stretch, an open overlay or a partial capture never counts as absence.
  • Cache uploads no longer include _firstSeen / _lastSeen / _seenCount bookkeeping or tokens.

Wire parity #

  • Nodes carry disabled (measured), placeholder, slider range (when the host provides min/max), parent_id, and the setText action on editable fields. Roles use Android's vocabulary (scrollable, switch, radio, navigation, modal, overlay, listitem); raw Flutter role names no longer leak.
  • ui_diff keeps its delta shape: moved entries now carry path (the key the backend reads), updated entries carry subtree_text, normalized_text, layer, editable, secure, parent_id, visible_fraction, and fraction-only visibility changes are reported.
  • A node is visible only when at least 5% of it is on screen.
  • Snapshot frames carry app_user_id, app_version and sdk.
  • verification_result carries the achieved slider value and strategy; slider failure codes match the backend/Android (invalid_params, value_out_of_range, range_unknown, set_slider_not_applied).
  • Every terminal mission_status carries step_index (on succeeded, the last step), so the agent can say which chained step failed.
  • continue_on_failure missions emit step_failed and keep going.
  • New flags.nativeBridge gates the synthetic-pointer tap fallback.

Multi-step missions #

  • Cancels and newer missions take effect immediately (waits, retry delays and attempts race the cancel signal); a pre-cancelled mission no longer cancels the running one; a cancelled step emits only cancelled.
  • A blind step right after a settle wait polls up to 2 s for a slow next screen before failing.
  • Malformed steps fail invalid_mission; unexpected errors fail exception; terminal statuses are never evicted from the outbound queue.
  • Standalone highlights (guided walkthrough) run as internal hl_ missions: full find ladder, scroll into view with align, re-find before drawing; duration_ms: 0 stays until cleared. Highlights yield while a mission runs.

Execution safety #

  • Taps: the synthetic pointer needs >=50% visibility and a hit test that reaches the target; a tap with no visible effect is never retried (no double side effects); agent taps are not counted as user clicks.
  • set_text on a non-editable target writes only to a field BOUND to the matched label (or takes the slider path), with no focus-tap side effect; clears are verified.
  • A measured-disabled target fails fast with target_disabled; the enabled twin wins ties.
  • back uses the host hook / Navigator first and restores a custom tab only when nothing can pop. Retries reuse the node found on the first attempt.
  • Text-match promotion never climbs past a control; find_candidates honours scope, role and forbid filters; scrolling prefers the topmost layer's vertical scroller, skips pagers, and waits for pagination.
  • The stable-ID rung cross-checks text, so a shifted ID cannot tap the wrong sibling ("3 Months" vs "6 Months").

Result accuracy #

A mission is reported succeeded only when the INTENDED target was acted on and verification supports it; otherwise it is failed with a specific reason (the terminal vocabulary is unchanged).

  • set_text never types into a field whose own label/hint names something else ("PIN" for "Full Name") and never redirects to merely the nearest field: the field must sit in the label's own container, directly below / right of it with nothing labelled in between, or be the one field whose label agrees. Otherwise target_mismatch, nothing typed. Obscured fields are skipped unless the request asks for a PIN / password.
  • Side-effect verbs (set_text, click / tap / navigate, check, select, set_slider) match whole words only ("PIN" ≠ "Pincode"), refuse an ambiguous match (ambiguous_target, candidates still sent on disambiguating) and refuse a qualified label for a write ("Name" → "Nominee Name"). Read-only verbs keep the lenient ladder.
  • Taps: a tappable twin must have the same text ("Name" never taps "Change Name"); a container's only button is tapped only when it agrees with the request (target_mismatch otherwise). A stable id now naming a different number ("12 Months" for "6 Months") is not acted on. A retry re-finding by rectangle must agree on the label.
  • Verification is target-scoped: a tap needs a route change, an overlay opening / closing, or a change on the target, its option group, its own subtree or its bounded container. Changes elsewhere on the page — and anything that was already changing before the tap (a baseline capture ~200 ms earlier) — no longer count. navigate needs a change of place; optional params.expect_screen must match.
  • set_text verifies the requested field's VALUE (never its label), which must have changed unless it already held exactly the text (set_text_already_satisfied); formatter tolerance (case, spaces, separators, masks) is kept.
  • When it cannot look, the SDK says so: verification_unavailable (one retry for idempotent verbs, none after a tap / back), check_not_applied, select_not_applied, back_had_no_observable_effect. A tap after which something changed elsewhere on screen (not on the target, and not a self-updating clock or countdown) is reported verification_unavailable with evidence unattributed_change — never success, and never "nothing happened".
  • Second look, observation only. When a dispatched tap / navigate / back cannot be confirmed, the SDK re-captures once ~1.5 s later and re-runs the verifier — a late, network-driven update becomes a verified success. The action is never dispatched a second time; still unconfirmed → the original failure is reported.
  • read_field on an empty field fails field_has_no_text instead of answering with the label.
  • Additive wire keys: verification_result gains requested_stable_id, requested_text (label only, ≤60 chars, never for obscured fields), acted_stable_id, acted_role, redirected, match_source, verified, value_matched (a boolean, never the value); terminal mission_status gains steps_completed, steps_total, steps_skipped, steps_failed and mirrors the identity keys on failure. Inbound set_text values are redacted in the debug wire log.
  • More conservative on device: taps whose only visible effect is elsewhere on the screen (a counter, a badge, a status line outside the tapped card) now report tap_had_no_observable_effect instead of success.

Icon-only controls and custom tab bars #

  • Small icon-only tappables are named from what they draw: an image's asset file name (ic_home_active.png → home), a Material / Cupertino icon's literal name (Icons.pie_chart → pie chart), or — for a tab — "Tab i of n". Large wrappers are never named; a real label is never overridden.
  • Custom bottom-navigation rows are reported as tab (excluding Material button bars, grids and keypads) and kept first under the 15 KB budget.
  • Custom tab rows report selected when exactly one item is drawn differently, else from the tab the session saw lead to the current screen.
  • back after a custom-tab switch re-selects the previous tab.

Fixes #

  • A modal no longer hides on-screen UI outside it; an inline Dialog no longer turns its page into an overlay; sheet scrims attach to their sheet.
  • Effect durations of 0 no longer crash the highlight / border / awakening animations (clamped to 1 ms).
  • mission_exploration and mission responses are trimmed to fit the 15 KB transport cap instead of being dropped.
  • Cache: on-screen nodes are never capped away; over-cap overlays no longer re-upload on every capture; a 200 with zero rows written is retried; a file the backend keeps rejecting is quarantined instead of blocking sync; sync enables as soon as the gate and API key allow it.
  • Lifecycle flushes send a diff, not a full baseline; the active border is dismissed on stop.
  • Release builds: tracker IDs no longer collapse to Instance of … (0.2.0 formats kept for strings, numbers, enums, dates and lists); WireLog and inbound frame logging are silent.
  • The SDK's own panel is no longer captured as host UI.

0.2.0 #

Native-parity release: the Flutter SDK's config wiring, call/agent modes, back navigation, and widget UX brought in line with the Android and React Native SDKs and the revrag-core wire contract. Verified live on a physical device.

Breaking changes — migration required #

  • Multi-agent (flowName) support removed — React / React Native parity. One integration is one agent, so the per-flow scoping is gone:
    • embedInitialize, EmbedProvider and embedEvent (and embedTrack*) no longer take a flowName.
    • EmbedWidget.enabledRoutes changes shape from Map<String, List<String>> (flow → routes) to a flat List<String>: enabledRoutes: {'main': ['home','account']} → enabledRoutes: ['home','account'].
    • EmbedWidget.groupContinuity / groupDelays (flow-keyed maps) become the single continuity: / buttonDelay:.
    • EmbedRouteManager's flow surface (currentFlow, catalogFlow, getFlowForRoute, setCurrentFlow, flowRoutes, continuityForFlow / delayMsForFlow / delayPolicyForFlow) is replaced by a flat API (activeGroup, isRouteEnabled, groupForRoute, enabledRoutes, continuity, delayMs, delayPolicy). Config, cache and event scoping collapse to one agent; existing on-device caches stay valid (the default scope is unchanged). Multi-agent apps must split into separate integrations.
  • EmbedWidget apiKey / embedUrl / primaryColor / groupInsets removed (and the EmbedButtonInset type). Credentials come from embedInitialize; the FAB position (widget_config.position) and colors (widget_config.colorPalette) come from the backend — the host no longer overrides them on the widget. Use a per-widget key only via embedInitialize.
  • EmbedWidget / EmbedProvider rightPadding / bottomPadding removed. FAB position is now driven solely by the backend widget_config (right_padding / bottom_padding / widget_position) — the host no longer overrides it in code. Set the position from the dashboard instead; remove the two params from your EmbedWidget call.
  • embedInitialize is now the single, all-named intake — embedInitialize(apiKey: …, appVersion: …, embedUrl: …). apiKey moved from positional to a required named parameter, and appVersion is now required (embedSetAppVersion() and the package_info_plus auto-derivation are gone).
  • EmbedProvider removed. It only forwarded apiKey / embedUrl / appVersion into embedInitialize and mounted an EmbedWidget; with embedInitialize as the single intake it was a redundant wrapper. Call embedInitialize + wrap with EmbedWidget directly.
  • Server-driven panels/cards now render only in workflow mode. A call the user starts from the FAB (or the inactivity auto-trigger) is a co-pilot call and drops inbound panel frames. To keep panels, start the call from host code with EmbedWidget.startCall(agentTriggerMode: AgentTriggerMode.WORKFLOW).
  • other_data flags removed — no peer SDK ever read them: widget_tree_snapshot_enabled and screen_capture_enabled (widget-tree snapshot sends now gate on action_config.flags.dataCapture), and embed_route_allowlist (the platform route allowlist is now host-prop-only via EmbedWidget(usePlatformRouteAllowlist: true)). Tenants relying on the old flags must move the opt-out to dataCapture / the host prop.

New #

  • AgentTriggerMode (co-pilot / workflow) — host-declared at EmbedWidget.startCall(agentTriggerMode:) and latched per call; a pure resolveCallPlan decides who owns the UI, whether panels render, and whether the avatar surface opens. The enum values are CO_PILOT / WORKFLOW (identifier-for-identifier with Android), and the mode's cross-SDK wire string is lowercase copilot / workflow — serialize with mode.wire, read back with parseAgentTriggerMode(String?) (case- and separator-insensitive, mirrors Android's parser).
  • Visibility groups (buttonVisibility) — React Native parity. EmbedWidget(buttonVisibility: EmbedButtonVisibilityConfig(groups: [...])) lets different sets of screens carry different FAB continuity / pre-show delay / delay-policy (EmbedButtonGroupConfig{id, screens, continuity, delayMs, delayPolicy}). Resolves per current route (first matching group wins); a group's screens also join the allow-list. Screens in no group fall back to the widget-level continuity / buttonDelay / embedButtonDelayMs.
  • EmbedWidget.expandWidget() / embedExpandWidget() — programmatic inverse of collapseWidget() (emits agent_tap_to_open); startCall() does not auto-expand.
  • EmbedWidget.openAvatarScreen() — programmatically open the full-screen agent surface (starts a workflow call if none is running, else re-opens the surface after a collapse).
  • action_config coverage completed — dataCapture master gate, awakeningEffect / activeBorderGlow / highlighting / clickTracking kill-switches, the three themed gradients, and all 26 effects.* tuning knobs (unset knobs reproduce the built-in look exactly). New: an active-border watchdog and nudge-time FAB breathing.
  • widget_config completed — position.* and agentAvatar.avatarSize merged; sizing follows the native AvatarSizing rule and bar typography scales with it. isCollapsed opening state honored once per lifetime.
  • call_id latched from /token and sent flat on agent_conversation_started / _ended (Android parity).
  • System-back rung — back now sweeps every reachable navigator (deepest-first, PopScope-aware) so nested / per-tab / activity-per-screen hosts no longer exhaust the ladder.

Fixes & behavior (native parity) #

  • Inactivity: nudgeDelay <= 0 = off; show_popup shows only with a non-empty tooltip; shouldAutoCollapseCard (captions suppress the fold and cancel a running countdown).
  • Widget UX: one centered 90/60/40 expanded-bar width; awakening plays only while no call is live and collapse returns the FAB to its dock; static collapsed avatar; avatar-open icon hidden in co-pilot; ink-square and glow-bloom collapse artifacts fixed; a silent config revalidate no longer collapses an open bar; avatar cannot surface on a co-pilot call (stale-plan race closed).
  • Memory (OOM guard): the ExplorationLog node union is now call-scoped (reset on AgentRuntime.stop, not only at mission start) and capped LRU to 12 screens, so it can no longer grow unbounded across calls for the life of a long-lived host process.
  • Internal: lib/src/embed.dart split into focused part files; comment cleanup; CLAUDE.md and docs/CONFIG_WIRING.md added.

Fixes (device-verified) #

  • Orb-flight performance. The awakening overlay no longer paints a full-screen radial-gradient bloom or two rainbow sweep-shader rings per frame: the bloom is bounded to a circle and a single burst ring is drawn, with smaller blur radii. On a mid-tier device this cut janky frames from ~10% to ~6% (raster p95 22.8 ms → 16.9 ms) — the bottleneck was fill-rate/shader churn, not blur.
  • Mic and speaker toggles are single-flight. Rapid mute/unmute (or speaker) taps no longer stack concurrent native setMicrophoneEnabled / setSpeakerOn calls that churned the audio session and lagged the agent's speech; a burst now collapses to one native op at a time, and the stale-isMuted read is gone.
  • FAB collapse no longer dips. On call end the FAB settles straight at its dock instead of dropping ~14 px and springing back — the elasticOut landing bounce that restarted after the FAB had already docked is removed.

Previously staged (0.0.21-dev) #

Behavioral change — retry policy. A tap/navigate whose SEMANTIC dispatch fired but produced zero observable evidence now fails after ONE attempt (VerificationOutcome.unknown, terminal): retrying an already-fired action re-fires it physically (double/triple submits). Synthetic-pointer fallbacks and null after-snapshots keep their retries — nothing semantic was delivered. Hosts that tuned retriesPerStep for this case should rely on the backend's failure_reason: tap_had_no_observable_effect to re-plan instead.

Source-breaking for StepVerifier subclasses. StepVerifier.verify gained an optional named parameter UiNode? resolvedTarget (the find-ladder winner the runner acted on). Custom verifier overrides must add it (and may ignore it).

Also in this release: failure_reason emitted alongside error on mission_status (the backend reads only the former); node model gains value/checked/editable/secure with capture-time (sticky) secure redaction — typed field contents no longer ride text or stable ids; find ladder edge fixes (rung-1 promotion, single-token subtree hatch, IoU floor, normalised forbid_text, container-anchored inside_text); config cache un-brick (other_data versioned + TTL + revalidate; isLive hides only on explicit false); wait clamp; stale-node tap refusal; CI + lib/core test suite (180+ tests).

0.0.20 #

Fixes #

  • Fixed agent audio dropping when a wired/Bluetooth headset is connected mid-call. The SDK no longer forces the audio route on a polling timer; it relies on LiveKit's native headset prioritization and reacts only to real device-change events.
  • The inactivity tooltip no longer appears while a call is connecting/connected (previously it could pop up after the bar auto-collapsed).
  • The inactivity tooltip now auto-dismisses on any user interaction (tap, scroll, drag), not only a FAB tap.

Features #

  • The expanded voice bar auto-collapses back to the FAB after a call connects while keeping the call live. Delay is configurable via collapsedView.collapsedTime (seconds, default 15s).
  • Added a "live call" pulse around the collapsed FAB that appears only after the bar fully collapses and only while the user or agent is speaking. Color is configurable via colorPalette.pulseColor (default purple #B391F3).
  • The default avatar fallback now uses a Lottie animation instead of the Material chat/person icons.

Tweaks #

  • Reduced the expanded bar height, Connect-button padding, and mute/end-call button sizes.
  • Bumped the SDK version reported to the backend (sdk_version) to 0.0.20.

0.0.19 #

Fixes #

  • Relaxed the livekit_client constraint from the exact pin 2.6.5 back to ^2.5.3. The exact pin transitively forced meta ^1.17.0 (required by livekit_client 2.6.5), which broke pub get for apps on older Flutter SDKs that pin meta 1.16.0. The range lets pub select a compatible livekit_client version per app.

0.0.18 #

FAB pre-show delay & per-flow delay policy #

  • Added embedButtonDelayMs (on EmbedWidget / EmbedProvider) — global delay before the FAB appears after navigating to an enabled route. Default 0 (no delay).
  • Added groupDelays (Map<String, EmbedButtonDelay>) — per-flow delay override with EmbedButtonDelayPolicy: perScreen, oncePerGroupEntry, oncePerAppSession. Falls back to embedButtonDelayMs.
  • Added React-API aliases on EmbedButtonContinuity: continuous (= keepVisible) and perScreen (= reset), plus EmbedButtonContinuity.fromString / EmbedButtonDelayPolicy.fromString parsers.

Fixes #

  • Nudge/inactivity countdown now starts when the FAB becomes visible (after embedButtonDelayMs), not when the route is first entered.
  • inactivity_behaviour: "auto_trigger" now maps to InactivityMode.AUTO_TRIGGER (auto-starts the call like start_call); previously it silently fell back to showing the popup. Added InactivityMode.fromBehaviour.
  • FAB no longer renders off-screen on the app's initial/home route — position is recomputed once the screen size is available (post first layout) and on metrics changes.
  • Fixed agentTapToOpen / agentTapToClose enum identifiers (backend values agent_tap_to_open / agent_tap_to_close unchanged).

Docs #

  • Added doc/fab-visibility-advanced.md (Flutter FAB visibility guide) and doc/embed-button-delay.md.

0.0.17 #

  • Typewriter transcription panel: vertical expansion from bottom to top when type == "calculation" data received via LiveKit
  • FAB positioning: widget_position (bottom-right, bottom-left, top-right, top-left) now respected from backend config
  • Fixed bottomPadding and rightPadding not applying correctly to FAB position
  • Bounce animation on FAB when transcription panel closes
  • Analytics event names updated: agent_tap_to_open / agent_tap_to_close
  • SdkEventName enum added for all internally-fired analytics event names (exported as public API)
  • All public event APIs (embedEvent, embedTrackEvent, etc.) now return Future<bool> for send-success feedback
  • EmbedRouteListener widget added for GoRouter / ShellRoute automatic route detection
  • EmbedNavigatorObserver now accepts optional nameExtractor for GoRouter alias support
  • Route matching now strips leading slashes — GoRouter paths (/home) match aliases (home)
  • Cache-first config strategy restored in _fetchUIConfig with API fallback on cold start
  • Removed all debug logs; all exceptions handled internally — zero crash guarantee for host app
  • Removed dead _buildTranscriptionPanel overlay (superseded by inline vertical expansion)

0.0.16 #

  • Graceful exception handling across SDK — zero crash guarantee
  • Fixed event routing and SDK key resolution issues
  • Stability Improvements

0.0.15 #

  • Stability Improvements

0.0.14 #

  • Minor Bug Fixes and Stability Improvements

0.0.13 #

  • Minor Bug Fixes and Stability Improvements

0.0.12 #

  • Added capability to send ANALYTICS_DATA event from screens which are not part of enabled routes.

0.0.11 #

  • Added ANALYTICS_DATA event for tracking structured analytics events with a specific event identifier

0.0.10 #

  • Minor Bug Fixes and UI improvements

0.0.9 #

  • Added rightPadding and bottomPadding to set the initial position of Embed Widget

0.0.8 #

  • Added onPermissionStatusChanged callback to recieve the permission status change events
  • Minor Bug Fixes and Stability Improvements

0.0.7 #

  • Minor Bug Fixes and Stability Improvements

0.0.6 #

  • Bluetooth Headset Support added
  • Added Inactivity Actions
  • Minor Bug Fixes and Stability Improvements

0.0.5 #

  • Added Multi Flow Support with enabledroutes

0.0.4 #

  • Added Support for Re-initialisation of embed agent

0.0.3 #

  • Added Support for Buttons
  • Added Route based activation
  • Added embedEvent call for user generated USER_DATA nd SCREEN_STATE events
  • Added Embed Config Service for management of apiKey and embedUrl
  • Improved widget context extraction
  • Updated Documentation

0.0.2 #

  • Removed the requirement for bluetooth permissions
  • Updated License

0.0.1 #

  • Initial release of Embedded Agent SDK
  • Core functionality for automatic widget tree traversal
  • Real-time widget monitoring with collapsible interface
  • Comprehensive widget property extraction
  • Cross-platform support for Android and iOS
  • Example applications demonstrating SDK usage
  • JSON output format for widget information
  • Performance-optimized widget tree analysis
0
likes
120
points
1.05k
downloads

Documentation

Documentation
API reference

Publisher

verified publisherrevrag.ai

Weekly Downloads

A powerful Flutter SDK that provides a powerful voice-enabled AI-agent functionality with real-time widget tree monitoring for screen context fetching and realtime voice communication.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, http, livekit_client, lottie, path_provider, permission_handler, shared_preferences

More

Packages that depend on embed_flutter

Packages that implement embed_flutter