Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ai Mistral Platform Laravel Package

symfony/ai-mistral-platform

Symfony AI bridge for the Mistral platform, providing chat completions and OCR integration through Mistral's API. Enables Symfony applications to use Mistral models for AI-powered text and document processing.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture Fit

  • Symfony AI Ecosystem Alignment: The package remains a Symfony AI bridge integrating cleanly with Laravel via Symfony's HTTP client (PSR-18 compliant; Laravel's own HTTP client is Guzzle-backed). Laravel's service container can host Symfony's ClientInterface and Provider abstractions without major refactoring.
  • Multi-Provider Strategy — Weakened in v0.15.0: The Provider abstraction still enables dynamic routing between Mistral and other providers, but #2622 renames the shared canonical max_output_tokens option to each bridge's own wire field. That is an architectural regression in the abstraction's symmetry: a single provider-agnostic options object no longer covers output-length control across bridges. A translation layer (our code, not the package's) is now required to keep multi-provider configs uniform.
  • Event-Driven Extensibility: Symfony's AiEventDispatcher can be bridged to Laravel's Illuminate\Events\Dispatcher for centralized logging, monitoring, and analytics. Unchanged in this release.
  • Streaming Support: The DeltaInterface for semantic streaming is compatible with Laravel's queue system, though queue middleware may be required for real-time chunk processing. Unchanged.
  • Cost-Aware Telemetry (v0.14.0, still valid): TokenUsage carries a model property, enabling per-model, per-request cost accounting inside the application layer. For Laravel this maps onto a cost-calculation service bound to the container and onto existing logging/metrics channels.
  • Automated Model Catalogs (refreshed again in v0.15.0 via #2666): Catalogs continue to be generated by github-actions, so the package tracks Mistral's model lineup upstream. This remains the machine-maintained source of truth for "which models exist and what they cost."
  • New in v0.15.0 — Wire-Field Fidelity: Renaming the canonical option to per-bridge wire fields improves fidelity (no lossy translation inside the bridge) at the cost of portability (no shared options contract across bridges). For a single-provider Laravel deployment this is neutral-to-positive; for a multi-provider fallback design it shifts work into our integration layer.

Integration Feasibility

  • Low-Coupling Design: PSR-18 and Symfony abstractions mean existing Laravel components — facades, service providers, HTTP clients — can wrap Symfony interfaces with minimal overhead.
  • Direct API Support: Out-of-the-box chat completions and embeddings support eliminates custom API wrappers. EmbeddingClient and ChatClient inject directly into Laravel services.
  • Error Handling: Uniform error exposure simplifies debugging across providers; Laravel's App\Exceptions\Handler can extend Symfony's error traits.
  • Configuration Flexibility — With a New Translation Concern: Symfony configuration still maps to Laravel config files, but the output-token option is now bridge-specific:
    // config/ai.php
    'providers' => [
        'mistral' => [
            'client' => \Symfony\Ai\Mistral\MistralClient::class,
            'api_key' => env('MISTRAL_API_KEY'),
            'endpoint' => env('MISTRAL_ENDPOINT', 'https://api.mistral.ai'),
            // v0.15.0: use Mistral's wire field, not the old canonical key
            'max_tokens' => env('AI_MAX_OUTPUT_TOKENS', 1024),
        ],
    ],
    
    If we intend to keep a provider-agnostic application config, add a small mapper so call sites never reference a wire field directly:
    // app/Services/OutputLimitTranslator.php
    public function toWireOptions(string $provider, int $maxOutputTokens): array
    {
        return match ($provider) {
            'mistral' => ['max_tokens' => $maxOutputTokens],
            default   => ['max_output_tokens' => $maxOutputTokens],
        };
    }
    
  • Cost Attribution Wiring (unchanged): Because TokenUsage exposes the serving model, a cost layer remains a thin, testable service rather than a cross-cutting concern. The ai-pricing.php map, the AiCostCalculator, and the AiEventFired listener pattern from the prior assessment still apply verbatim — this release does not touch TokenUsage.
  • Model Catalog as Config: The v0.15.0 catalog refresh (#2666) is a direct, mechanical update to our ModelRegistry; it requires no code change, only cache invalidation of the boot-time catalog singleton.

Technical Risk

  • Pre-1.0 Maturity, Now Compounding: At v0.15.0, the package is still pre-1.0 with a small community footprint. Our upgrade path now spans v0.8.0 → v0.15.0, seven minors, whose individual changelogs remain uncaptured — only the final hop (0.14 → 0.15) is summarized here.
  • New — Breaking Option Rename (#2622): max_output_tokens → per-bridge wire field is a public-surface change. Any config array, DTO, or call site passing the canonical key will not necessarily error; depending on validation strictness it may be silently ignored, falling back to a provider default. That produces truncated outputs or unexpected token spend with no exception — the worst failure class for a silent-degradation path.
  • New — Cross-Bridge Config Divergence: Because the option is now named per bridge, a shared config file driving both Mistral and a fallback provider must branch by provider. This raises the cost and the bug surface of the multi-provider fallback we planned in the prior assessment.
  • Version Constraint Bump (#2753): symfony/ai-* constraints move to 0.15. This makes the upgrade all-or-nothing across the AI package family — a partial bump will fail dependency resolution, and any other Symfony AI bridge we adopt must move in lockstep.
  • No Native Laravel Integration: Absence of a Laravel service provider or facade still requires custom bootstrapping in AppServiceProvider.
  • Queue/Job Integration: Streaming responses (DeltaInterface) may require custom queue handlers or event listeners.
  • Caching: Laravel's cache backends are still not natively integrated; embeddings/completions caching and cost accumulation must be wired manually.
  • Pricing Drift (carried forward): Catalog updates tell you which models exist; they do not publish prices. A stale ai-pricing.php produces silently wrong cost attribution.
  • Catalog Churn (carried forward): Two of three commits in this release are catalog/version maintenance, confirming that release cadence is partly driven by Mistral's lineup rather than by defect fixes.
  • API Dependency: Mistral API changes can still necessitate bridge updates; config caching may need to be cleared on upgrades — now especially relevant since a renamed key can survive in config:cache and mask the migration.
  • Testing Coverage: Still limited fixtures. Our PestPHP suite must now additionally assert that output-limit options are actually applied per bridge, not merely accepted.

Key Questions

  1. Upgrade Path (v0.8.0 → v0.15.0): What breaking changes landed across minors 0.9–0.14, and now 0.15? Who reviews the intermediate changelogs, and is there a harness exercising our chat, embeddings, and streaming call paths before we bump?
  2. max_output_tokens Blast Radius: Where is the canonical key currently set — config files, env vars, DTOs, tests, fixtures, documentation? Does the bridge throw on an unknown option or ignore it? The answer determines whether this is a 30-minute or a 3-day migration.
  3. Per-Bridge Translation Ownership: If we keep multi-provider fallback, who owns the provider→wire-field mapper, and is it tested against each bridge's actual option names?
  4. Cost Ownership: Who owns the model→price mapping in ai-pricing.php, and what is the review cadence against Mistral's published pricing? Is there a monthly reconciliation against the Mistral invoice?
  5. Cost Granularity: Per tenant, per feature, per user, or per model? TokenUsage.model supports all four; the decision determines cache key design and reporting schema.
  6. Provider Strategy: Is Mistral primary or fallback, and does the new per-bridge option naming change that economics enough to reconsider consolidation onto one provider?
  7. Streaming Handling: Real-time UI (Echo/Pusher), queued jobs, or SSE? Still the least-covered path by the package's fixtures.
  8. Observability: How does AiEventDispatcher integrate with Monolog, Sentry/Datadog, and Telescope? Do token/cost telemetry and the new option-rename errors land in the same pipeline?
  9. Catalog Consumption: Do we consume the automated catalog programmatically (validating model names pre-dispatch) or treat it as documentation? The prior assessment's recommendation stands; this release adds another catalog delta to consume.
  10. Version Pinning: Given the constraint bump to 0.15 couples all Symfony AI packages, do we pin exactly and schedule reviews, or float and accept unreviewed model/option changes?
  11. Silent-Default Detection: Can we detect in production when a request omitted an output limit because of a renamed key? A default-value log line or metric would convert this failure class from silent to observable.
  12. Long-Term Maintenance: Who owns updates when Symfony AI, Mistral's API, or the model catalog changes?

Integration Approach

Stack Fit

  • Symfony HTTP Client: Laravel's HTTP client is PSR-18 compliant, so Symfony's HttpClientInterface injects directly:
    // app/Providers/AppServiceProvider.php
    public function register()
    {
        $this->app->bind(\Symfony\Contracts\HttpClient\HttpClientInterface::class, function () {
            return \Symfony\Contracts\HttpClient\HttpClient::create([
                'base_uri' => env('MISTRAL_ENDPOINT'),
                'auth_bearer' => env('MISTRAL_API_KEY'),
            ]);
        });
    }
    
  • Service Container Integration: Unchanged — bind MistralClient to the Symfony HTTP client; bind ProviderInterface to the Mistral implementation with room for fallbacks.
  • Option Translation Layer (new): Wrap client construction so wire-field naming is resolved once, not at every call site:
    $this->app->bind(\Symfony\Ai\Mistral\MistralClient::class, function ($app) {
        return new \Symfony\Ai\Mistral\MistralClient(
            $app->make(\Symfony\Contracts\HttpClient\HttpClientInterface::class),
            // v0.15.0 wire field
            maxTokens: (int) config('ai.providers.mistral.max_tokens'),
        );
    });
    
  • Event System: Bridge AiEventDispatcher to Laravel events and attach the cost calculator as a listener (unchanged from v0.14.0):
    // app/Listeners/RecordAiSpend.php
    public function handle(AiEventFired $event): void
    {
        if ($usage = $event->getTokenUsage()) {
            $this->costs->calculate($usage, tenant()->id, feature: $event->getContext()['feature'] ?? 'unknown');
        }
    }
    
  • Model Catalog as Registry: Same singleton pattern; v0.15.0 requires only a cache flush after the dependency bump:
    $this->app->singleton(ModelRegistry::class, fn () =>
        ModelRegistry::fromCatalog(cache()->rememberForever('ai.models', fn () =>
            json_decode(file_get_contents(base_path('vendor/.../models.json')), true)
        ))
    );
    
  • Queue Integration: Unchanged — chunk handlers append to a buffer with idempotent keys and TTLs.

Migration Path

  1. Grep-first, upgrade-second: locate every occurrence of max_output_tokens across config, env, DTOs, tests, and docs. Treat this inventory as the migration checklist before touching composer.json.
  2. Pilot on an exact pin at 0.15.0 (not a range) in a single non-critical service; validate chat, embeddings, streaming, and output-token behavior (assert the requested limit is honored, not defaulted).
  3. Reconcile the full version gap: diff CHANGELOG.md from v0.8.0 through v0.15.0. Prior releases covered only the last hop; that debt has now grown by one more minor.
  4. Introduce the translation layer before the fallback provider: if multi-provider is on the roadmap, land the provider→wire-field mapper now, while only one provider exists, so the second provider is a config addition rather than a refactor.
  5. Invalidate aggressively on deploy: php artisan config:clear and a cache-key bump for the model registry. A stale config:cache can preserve the old key and mask both the rename and the catalog refresh.
  6. Keep the cost layer additive: TokenUsage.model is unchanged in this release; the shadow-mode rollout from the prior assessment proceeds as planned.
  7. Lock the upgrade process: exact pins across the Symfony AI package family, per-release review, and re-running the streaming, cost-accuracy, and option-application suites before each bump.

Compatibility

  • PHP/Laravel: No version constraints introduced by this release for our stack; confirm against the supported matrix at install time.
  • Symfony AI Family: The 0.15 constraint bump (#2753) couples all Symfony AI packages — partial upgrades will not resolve. Coordinate as a single dependency unit.
  • Breaking Option Surface: max_output_tokens is replaced by per-bridge wire fields. This is the only behavior-affecting change in the release and the primary compatibility risk.
  • Backward Compatibility: TokenUsage and catalog shapes are untouched; the cost layer and registry see no disruption. Code performing strict option-array equality assertions in tests will need updating.
  • Config Caching: Renamed keys plus config:cache is the highest-risk combination in this release — stale cached config can silently suppress the new key.
  • Model Identifier Drift: The #2666 catalog refresh may introduce or rename models; hard-coded model strings must be validated against the registry at boot.

Sequencing

  1. Inventory max_output_tokens usage and confirm the bridge's behavior on unknown options (throw vs. ignore).
  2. Upgrade to a pinned 0.15.0 across the whole Symfony AI family; clear and rebuild config and registry caches.
  3. Validate call paths (chat/embeddings/streaming) and assert output-limit application.
  4. Register the Symfony client and provider bindings, including the wire-field translation layer.
  5. Bridge AiEventDispatcher to Laravel events and add observability listeners.
  6. Wire the model registry and pre-dispatch model validation against the refreshed catalog.
  7. Add the cost calculator in shadow mode; reconcile against one billing cycle.
  8. Promote cost attribution to authoritative; wire dashboards and tenant-level budgets.
  9. Only then implement multi-provider fallback, using the translation layer and re-verifying cost attribution across providers.
  10. Add Laravel ergonomics (facade, publishable config) once the above stabilize.

Operational Impact

Maintenance

  • Release Cadence Is Confirmed Catalog-Driven: Two of three commits in v0.15.0 are maintenance (version bump, catalog refresh). Expect a steady drip of low-risk releases punctuated by occasional option-surface changes like #2622 — cheap individually, but they demand a named owner and a scheduled review slot.
  • Pre-1.0 Discipline Required: Stay on exact pins with a committed lockfile; review each changelog rather than floating on ^0.15.
  • Two Maintenance Surfaces, Now Three: The package, the pricing configuration, and (new) the provider→wire-field translation layer all require upkeep. The pricing map and translation layer are ours; both fail silently if neglected.
  • Coupling Increases: The 0.15 constraint bump means Symfony AI packages must move together — treat them as one dependency with one upgrade ticket.
  • Ownership: Designate a TPM/DRI for the bridge, catalog consumption, pricing map, and option translation. Define an escalation path for Mistral API changes.

Support

  • Debugging Improves (for cost), Worsens (for truncation): TokenUsage.model continues to make cost tickets traceable to model and provider. But a silently ignored output-limit key presents as "the model gives short answers," which is a product bug report, not an AI one. Add "was an output limit applied?" to the triage script.
  • Support Runbook: Document (a) how to reproduce a failing request against a specific model, (b) how to verify a reported cost against the configured rate, (c) the escalation path when a model disappears from the catalog, and (d) how to confirm the effective output-token limit for a given provider.
  • Cost Disputes: Unchanged — answerable via model-level attribution, provided the pricing map is current.
  • Community Support: Still early-stage with minimal dependents; upstream responsiveness is best-effort. Assume internal capability.

Scaling

  • Horizontal Scaling: The bridge remains stateless; scale with the Laravel app. Streaming stays the constraint — pin streaming workers to queues with dedicated concurrency limits.
  • Cost Telemetry Write Volume: Unchanged — batch per-request Cache::increment into aggregates or push to a time-series store at high volume.
  • Catalog Lookup: Resolve the registry once per process via a cached singleton; the v0.15.0 refresh is a one-time cache invalidation, not a runtime concern.
  • Multi-Provider Headroom — Costed Higher: Provider abstraction still allows capacity spreading during Mistral rate-limit events, but the per-bridge option naming means each additional provider adds both a pricing entry and a translation branch.
  • Token Budgets: Still the cheapest guardrail against runaway agentic loops — enforce per-tenant and per-feature ceilings pre-dispatch. Note that these guardrails now depend on the renamed key actually taking effect.

Failure Modes

Failure Blast Radius Mitigation
Mistral API outage / rate limit Requests fail or stall Multi-provider fallback via Provider abstraction; retry with jittered backoff
Renamed max_output_tokens silently ignored Truncated outputs or inflated spend, no exception Grep inventory pre-upgrade; assertion test that the limit is honored; log effective options per request
Stale config:cache after upgrade Old key persists, masking the rename config:clear in deploy pipeline; cache-key version bump
Partial Symfony AI package upgrade Dependency resolution failure at deploy Bump the whole family in one commit; CI install check
Stale pricing config Silent financial misreporting Monthly invoice reconciliation; alert on "unknown model" lookups
Unknown model in TokenUsage Null/zero cost attributed Pre-dispatch validation against refreshed catalog; log-and-alert on unmapped models
Catalog update renames a model Dispatch failures on hard-coded identifiers Registry-based validation at boot; fail fast in CI
Streaming chunk loss Truncated responses, orphaned buffers Idempotent buffer keys, TTLs, dead-letter queues
Upgrade regression across seven minors Unexpected breakage in production Exact pinning, staged rollout, contract tests on chat/embeddings/streaming
API key exposure Credential compromise Env/Vault storage, no keys in config cache, rotation runbook
Cost runaway from agentic loops Budget overrun Per-tenant token budgets enforced pre-dispatch

Ramp-Up

  • Engineer Effort: ~1–2 days for a Laravel developer to reach a working chat/embeddings integration; ~1 day for the event bridge and observability; ~1–2 days for the cost-attribution and model-registry layer; ~0.5 day for the max_output_tokens migration plus a per-bridge translation helper if multi-provider is in scope.
  • Learning Curve: Two abstractions to internalize — Symfony's AI provider/TokenUsage model and Laravel's container/event binding. New since v0.14.0: the option surface is no longer uniform across bridges, so "which key does this provider expect?" becomes a recurring question the internal docs must answer.
  • Team Enablement:
    • A one-page internal guide covering binding, event bridging, streaming job patterns, the cost calculator, and the wire-field option table per provider.
    • A pricing-map contribution guide.
    • A "review a release" checklist — this release demonstrates why: one line in a changelog can silently change output behavior.
  • Onboarding Risk: Low individual complexity, but thin documentation plus a now-divergent option surface make the internal guide load-bearing. Budget for it explicitly.

Assessment delta from v0.14.0 → v0.15.0: Not additive — one breaking change. #2622 renames the canonical max_output_tokens option to per-bridge wire fields, which (a) requires an inventory-and-migrate pass on our config surface, (b) can fail silently if an old key is retained, and (c) weakens the provider-portability claim that underpinned the multi-provider fallback plan by introducing a per-bridge translation requirement. #2753 couples all Symfony AI packages to 0.15, making upgrades all-or-nothing. #2666 is a routine catalog refresh requiring only cache invalidation. The v0.14.0 cost-attribution thesis is unchanged and still valid — TokenUsage was not touched. Net: the strategic case for the package holds, but the upgrade is no longer a drop-in, and the unverified v0.8.0 → v0.14.0 path now extends to v0.15.0 and must be diffed before adoption.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk