What Changed in Laravel AI SDK v0.10.3
Before v0.10.3, the Laravel AI SDK returned a typed response object with shared properties like $response->text, $response->usage, and $response->meta. Anything outside that common shape — rate limit headers, provider-specific request IDs, or extra JSON fields — was simply unreachable without writing your own HTTP middleware.
Version 0.10.3, released on August 6, 2026, closes that gap. A new public raw property on every response holds the Illuminate\Http\Client\Response from the underlying HTTP call:
$response = (new SupportAgent)->prompt('Summarize this document.');
$response->raw->header('x-ratelimit-remaining-requests');
$response->raw->json('id');
Because it is a standard Laravel HTTP client response, header(), json(), and status() all work exactly as they do after an Http::get() call.
Per-Step Raw Responses
An agent that calls tools makes multiple round-trips. $response->raw reflects the final request — the one that produced the text you received. Every intermediate step also keeps its own raw:
foreach ($response->steps as $step) {
$step->raw?->header('x-ratelimit-remaining-tokens');
}
This matters for rate limit accounting: a five-step run consumed budget across five requests, and reading only the last header gives you an incomplete picture.
Monitoring Rate Limits With an Event Listener
Instead of checking headers at every call site, you can centralise the logic in an event listener. The AgentPrompted event carries the full response:
use Laravel\Ai\Events\AgentPrompted;
Event::listen(AgentPrompted::class, function (AgentPrompted $event) {
$remaining = $event->response->raw?->header('x-ratelimit-remaining-requests');
if ($remaining !== null && (int) $remaining < 10) {
Log::warning('Provider request budget running low.', [
'provider' => $event->response->meta->provider,
'remaining' => $remaining,
]);
}
});
One listener covers every agent run in your application.
Correlating Failures With the Provider
When a run produces unexpected output and you need to open a support ticket, providers ask for their own request ID. You can now log it without capturing the full prompt payload:
Log::info('Agent run completed.', [
'invocation' => $response->invocationId,
'provider_request_id' => $response->raw?->header('request-id'),
]);
Header names vary by provider, so check the documentation for whichever one you are using.
When raw Is Null
The property is nullable — always use the null-safe operator ?->. Four situations return null:
- Streamed responses (
$agent->stream()andAgentStreamed) — the response is assembled from stream events, not a single response body. - AWS Bedrock — the AWS SDK handles the HTTP call, so no
Illuminate\Http\Client\Responseis produced. - Serialized responses — Guzzle streams cannot be serialized, so
rawis dropped when a response passes through a queue or cache. Read the header before dispatching a job and pass the value explicitly. - Faked agents — unless the fake is built with
withRawResponse().
Testing Rate Limit Logic
Fake responses support withRawResponse() so you can simulate low-budget scenarios in tests:
use GuzzleHttp\Psr7\Response as Psr7Response;
use Illuminate\Http\Client\Response;
use Laravel\Ai\Responses\TextResponse;
SupportAgent::fake([
(new TextResponse('Hello', new Usage, new Meta))->withRawResponse(new Response(
new Psr7Response(200, ['x-ratelimit-remaining-requests' => '99'], '{}')
)),
]);
$response = (new SupportAgent)->prompt('Hi');
$response->raw->header('x-ratelimit-remaining-requests'); // '99'
Key Takeaways
$response->rawis anIlluminate\Http\Client\Responseavailable on every non-streamed, non-Bedrock response from v0.10.3 onward.- Each step in a multi-step agent run has its own
raw, giving you per-request rate limit data. - The
AgentPromptedevent exposesrawfor centralised monitoring without scattering header checks across your codebase. rawis null for streamed responses, Bedrock, serialized responses, and unfaked test agents.- Use
withRawResponse()(notwithRaw()) to supply headers in fakes.
Source: Laravel AI: Get Raw HTTP Responses and Rate Limits — Laravel News