tetrixdev/laravel-ai-bridge
laravel-ai-bridge is a lightweight Laravel package for connecting your application to AI services through a simple, unified bridge. It helps you organize AI provider configuration and keep prompt/response integrations clean and maintainable.
Architecture fit
ai-bridge service: HTTP client + service provider + configuration, exposing conversation routes and a connection-status endpoint. effort is implemented as a thin pass-through (ai_request.options.effort), which is the right shape — no new persistence, no new domain model, no schema change.effort_levels on the connection status endpoint rather than hardcoding a vocabulary. That is a sound pattern and gives us a forward-compatible seam for future thinking levels.POST /ai-bridge/connections/{id}/mcp, POST/DELETE .../upstreams/{server}/sign-in). This is the correct placement — the package owns the browser-facing surface, so it should own the token check — but it means the package is now a security control in our stack, not just an HTTP convenience wrapper.allowSameSite() and CSRF except list and applies even to cookie-authenticated requests with no started session; only token-authenticated calls (bearer, Sanctum PAT) bypass. That is a defensible strict-by-default posture, but it establishes a second, independent CSRF policy alongside the host app's. Any team with an existing exemption on these paths now needs to know about it.tool_call_id being required on the mcp route ties a relayed call to a card that was actually shown — a data-integrity constraint on the relay, not a transport detail. The PHP API keeps it optional for trusted server code, which correctly preserves server-to-server ergonomics while tightening the browser path.Integration feasibility
ai-bridge >= 0.32.0 for effort to have any effect. This remains a hard cross-service dependency and a coordinated release, not an independent package bump.effort is scoped to Claude conversations only; BYOK and managed mode never transmit it. Any product surface exposing an effort control must branch on provider/mode or it will present a control that silently does nothing.effort matches ^[a-z]{1,16}. Feasible, but the regex encodes an assumption (single lowercase token, no separators, no numerics). Verify current and planned level names fit before we build UI around it.tool_call_id_required. Any non-PHP consumer (front-end relay, JS proxy, webhook bridge) must be updated in lockstep. PHP callers of the client API are unaffected.ai-bridge.csrf.upstreams / AI_BRIDGE_CSRF_UPSTREAMS (defaults on for the 0.19 upstream routes) and ai-bridge.csrf.routes / AI_BRIDGE_CSRF_ROUTES (default off, applies the same check to the package's other state-changing browser routes, and becomes the default in the next major). The bundled <x-ai-bridge::chat /> sends the token itself; custom front-ends do not.laravel/framework — confirm this is a real Composer constraint and not documentation-only.Technical risk
model now wins over the conversation's stored model. Previously the stored model was authoritative. Any existing caller that passes a model field incidentally — or that relied on the conversation's pinned model for cost/quality guarantees — will silently change routing and spend. This is not a deprecation; it is an immediate precedence flip with no opt-in described. Not addressed in v0.21.0.tool_call_id required on the mcp HTTP route. A hard 422 for any relay that previously omitted it. Small blast radius if only the bundled component calls it; large if we proxy through our own front-end or workflow builder.csrf_token_mismatch on cookie/session-authenticated calls to the 0.19 routes. Custom clients — including single-page apps using cookie auth, and any cookie-authenticated-but-sessionless auth scheme — will fail until they send X-CSRF-TOKEN, _token, or X-XSRF-TOKEN. The guard explicitly overrides allowSameSite() and the app's CSRF except list, so existing exemptions do not protect these calls.ai-bridge.csrf.routes flips to default-on. Teams that do nothing today inherit a breaking change later; enabling it now converts a surprise into a controlled rollout.AI_BRIDGE_CSRF_UPSTREAMS=false is only safe when the app itself protects these routes. If we disable it for a quick fix and forget, we reintroduce the cross-subdomain token-less attack the release exists to close.effort to a pre-0.32 bridge does not error; it is ignored. Absent client-side feature detection, users will believe thinking level is applied when it is not. Still open.effort_levels is ambiguous. It means "bridge too old," not "no levels available." Consumers must not treat empty as a valid empty capability set. Still open.Key questions
model precedence change covered by an ADR, and is there an upgrade note or opt-in flag for consumers who depended on stored-model authority? (unchanged, still unanswered)effort_levels vocabulary today, and is the ^[a-z]{1,16}$ constraint guaranteed stable across bridge releases? (unchanged)ai-bridge (and now on laravel/framework), or are both requirements documentation-only?effort is suppressed)? (unchanged)effort is supplied but unsupported by the connected bridge version? (unchanged)allowSameSite() and the CSRF except list, and is there a timeline/issue for the next-major default for csrf.routes?tool_call_id validated against a stored card record (referential check) or only presence-checked? The release note implies the former; the implementation detail determines whether we need our own FK-style validation at the relay.AI_BRIDGE_CSRF_UPSTREAMS=false disable both the upstream routes and the csrf.routes check, or only the former?Stack fit
VerifyCsrfToken, Sanctum SPA cookie flow, axios defaults) should satisfy it in most cases.laravel/framework to the same matrix if the constraint is real.Migration path
ai-bridge to >= 0.32.0 in all environments first, including staging and any preview/ephemeral environments. Confirm the connection status endpoint now returns a non-empty effort_levels. (unchanged)model fields. Enumerate which conversations currently rely on stored-model authority. This remains the gating item for the release, not the effort feature. (unchanged)/ai-bridge/connections/{id}/mcp and /upstreams/{server}/sign-in. Confirm each sends X-CSRF-TOKEN, _token, or X-XSRF-TOKEN. Confirm no caller depends on allowSameSite() or the app CSRF except list to reach those paths. Upgrade the bundled <x-ai-bridge::chat /> alongside the package so the token is sent automatically.tool_call_id to every non-PHP mcp invocation. Treat this as a client release that must ship with (or before) the package upgrade.AI_BRIDGE_CSRF_UPSTREAMS to on; only set false with a written justification referencing a specific app-level control, and add a config test asserting it stays unset.ai-bridge.csrf.routes / AI_BRIDGE_CSRF_ROUTES in staging immediately and in production once step 4 is clean, so the next major is a no-op rather than a surprise.effort and missing tool_call_id, plus 419 csrf_token_mismatch.Compatibility
ai-bridge < 0.32: in that window effort_levels is empty and effort is a silent no-op. Gate the UI on non-empty effort_levels, never on package version alone. (unchanged)tool_call_id optional); breaking for HTTP/browser callers on both the tool_call_id requirement and the CSRF check. Communicate it as breaking to integration teams even though the package may tag it minor.allowSameSite() for these paths is now stricter post-upgrade. That is the point, but it must be announced as a behaviour change, not shipped silently.csrf.routes default flips in the next major. Add it to our forward-compat tracker and, ideally, to our own changelog.Sequencing
Bridge upgrade → package upgrade → model-precedence audit and remediation → CSRF client audit and token rollout → tool_call_id relay fix → enable csrf.routes early → effort feature detection in client → effort UI/API exposure → docs and support enablement → post-release verification of effective model logging and CSRF rejection rate. Do not invert the bridge/package steps ahead of the model-precedence audit; shipping the package before that audit risks unplanned model routing and cost. The CSRF steps (4–6) are independent of the bridge and can run in parallel, but they must complete before the package reaches production with any cookie-authenticated browser client in scope.
Maintenance
ai-bridge versions aligned. Any bridge release that changes effort_levels semantics or extends the level vocabulary is now a coordinated upgrade. (unchanged)csrf.upstreams or csrf.routes. The default flip in the next major is a scheduled item on our upgrade calendar.csrf.upstreams, csrf.routes, and the two env vars). Recommend a single documented default posture — both on — and an explicit exception process for anything else.Support
csrf_token_mismatch from custom front-ends, particularly SPA and cookie-auth-without-session setups, and from anyone whose app had these routes in a CSRF except list. Pre-announce before rollout; do not let it surface as a mystery failure.tool_call_id_required: 422s on relay paths that were fine yesterday. Fix is client-side; the diagnostic should name the field.effort will surface as user-facing failures if the client does not validate against the same ^[a-z]{1,16}$ rule pre-flight. Mirror the validation client-side and in any admin tooling. (unchanged)effort_levels emptiness (unchanged); (b) "419 on an AI route" → check token presence, then confirm AI_BRIDGE_CSRF_UPSTREAMS is not overridden, then check for a conflicting app-level exemption assumption; (c) "422 tool_call_id_required" → relay client version skew.Scaling
effort is a single scalar option on an existing request. The CSRF check is an in-process token comparison — no extra round trip. No additional network calls beyond the connection-status read, which should be cached with a short TTL.Failure modes
model overrides stored model; wrong model routed, cost/quality drift, no error raised. (unchanged, still open)effort sent to bridge < 0.32 is discarded; users misled about thinking depth. (unchanged)effort_levels interpreted as "unsupported capability" rather than "old bridge," producing either a hidden feature or a broken one depending on interpretation. (unchanged)allowSameSite() or a CSRF except entry for these paths discover at runtime that the package's guard does not honour it. Especially likely where these routes were added post-exemption.AI_BRIDGE_CSRF_UPSTREAMS=false set during an incident and never reverted, silently reopening the cross-subdomain vector the release closes.tool_call_id after the package upgrade, producing 422s only on the browser path while server-side tests stay green.csrf.routes default flip lands unmanaged because we deferred awareness of it.laravel/framework)Ramp-up
tool_call_id changes are breaking at the HTTP boundary even if the package semver says minor. Budget a written upgrade note, not just a release-note link.tool_call_id at our relay in the same window. Enable csrf.routes proactively to absorb the next-major default. Treat effort as the lower-risk, opt-in feature it appears to be.How can I help you explore Laravel packages today?