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 Bedrock Platform Laravel Package

symfony/ai-bedrock-platform

AWS Bedrock platform bridge for Symfony AI, letting you invoke foundation models and list available ones through Bedrock, with support for Anthropic Claude, Meta Llama, and Amazon Nova request formats.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony AI bridge, not a Laravel package, so day one is about wiring it into Laravel's container rather than reaching for a facade. Budget half a day for setup, most of which is AWS-side.

Install and confirm the moving parts

composer require symfony/ai-bedrock-platform

You get the Symfony AI platform contracts as a transitive dependency (the PlatformInterface, message/model value objects, and result converters). Pin the version — this is a 0.x package (latest tagged v0.14.0) and minor bumps have carried behaviour changes.

Look here first, in this order

  1. vendor/symfony/ai-bedrock-platform/ — the bridge is small. Read the provider abstraction added in v0.8.0 and the per-family adapters (Anthropic/Claude, Meta/Llama, Amazon/Nova). The adapters are where request-schema differences live; that's the code you'll actually be reading when a payload looks wrong.
  2. The bundled model catalog and the model-list console command (v0.7.0, "sync catalog with Bedrock API"). Run it before writing any model ID into config:
php artisan list | grep -i model   # Symfony console commands surface through Artisan
  1. The ListFoundationModels call path — this is your source of truth for what your account can actually reach.

The first use case: one Claude call, end to end

Resolve the platform out of the container in tinker and invoke a model with a plain prompt. Do this before building anything abstract. If it fails, the failure is almost always one of three things: credentials not on the default AWS chain, the model not enabled for your account/region (Bedrock requires explicitly requesting model access in the console), or a model ID that needs an inference-profile prefix (us.anthropic.…) rather than the bare foundation-model ID. That third one is the most common surprise and has been patched twice upstream (#1729, #2016).

Minimal Laravel wiring

// config/ai.php
return [
    'bedrock' => [
        'region'      => env('AWS_DEFAULT_REGION', 'us-east-1'),
        'default'     => env('BEDROCK_MODEL', 'anthropic.claude-3-5-sonnet'),
        'cheap'       => env('BEDROCK_CHEAP_MODEL', 'amazon.nova-lite'),
    ],
];

Let the AWS SDK resolve credentials from the default chain (env vars locally, IAM role on EC2/ECS/Lambda). Don't put long-lived keys in .env for anything beyond local dev.

Implementation Patterns

Bind the platform, not the client. The stable seam is the Symfony AI platform contract; bind that in a service provider so the rest of your app never names a Bedrock class. This is what lets you swap to the OpenAI-compatible Mantle path added in v0.14.0 without touching call sites — and it's the single highest-leverage decision here.

$this->app->singleton(PlatformInterface::class, fn ($app) => new BedrockPlatform(
    region: config('ai.bedrock.region'),
));

Then a thin app-level service (App\Ai\Assistant) that takes the platform and exposes domain methods: summariseTicket(), classifyLead(). Controllers and jobs depend on that, never on the platform. When the bridge renames a class in a 0.x bump, you edit one file.

Route by task, not by model. Use the provider abstraction for a two-tier setup: a strong model for reasoning/extraction, a cheap one (Nova Lite, Llama) for classification and short summaries. Put the routing table in config so it's tunable without a deploy, and log which tier served each call. Cost control here is far more effective than post-hoc monitoring.

Structured output is the killer feature for Laravel work. Claude-specific structured output (v0.6.0) means you can ask for a JSON schema and hand the result straight to a Form Request / DTO / Model::create(). Pattern: define the schema once as a class constant, validate the decoded array with Laravel's validator anyway (models drift, and unsupported JSON Schema features get demoted to description — see gotchas), then persist. Never trust the shape blindly.

Queue anything user-facing. Bedrock latency plus cold starts will blow past a web request budget. Put invocations in jobs with $timeout set explicitly (queue worker timeout must exceed it), $tries = 3, and a backoff() of [5, 30, 120] for throttling. This also gives you retries for free when AWS returns 429s.

Stream where the UX demands it. For chat-style features, stream tokens through an SSE response or Livewire; for everything else, don't — streaming complicates cost accounting and error handling for no benefit.

Agentic loops. Tool calling is supported, and v0.10.0 added the ability to override tool_choice from caller options — that's what you reach for when you need to force a specific tool rather than let the model choose. Multimodal tool results (v0.11.0) let a tool return an image back into the conversation, which is useful for screenshot/PDF-inspection tools.

Cache the catalog. ListFoundationModels is metadata, not data — cache it for an hour and expose it as an Artisan command for ops. Cheap, and it prevents a class of "model not found" confusion.

Testing. Bind a fake PlatformInterface in tests that returns canned results. Do not hit Bedrock in the default test suite; keep a separate, opt-in integration test against the cheapest available model, guarded by an env flag.

Gotchas and Tips

0.x means pin, don't float. "symfony/ai-bedrock-platform": "0.14.*" in composer.json. Treat minor upgrades as scheduled work with a changelog read, not something composer update does on a Friday. Several recent releases are bug fixes you want — but you want them deliberately.

Model IDs are the sharpest edge. Two separate upstream bugs (#2016 Claude ID mapping, #1729 inference-profile region matching) mean: don't hand-construct IDs. Take them from the catalog command output, and be aware that cross-region inference profiles use a region-prefixed ID that differs from the foundation-model ID. If you get ValidationException: model identifier is invalid, this is why — not your credentials.

Model access is per-account, per-region. Enabling a model in us-east-1 does nothing for eu-west-1. Do this before you build; it's a console step with a (usually fast) approval, and it's the most common "the package is broken" false alarm.

Payloads must be structured. Since v0.6.0 a string payload to the model client throws InvalidArgumentException. If you're porting code from a raw-HTTP Bedrock implementation, you were probably json_encode-ing yourself — stop.

PHP 8.2 installs. The json_validate() polyfill declaration was fixed in v0.14.0 (#2480). On Laravel 10/11 with PHP 8.2, don't go below that.

Extended thinking will crash the result converter pre-v0.11.0. ClaudeResultConverter choked on thinking content blocks (#2286). If you plan to use thinking-enabled models, v0.11.0+ is a hard floor.

Structured output schemas get mutated. Unsupported JSON Schema features are relocated into description (#2174) rather than rejected. Your schema is advisory. Always validate the parsed result server-side.

Throttling and quotas are per-model, per-region. A queue with backoff handles most of it, but a burst of parallel jobs will hit the ceiling fast. If you're doing batch work, serialize per model tier.

Timeouts bite twice. PHP's max_execution_time (web) and the queue worker's --timeout are separate from the HTTP client timeout inside the bridge. Set all three; a large Claude completion can take 30–60s.

Finish reasons are normalized now (v0.11.0) — good. Before that, stop_reason handling was model-family-specific. If you have any branching on truncation/length, verify against the normalised values rather than raw per-family strings.

Cost and PII are your problem, not the package's. Log token usage per call in a dedicated channel and alert on a daily threshold; Bedrock's per-token pricing is invisible until the invoice. And don't log prompt/response bodies by default — add a redaction step and treat the bridge as a boundary where user data leaves your app.

Pick one path. Native provider abstraction or Mantle's OpenAI-compatible surface. Supporting both doubles your test surface for a 0.x package with two stars and zero dependents — treat Mantle as a migration escape hatch you've documented, not a second production path.

The bus factor is real. Two stars, zero dependents, maintained inside the main symfony/ai monorepo. Upstream fixes land, but you are an early adopter: expect to read the source, and consider pinning to a commit if you hit a blocker rather than waiting on a release.

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.
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo