flutter_ai_client 0.3.0
flutter_ai_client: ^0.3.0 copied to clipboard
Provider-agnostic chat controller for flutter_ai: wraps any LlmProvider with optimistic send, cancellation, regeneration, and frame-batched streaming.
Changelog #
0.3.0 #
- Add
UseChatController.load(AiConversation)— swaps the transcript in place (cancelling any in-flight turn) so hosts can switch threads without disposing and recreating the controller. (#136) - Add
KeyValueChatThreadStore, a persistentChatThreadStorebacked by anyKeyValueStoreyou supply (shared_preferences, a file, secure storage, …), so chat history survives app restarts without the package depending on a storage plugin. (#137) - Add
suggestFollowUps(conversation, provider, {count, options})— generates contextual follow-up prompts (for theAiSuggestionsstrip) via a one-off model call, so follow-ups can be dynamic instead of a static set. (#140)
0.2.5 #
- Fix: the controller no longer reports
idlewhile the agent loop runs its tool executor between model calls. A newChatStatus.executingTools(included inisBusy) keeps the turn marked busy, so UIs don't re-enable input mid-turn andattachStoredoesn't persist a transcript with unanswered tool calls. - Fix:
selectBranchis now a no-op whenever a turn is in flight (including the tool-execution phase), preventing a mid-loop branch switch from corrupting the transcript. - Fix: the default message-id generator now uses a per-controller random prefix
(
msg-<prefix>-<n>) instead of restarting atmsg-0, so seeding a controller with a rehydratedChatStoretranscript no longer produces colliding ids. Pass a customidGeneratorto override. - Fix: interrupting a stream with
submit/addToolResults, and an in-bandStreamErrorEventwith nomessageId, no longer leave the interrupted message stuck in thestreamingstate (a permanent typing indicator that also got persisted). The trailing message is now finalized. - Fix: a synchronous throw from
provider.sendor atrimHistorycallback is now caught and surfaced asChatStatus.error(with the turn future completing), instead of escaping — which left the status stuck atsubmitted, or became an unhandled zone error inside the agent loop.
0.2.4 #
keepLastWithSummary: a context strategy that folds a caller-supplied rolling summary of older turns into the request (as a syntheticsystemmessage) instead of silently dropping them — compaction that preserves load-bearing context. Your app owns producing/persisting the summary (any model or heuristic, saved viaChatStore); the strategy just injects it and windows the recent messages. No memory service baked in.
0.2.3 #
- Observability:
UseChatController(observer:)accepts aChatObserverthat receives the agent lifecycle — turn start, each model request, response with tokenAiUsage+ finish reason, tool calls/results, errors, and turn end. Shaped after the OpenTelemetry GenAI semantic conventions, with no OTel dependency — map the callbacks onto your own tracer or analytics sink. Opt-in and no-op by default.
0.2.2 #
- Agent guardrail:
maxIdenticalToolCalls(opt-in, 0 = off) halts the agent loop with a typedAgentLoopExceptionwhen the model keeps requesting the same tool call (identical name + args) after it has already run that many times in a turn — a runaway-loop guard that stops before burning tokens up tomaxSteps. Complements the existingtokenBudgettoken ceiling.
0.2.1 #
- Fix: raise the
flutter_ai_corelower bound to^0.1.11— the controller usesAiUsage(added in core 0.1.3) and later APIs, so the old^0.1.0bound let dependency downgrades resolve a core that couldn't compile. - Docs: shortened the pubspec
descriptioninto pub.dev's 60–180 character window.
0.2.0 #
-
BREAKING:
onToolCallsnow receives a second argument, anAiToolCallSignal. The controller cancels it when the turn is stopped, replaced, or disposed while the executor is still running, so long-running tools can abort in-flight work instead of finishing only to have their result discarded. Observe it viasignal.isCancelled,await signal.whenCancelled, orsignal.throwIfCancelled().Migration: change
onToolCalls: (calls) async { ... }toonToolCalls: (calls, signal) async { ... }. Honoring the signal is optional; adding the parameter is required.
0.1.8 #
- Docs: refreshed the README listing with a hero image, screenshot gallery, and badges (consistent across the package family). No code changes.
0.1.7 #
- Tool-argument validation (
validateToolArgs, default on): the agent loop validates each model-produced tool call against the tool'sparametersSchemabefore running it. Calls with invalid args are not executed — an errorToolResultPartdescribing the violations is fed back so the model can self-correct (bounded bymaxSteps). Opt out withvalidateToolArgs: false. - History trimming (
trimHistory): a pluggable strategy that maps the full conversation to the (smaller) conversation actually sent to the provider; the stored transcript is never trimmed. Ships withkeepLastMessages(n)andtrimToApproxTokenBudget(maxTokens)strategies (both preserve the system prefix and avoid orphaning tool results).
0.1.6 #
- Declare supported platforms (Android/iOS/web/macOS/Windows/Linux) for the pub.dev listing.
0.1.5 #
- Turn-sequence guard: a late event from a cancelled stream can no longer mutate
the conversation or leak onto the
eventsstream after a new turn starts. maxBranches(default 20) caps retained regenerations so a long chat can't grow without bound.tokenBudget: stop the agent loop once cumulative usage exceeds the budget (a cost ceiling on top ofmaxSteps).
0.1.4 #
- Thread management:
ChatThread, aChatThreadStore(list/delete on top ofChatStore),autoTitle(conversation), and anInMemoryChatThreadStorefor demos/tests — enough to drive a multi-conversation sidebar.
0.1.3 #
totalUsagegetter onUseChatController: summedAiUsageacross the conversation (feed anAiContextMeteror estimate cost).
0.1.2 #
- Agent loop: pass
onToolCalls(and optionalmaxSteps, default 8) toUseChatControllerand it becomes an automatic agent — when a model turn ends with unanswered tool calls it runs the executor, feeds the results back, and re-prompts until there are no pending calls ormaxStepsmodel calls have run. WithoutonToolCallsbehavior is unchanged (the host drives tools manually viaaddToolResults). Cancellation/stop aborts the loop mid-flight.
0.1.1 #
editMessage(id, text)/editLastUserMessage(text): edit a sent user message (keeping attachments), discard everything after it, and re-run from that point — starting a fresh branch set. Closes the previously dead "edit" affordance inAiMessageActions.- Persistence seam: a
ChatStoreinterface (load/save) plus anattachStore(controller, store, id)helper that debounce-auto-saves the conversation once each turn settles. History is still in memory by default; this makes saving/restoring a thread a few lines.AiConversationis already JSON-serializable, so a store is just encode/decode around your storage.
0.1.0 #
Initial release.
UseChatController— aChangeNotifierwrapping anyLlmProvider:- optimistic, synchronous user-message append
sendText/submit/stop/regenerate/clear- live model/provider switching (
setProvider,setOptions,setTools) - coalesced, injectable notification scheduling (frame-batched streaming)
- raw
eventsstream escape hatch
ChatStatus(idle / submitted / streaming / error).- Exposes
stackTracealongsideerrorso failures can be reported with full context. - A fatal (message-scoped)
StreamErrorEventtears down the active turn so a misbehaving provider can't keep mutating the conversation after a fatal error; tool-scoped errors remain non-fatal. - Re-exports
flutter_ai_core.