ai_plus 0.0.2
ai_plus: ^0.0.2 copied to clipboard
Provider-agnostic AI SDK for Dart and Flutter: one API for OpenAI, Gemini, Claude and OpenAI-compatible servers, with streaming, tools, agents and RAG.
0.0.2 #
This release fixes a number of correctness and security issues found in a full audit. It is source-compatible with 0.0.1; the behaviour changes are listed below.
Security #
- Gemini: the API key is now sent in the
x-goog-api-keyheader instead of the?key=URL query parameter. Before, network errors could put the key into exception messages and logs. - Network exceptions no longer include the request URL.
AiPromptTemplate.rendersubstitutes in a single pass. Before, a{{variable}}inside a user-supplied value was expanded, which allowed template injection.
Bug fixes #
- Streaming tool calls were broken for OpenAI, custom providers and Anthropic. Argument fragments are now accumulated, and each tool call is emitted once with complete arguments.
- OpenAI streams reported
AiFinishReason.unknownon every chunk. Gemini streams had the same problem. NowfinishReasonisnullexcept on the final chunk. - OpenAI: only the first result of a multi-tool turn was sent, so parallel
tool calls (as produced by
AiAgent) failed with HTTP 400. Each result is now sent as its owntoolmessage. - OpenAI structured output always used strict mode, which rejects schemas
with optional properties (including the README example). Strict mode is
now used only for schemas that meet its requirements, and strict schemas
get
additionalProperties: false. AiAgentstopped without running tools when a provider returned tool calls with astopfinish reason, which Gemini always does. The loop now continues whenever tool calls are present.- Gemini tool turns are marked
toolCalls, and function responses use theuserrole. Gemini thought signatures are preserved and sent back, which newer Gemini models require for function calling. AiConversation.streamstored every streamed token as a separate text part, somessage.textin the saved history had a newline between tokens. Streamed replies are now stored as one text part.CacheMiddlewarekeyed responses only on model, role and text, so requests that differed in images, tools, schema, temperature or other parameters could get each other's cached answers. Keys are now a SHA-256 digest of the whole request.RetryMiddlewarereplayed a stream from the start if it failed mid-way, duplicating output. Streams are now retried only before their first chunk.retry-afterdelays are capped atAiRetryPolicy.maxDelay.AiRateLimitException.retryAfterandAiException.requestIdwere never set. They are now parsed from response headers (retry-after,retry-after-ms,x-request-id,request-id).- Error messages for 401, 403, 429 and 5xx responses now include the
provider's own error message. HTTP 408 maps to
AiTimeoutException. - A connection dropped mid-stream now raises
AiNetworkExceptioninstead of a rawhttp.ClientException. LoggingMiddlewareandMetricsMiddlewaremissed errors on streams. Metrics now also record stream latency.AiClient.close()was a no-op. It now closes the HTTP client that a built-in provider created. Clients you inject stay open.- Anthropic streams ignored
errorevents, dropped input-token usage, and treated an emptycontentarray as a parsing error. All three are handled. - Gemini prompts blocked by safety filters now raise
AiContentFilterExceptioninstead ofAiParsingException. AiClient.generatenever sent the schema to providers without native structured output (Anthropic), so the model rarely replied with JSON. The schema is now included as an instruction.AiKnowledgeBase.ask(systemPrompt:)dropped the retrieved context entirely. The context is now appended to the custom prompt.AiKnowledgeBase.ingestBatchvalidatesidsandmetadataListlengths. Generated ids are unique.- Tool results that are not JSON-encodable no longer crash request encoding.
They fall back to
toJson()ortoString(). - Timeout messages are accurate for sub-second timeouts.
- Conversation ids generated within the same millisecond no longer collide.
Behaviour changes #
AiConversation.send/streamadd the user message and the reply to the history only after the turn succeeds. A failed or cancelled turn leaves the history unchanged.AiClient.chatandAiClient.streamdeliver validation errors through the returnedFuture/Streaminstead of throwing synchronously.awaitandawait forcode is unaffected.MemoryVectorStore.addreplaces an existing document with the same id instead of storing a duplicate.- Default models: Gemini
gemini-2.0-flash→gemini-flash-latest, Gemini embeddingstext-embedding-004→gemini-embedding-001(the old models have been retired), Anthropicclaude-sonnet-4-20250514→claude-sonnet-5. - OpenAI sends
max_completion_tokensinstead of the deprecatedmax_tokens, which reasoning models reject, and requests usage in streams viastream_options.CustomProviderkeepsmax_tokens, mapsdevelopermessages tosystem, and omits theAuthorizationheader when the API key is empty. ConsoleAiLogger.errorprints stack traces only whenenableDebugis on.
New features #
headersparameter on every provider and factory, for Azureapi-key, OpenRouter,anthropic-beta,OpenAI-Organizationand so on. The factories also accepthttpClient.- The providers (
OpenAiProvider,GeminiProvider,AnthropicProvider,CustomProvider) andAiHttpClientare exported frompackage:ai_plus/ai_plus.dart, so importingsrc/is no longer needed. AiHttpClient.postSsefor building custom SSE-based providers.AiToolCallContent.metadatacarries provider-specific data that must be sent back with a tool call.MemoryAiCache(maxEntries:)adds LRU eviction andlength.AiMiddlewareis now an extendable base class, so a middleware can override just one method.AiKnowledgeBaseaccepts anyAiVectorStore(it previously requiredMemoryVectorStore),embeddingServicedefaults toclient.embeddings, and astoregetter was added.addDocumentnow returns aFuture.MemoryVectorStore.length, and faster search through precomputed norms.CacheMiddleware.cacheKeyis public, for custom cache implementations.AiNetworkExceptionandAiTimeoutExceptionacceptstatusCodeandrequestId.
Compatibility #
- Minimum Dart SDK lowered from 3.12 to 3.4 (Flutter 3.22+). Verified by running the test suite on Dart 3.4.
- New dependency:
crypto(for stable cache keys). - API documentation for all public members. CI runs formatting, analysis, tests on stable and on the minimum SDK, and a publish dry run.
0.0.1 #
Initial Release #
Core
AiClient— primary orchestrator with middleware pipelineAiProvider— abstract provider interface with factory constructorsAiRequest/AiResponse/AiStreamChunk— core data modelsAiCapabilities— runtime capability introspection
Providers
OpenAiProvider— full support: chat, streaming, tool calling, structured output, embeddings, image inputGeminiProvider— full support: chat, streaming, tool calling, structured output, embeddings, multimodalAnthropicProvider— chat, streaming, tool calling, image inputCustomProvider— any OpenAI-compatible endpoint (Ollama, LocalAI, Azure, Groq, etc.)
Models
AiMessage— factory constructors for all roles (system, developer, user, assistant, tool)AiContent— sealed hierarchy: text, image, audio, file, tool call, tool resultAiUsage,AiFinishReason,AiModel
Features
- Tool Calling —
AiTooldefinition with schema + auto-execution viaToolExecutor - Structured Output —
AiJsonSchema+ai.generate<T>()with native provider support - Streaming — SSE parsing with buffering for all providers
- Conversations —
AiConversationwith auto-managed history, streaming support - Conversation Storage —
AiConversationStorageinterface +InMemoryConversationStorage - Embeddings —
AiEmbeddingServicewith single and batch support - RAG —
AiKnowledgeBasewithingest(),search(),ask() - Vector Store —
AiVectorStoreinterface +MemoryVectorStorewith cosine similarity - Autonomous Agents —
AiAgentwith tool loop, instructions, max iterations
Middleware & Production
AiRetryPolicy— exponential backoff with jitterRetryMiddleware— automatic retry on transient failuresCacheMiddleware+MemoryAiCache— response caching with TTLLoggingMiddleware+ConsoleAiLogger— debug and info loggingMetricsMiddleware— request count, error count, latency tracking
Utilities
AiPromptTemplate—{{variable}}template rendering with validationAiCostTracker+AiPricing— token usage and cost estimation
Error Handling
- Complete exception hierarchy extending
AiException:AiAuthenticationException,AiAuthorizationException,AiRateLimitException,AiNetworkException,AiTimeoutException,AiInvalidRequestException,AiProviderException,AiParsingException,AiContentFilterException,AiUnsupportedCapabilityException,AiStructuredOutputException,AiToolNotFoundException,AiToolException
Quality
- 146 unit tests covering all modules
- Zero
dart analyzeissues - Comprehensive DartDoc on all public APIs
- MIT License