find_ai_chat 0.8.0 copy "find_ai_chat: ^0.8.0" to clipboard
find_ai_chat: ^0.8.0 copied to clipboard

Platformweb

Flutter SDK for the Find AI chat assistant. Drop-in widget with floating, drawer and embedded modes, SSE streaming, and signed-mode visitor auth.

Changelog #

0.8.0 #

  • Links inside a message are now tappable. Markdown links were already painted as links (primary colour, underlined) but nothing happened when you tapped them: the widget never passed onTapLink to the Markdown body and the package only fires its tap recognizer when that callback is set. Since the URL hides behind the link text, a visitor could neither open it nor copy it. This matters most when the assistant answers with a product or a course: the one thing the visitor is meant to do with that answer did not work.

  • FindChatCallbacks.onLinkTap lets the host app take a link before the SDK opens it. Return true if you handled it, false (or leave the callback out) to let the SDK open it externally. It exists because assistants usually link back into the host app itself, and sending a visitor to a browser tab to reach a screen they already have in front of them loses them:

    FindChatCallbacks(
      onLinkTap: (url) {
        if (url.host != 'app.mycompany.com') return false; // browser
        context.go(url.fragment);                          // in-app
        return true;
      },
    )
    
  • Only http, https, mailto and tel are opened. The link target is written by a model out of tenant data, not by the host app, so javascript: and data: are dropped before anything runs: on Flutter Web opening one of those means executing code in the page that hosts the chat. A dropped link is silent, which is what the widget already did before links were tappable. Relative links are dropped too: a message has no base to resolve them against.

  • New link_tapped event on FindChatCallbacks.onEvent, carrying the target Uri. It is emitted only for links the SDK accepted, and before the host callback decides, so analytics sees the same link that is about to open.

  • Adds a dependency on url_launcher.

0.7.0 #

  • Deleting a conversation now deletes it on the server (deleteConversation()), instead of only on the device. It takes the thread, its messages, its trace and the engine's state — the flow node, the history the AI nodes read, a half-finished data collection — so a visitor who starts over is not left answering a form they can no longer see. Pass a conversationId to delete another one from your own list screen; without it the active conversation goes, and the panel empties with it. One rule now covers the surface: clear* only touches this device, delete* talks to the server, so clearConversation() and startNewConversation() keep their old, local behaviour.
  • emptyConversation() wipes the same content but keeps the thread: same id, still in listConversations(), no messages.
  • Two new items in the "+" menu, "Vaciar conversación" and "Eliminar conversación" (FindChatActionIds.emptyConversation / .deleteConversation), which appear only when the connection allows deleting — visitor_can_delete, new on FindChatConfig, always true on signed connections and opt-in per connection on public ones. It defaults to false, so against a backend that does not send the flag neither item is drawn. Both are disabled during a turn (the worker would recreate the conversation when the turn ends) and when there is no conversation yet. The three actions leave an equally empty panel but are three different outcomes in a visitor's chat list — start over keeps the old thread and adds one, emptying keeps the thread without its messages, deleting removes it — so all three ship, and hiddenActions shortens the menu where the distinction does not apply.
  • Neither method throws: the action menu invokes them without awaiting, so a failure lands in state.errorMessage and shows in the panel's error banner, and the call returns false. Success shows nothing at all, on purpose — the API answers 204 whether or not the conversation existed, deliberately, since a 404 would let a visitor probe other people's ids, so "conversation deleted" would claim more than the server said. For the same reason retrying is always safe.
  • Ten new FindChatLabels fields, for the two new actions and their confirmations.
  • The widget speaks English too (strings, new FindChatStrings). It is the complete bundle — panel, composer, voice and error messages — so one parameter switches the language, and the per-area label objects still apply on top for single strings. FindChatStrings.en.copyWith(...) covers a language the SDK does not ship. Nothing changes by default: without strings the chat stays in Spanish. Following the app's own language is opt-in (strings: FindChatStrings.of(context)) because MaterialApp reports en_US until supportedLocales is configured — deducing it would have turned existing Spanish chats English on upgrade.
  • Error messages are translatable at last. They used to be the one text the SDK baked in: the controller has no BuildContext, so it wrote Spanish straight into the state. It now stores a typed reason — FindChatState.errorKind, plus errorDetail for the backend's own words — and the widget resolves it against the chosen language when it renders. state.errorMessage still carries the Spanish text for code that reads it.
  • Fix: the confirmation card's buttons wrap instead of overflowing. Their labels come from whoever defines the action, and a slightly longer pair — "Cancelar" and "Eliminar", or any translation — used to run past the edge.

