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 Type Safe Platform Laravel Package

symfony/ai-type-safe-platform

Symfony AI Type-Safe Platform adds type safety to AI-powered Symfony apps by mapping model responses to typed PHP objects. It integrates with Symfony AI and the Serializer to validate structured outputs, reducing brittle array handling and making LLM integrations more predictable.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install: composer require symfony/ai-type-safe-platform. This is a Symfony component (no Laravel service provider, no auto-discovery), so you wire it yourself. Check the composer.json for the PHP and symfony/type-info constraints — 0.x releases move fast and requirements bump often.

  • Look here first:

    • Symfony\AI\Platform\PlatformInterface / PlatformFactory — the entry point you invoke models through.
    • The TypeSafe bridge namespace introduced in v0.14.0 (#2549) — this is the piece that turns a PHP class into a JSON schema and hydrates the model's answer back into that class. Read the bridge's README and its tests before anything else; the tests are the most accurate documentation at 0.x.
    • The Result/response object's conversion methods (asObject(), asJson(), asText()) — pick one per call site and stick to it.
  • First use case (10 minutes): a typed extraction DTO.

    final class SupportTicket
    {
        public function __construct(
            public string $summary,
            public TicketPriority $priority,   // backed enum
            /** @var list<string> */
            public array $tags,
            public ?string $customerEmail = null,
        ) {}
    }
    

    Then bind the platform once in a service provider and invoke it with that class as the response format. The bridge derives the schema from the constructor signature — no hand-written JSON schema.

  • Laravel wiring (do this before your first call): register the platform as a singleton in AppServiceProvider reading from config/services.php / .env. Do not build a new platform per request; the underlying HTTP client and model catalogue are worth reusing within a request and across a queue worker's lifetime.

Implementation Patterns

  • DTO-first, not prompt-first. Design the class you want back, then write the prompt around it. Promoted constructor properties, backed enums, ?nullable types and /** @var list<Foo> */ docblocks all map cleanly. Anything you can express in symfony/type-info you get for free — that is the whole point of the TypeSafe bridge.
  • Keep DTOs flat-ish. Nesting works, but every level multiplies schema tokens and increases the chance a smaller model drifts. Two levels is usually the sweet spot; flatten deeper structures into an id/parent reference if the model starts omitting fields.
  • Service-layer wrapper, not controller calls. Put the invoke + hydrate + validate cycle behind an application service (e.g. TicketClassifier), inject the platform, and let controllers/jobs depend on your service. When the schema or model changes you edit one class, and you can swap in a fake in tests.
  • Always validate after hydration. The bridge guarantees shape, not semantics. Run the resulting DTO through Laravel's Validator or a small domain check (enum already covers most of it) and treat a failure as a retry-with-repair case rather than an exception thrown at the user.
  • Retries and repair loop: on a hydration/validation failure, re-invoke once with the validation error appended to the conversation. Cap at 1–2 attempts; more than that usually means the schema is wrong, not the model.
  • Queue it. Structured-output calls are slow (seconds) and occasionally flaky. Dispatch a job, keep the HTTP request path synchronous only for trivial lookups. Set $timeout and $tries explicitly on the job — Laravel's defaults are shorter than a large structured completion.
  • Scoring/classification responses (v0.14.0 change, #2566): score answers now require a probabilities field. If you were reading score/label only and tolerating a missing probabilities key, model your score DTO with a non-nullable probabilities array (map of label ⇒ float, or list of {label, probability}) and normalise/validate that the values sum to ~1.0 before acting on them. Do not silently ?? [] it — an absent field now signals a bad response you should retry.
  • Provider portability: the same DTO should work against OpenAI/Anthropic/Ollama bridges. Keep provider-specific knobs (temperature, strict-mode flags, response_format variants) in config keyed by provider, not in the DTO.
  • Testing: don't hit the network in feature tests. Either (a) bind a fake PlatformInterface that returns a canned JSON string for the hydrated DTO, or (b) snapshot the generated schema in a unit test so an accidental property rename that breaks your production prompt fails CI. A schema snapshot test is cheap and catches the most common regression in this package's usage.

Gotchas and Tips

  • 0.x versioning — pin exactly. "symfony/ai-type-safe-platform": "0.14.*" in composer.json. Minor releases here have shipped behaviour changes (v0.14.0 makes probabilities mandatory in score answers, and adds a whole bridge). A ^0.14 constraint will happily hand you v0.15 with a changed DTO contract.
  • The v0.14.0 TypeSafe bridge is additive but new. Treat it as young API: namespaces and the class-to-schema mapping may shift in 0.15. Wrap your usage in one adapter class so a rename is a one-file fix.
  • Schema is prompt tokens. A rich DTO costs money and context on every call. Keep DTOs lean, avoid long @var docblock descriptions, and cache repeated identical calls (Cache::remember on a hash of prompt + model + schema version) where the domain allows it.
  • Unsupported keywords fail differently per provider. Union types, mixed, recursive types, and associative arrays without a documented value type may produce an invalid schema that one provider rejects with a 400 and another silently ignores. Test your DTO against every provider you actually deploy to.
  • array without a docblock item type is a trap — you get [] back and hydration surprises. Always annotate with /** @var list<string> */ or a typed collection.
  • No Laravel auto-discovery. If you don't see your platform resolved from the container, it's because nothing registered it — check your service provider and that the config key is present in config/services.php. php artisan about won't help; tinker and app(PlatformInterface::class) will.
  • Debugging hydration: log the raw response string ($result->asText() or the provider payload) before conversion. Once hydration throws, the raw JSON is gone. A Log::debug in your wrapper service at the raw-response boundary has saved more debugging sessions than any other line in this integration.
  • Long-lived queue workers + singleton platform. If you build the platform with a config value, a config:cache or worker restart is required after changing env — the usual Laravel singleton-in-worker caveat, but it bites harder here because the failure is a silent wrong-model call.
  • Extension points worth knowing: a custom bridge under the platform's bridge namespace if you need an unsupported provider, and type-info's own handlers if you need to map a domain value object (money, UUID) to a scalar — that's cheaper than flattening your DTO.
  • Treat probabilities as a distribution, not truth. Now that they're required, it's tempting to threshold on them. Calibrate against a labelled sample before letting a > 0.8 rule trigger anything irreversible.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route