0.6.0 #

  • Voice input in the composer (audio on FindChatWidget, new FindChatAudioConfig). Off unless configured: passing it adds a mic button to the left of send that records, transcribes with the platform's speech recognition, and hands the text over. While recording, the text field is replaced by a row with cancel, an animated waveform, the elapsed time and finish; the draft that was in the field survives the round trip. Three ways to land the transcript, via transcriptMode: into the composer to review (the default — dictation usually needs a fix and sending on its own is surprising), sent straight away, or shown in a preview card to confirm. Auto-send falls back to the composer when a turn is in flight so a dictation is never dropped. Permission, network, "nothing heard" and unsupported-engine failures each get their own message; only the unsupported one hides the mic, because it is the only one retrying cannot fix.
  • Audio visualization driven by the real microphone amplitude (getUserMedia → AudioContext → AnalyserNode → RMS on web, the engine's level on native): louder speech, taller bars; silence leaves them nearly still. When amplitude cannot be measured it degrades instead of freezing — voice-activity detection first, then a smoothed pseudo-random animation while recording. A visualization failure never blocks recording or transcription. Rendering rebuilds no widgets per frame: one ticker advances the animation and only the bars repaint.
  • Configurable empty state (emptyState, new FindChatEmptyState and FindChatSuggestion). Title, description and clickable shortcuts before the first message, in place of the welcome bubble. label is what the visitor reads and message what gets sent, so a short button can carry a long prompt; title and description fall back to the connection's own, so an existing setup needs no duplication. Not passing it keeps the previous behaviour.
  • Callbacks and events (callbacks, new FindChatCallbacks and FindChatEvent): typed hooks for suggestions, recording and transcription, plus a single onEvent channel for analytics — one hook to wire instead of one per feature. message_sent carries where the message came from (typed, dictated, or a suggestion).
  • Every visible string is now overridable (labels, new FindChatLabels, and FindChatAudioLabels inside the audio config): header title, close tooltip, action menu, the new-conversation action and its confirmation, and the load error. With composerLabels this covers the whole widget, which is what translating it required. Setting loadErrorMessage also replaces the reason the backend returned, so a technical or foreign-language string cannot reach the visitor. Turn error messages are still not overridable.
  • Internally, the four new options did not multiply the plumbing: the three view widgets now pass a single FindChatViewProps bundle down to the panel, so adding an option touches one place instead of eleven (each view, its overlay twin, and the hand-written comparison that decides whether the overlay entry needs rebuilding).
  • New dependencies: speech_to_text and web. Both are only used by the voice module; a widget without audio never touches them.

0.5.0 #

  • Fix: the message list opens on the last message. On first mount (history already loaded), after switching conversations and after clearing, the list jumps to the bottom instead of showing the first message. Auto-follow during streaming now only applies while the visitor is at the bottom: scrolling up to re-read something no longer drags them back down, and sending a message re-engages it.
  • Composer redesign, after the Claude mobile / Claude Code composers: a bordered, rounded box with a single row ("+" action button, text field, send button), a focus ring, up to 6 auto-growing lines with bottom-aligned buttons, and a caption line under the box for the keyboard hint or the in-flight status. Shared by both visual styles; the accent follows the style (brand color in classic, monochrome in gptStyle). inputHeight keeps pinning the text field height.
  • Enter sends, Shift+Enter inserts a newline on desktop platforms (native and web). Before this, on web, Shift+Enter also sent, so multi-line messages could not be typed. On touch platforms the keyboard's action key still sends.
  • The text field stays editable and focused while a turn is in flight: the send button is disabled and the caption shows "Pensando…", but the visitor can type the next message without waiting.
  • Action menu moves to a "+" button on the left of the composer, replacing the long press on the send button, which was hard to discover. The menu opens upward from the composer in all three modes: the chat panel now hosts its own Overlay, so popups are positioned and clipped within the panel instead of spilling out of the floating card. The header no longer has the ↻ button: with showHeader: false it was unreachable, while the composer is always visible.
  • The two built-in entries collapse into one, Nueva conversación (FindChatActionIds.newConversation, new exported class): both only cleared the device-side state and left the backend conversation untouched. It confirms before running startNewConversation(). The clear_conversation id is gone, and FindChatActionConfirmation.confirmLabel now defaults to "Confirmar" instead of "Eliminar".
  • hiddenActions on FindChatWidget: ids of actions to hide from the menu, SDK or host-added. Empty by default, so everything shows; when nothing is left, the "+" button is not rendered.
  • composerLabels on FindChatWidget (new exported model FindChatComposerLabels): override the field placeholder, the keyboard hint and whether it shows (showKeyboardHint: null = desktop only, true/false = always/never), and the status label while a turn is in flight.
  • Neutral surface palette (no seed tint) in light and dark mode; the brand color is reserved for accents. The chat's text theme now follows the chat's brightness rather than the host app's, so markdown in replies stays legible when the chat and the host use opposite themes. themeBuilder still runs last and can override all of it.
  • Markdown in assistant replies: styled inline code and code blocks, block quotes, headings and links consistent with the chat typography.
  • Turn errors (network, 429, …) render as an inline banner above the composer instead of a bare line of text.
  • Action menu and confirmation restyled after Claude's popovers: rounded card with a hairline border and soft shadow, 40px items with a muted leading icon and rounded hover, "+" that turns into "×" while open, and a filled primary button in the confirmation step. Menu items and dialog buttons now inherit the host's font family.
  • Fix: the composer text sits visually centered against the "+" and send buttons. InputDecorator shifts the text down by (line height − font size) / 2 whenever textAlignVertical is set, on every renderer, so the composer no longer uses it: the field is centered structurally inside a box as tall as the buttons, and inputHeight now bounds the field to the lines that fit instead of using expands. Verified by pixel measurement in Chrome.
  • Fix: in floating and drawer modes, changing theme, visualStyle, colors or any other FindChatWidget prop on a rebuild had no effect until the widget was remounted, because the panel's OverlayEntry was never marked for rebuild.
  • Example app: runs without a backend by default. DemoChatBackend is an in-memory http.Client that answers the webchat endpoints (config, history, messages, SSE stream) with scripted replies and keyword-driven scenarios (largo, markdown, lento, error, falla). A real backend is opt-in via --dart-define=FIND_CHAT_CONNECTION_ID / FIND_CHAT_BASE_URL.

0.4.0 #

  • Action menu on the send button: long-pressing the send button opens a floating menu of chat actions. Works in all three display modes and with showHeader: false, so the actions stay reachable when the host app hides the header. The header's ↻ button is unchanged.
  • Ships one action, Eliminar conversación: asks for confirmation, then runs clearConversation() — messages and the persisted conversation id are dropped on this device only, the backend conversation is untouched. Disabled while a turn is in flight.
  • actionsBuilder on FindChatWidget composes the menu. It receives the SDK defaults (already resolved against the current state) and returns the final list, so host apps can append, reorder, or drop entries; returning an empty list turns the menu off. New exported models: FindChatAction and FindChatActionConfirmation.
  • The menu and its confirmation render via OverlayPortal instead of showMenu/showDialog: in floating/drawer modes the panel is inserted above the Navigator's overlay entries, so route-based popups would be painted behind the chat.

0.3.0 #

  • Per-turn options: scope what a turn can consult (RAG documents, dataset rows, …) by passing an opaque map that travels as the options field of POST /messages. Available on FindChatWidget / FindChatController / FindChatClient.sendMessage(), plus FindChatController.setOptions() to re-scope an ongoing chat — useful when the host app navigates between screens (e.g. from one product to another). The SDK never inspects the map's contents: the app's backend builds it, so extending the contract server-side needs no SDK release. Omitted from the request body when null or empty.

0.2.2 #

  • Add direct bubble color overrides for user and assistant messages.
  • Add direct text color overrides for user and assistant message bubbles.
  • Add inputHeight to customize the bottom text field height.
  • Fix: vertically center the message input text.

0.2.1 #

  • Add showHeader to FindChatWidget and the presentation views, allowing host apps to hide the built-in chat panel header.
  • Add themeBuilder, an advanced styling hook that receives the SDK-resolved ThemeData and returns a modified copy.
  • Fix: the message input no longer draws an extra internal border when focused.

0.2.0 #

  • Signed mode (auth_mode: "signed" connections): new tokenProvider callback on FindChatWidget / FindChatController / FindChatClient attaches the visitor JWT as Authorization: Bearer to every request (including each SSE reconnection, so long streams survive token expiry). On 401 the client fetches a fresh token and retries once; a persistent 401 throws the new FindChatAuthException.
  • Multiple conversations per visitor (signed mode): FindChatClient.listConversations() (GET /conversations), FindChatController.listConversations() / selectConversation() / startNewConversation(), and a conversationId getter for the active one.
  • Fix: GET /history message ids are numeric in the backend response; parsing no longer assumes a string.

0.1.0 #

  • Initial release: FindChatClient (HTTP + SSE against the public webchat API), FindChatController, FindChatWidget with three display modes (embedded, floating, drawer), light/dark theming and visual style (classic/gptStyle) configurable via explicit override or inherited from connection config, and FindChatSessionStore for visitor_id/conversation_id persistence.
2
likes
160
points
216
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter SDK for the Find AI chat assistant. Drop-in widget with floating, drawer and embedded modes, SSE streaming, and signed-mode visitor auth.

Homepage
Repository (GitHub)

License

MIT (license)

Dependencies

flutter, flutter_markdown_plus, http, shared_preferences, speech_to_text, url_launcher, web

More

Packages that depend on find_ai_chat