The Wire · Showcase
LARAVEL AI FIXES STREAMED TOOL-CALL USAGE LEAKS, CLOUD CLI PLUGS CREDENTIAL BLEED
By RepoJournal · Filed · About Laravel
Multi-step AI inference was silently dropping usage data from all but the final step, while the Cloud CLI was printing passwords in JSON output and breaking database restore commands entirely.
The Laravel AI package had a critical bug in streamed tool-calling: when a turn involved multiple inference steps with tool calls, only the deepest final step's usage was captured in the `StreamEnd` event [1]. Intermediate steps' usage was discarded because `HandlesTextStreaming` returned early without emitting events when delegating to `handleStreamingToolCalls()`. This fix lands across all provider gateways (Gemini, Anthropic, DeepSeek, Groq, Mistral, Ollama) [2]. A separate fix tackles partially-orphaned tool calls in conversation replay, where interrupted runs or max-step limits could leave tool results incomplete; the store now pairs calls to results one-to-one instead of by ID matching [3] [4].
Cloud CLI shipped four critical fixes. `database-cluster:update` was ignoring every option due to prefix mismatch between form keys and CLI argument names, rendering updates impossible [6]. `database-restore:create` was fataling on every invocation because a typed `Form::$errors` property had no default value [7]. Most alarmingly, credentials were leaking in JSON output: `cache:list --json` printed cache passwords in full, and other DTOs carrying secrets bypassed masking entirely [8]. The CLI also rebranded "hibernation" to "scale to zero" across all user-facing output, with backward-compatible aliases keeping scripts running [9]. Meanwhile, the built binary was locked to the hardcoded `https://cloud.laravel.com` base URL; `CLOUD_BASE_URL` environment variable is now respected [10].
On the framework side, Queue gains a `forward()` method to route jobs from one queue to another, solving the multi-site problem where queues have different names across environments [11]. Laravel now supports Guzzle 8, which brings persistent connections for PHP 8.5+ with ext-curl, exposed via `Http::globalPersistentTransport()` [12]. Process timeouts got clarity: idle timeouts and general timeouts now throw distinct exceptions so you can tell a hung process from one that just needed more time [13]. Gemini's default model bumped to `gemini-3.7-flash` [5].
MCP v1.0.0-beta.1 is a breaking change that aligns the protocol to MCP 2026-07-28, drops the initialize handshake, adds `server/discover`, and requires protocol metadata on every request [14]. The upgrade guide is live [15]. OAuth client registration shifts from Dynamic Client Registration to Client ID Metadata Documents, where your `client_id` points to an HTTPS URL describing your client instead of registering on every redirect [16] [17].
One email a day. Unsubscribe in one click.
Keep up with Laravel in about 3 minutes a day: what actually shipped — the commits, pull requests, releases, and security advisories that matter.
One email a day. Unsubscribe in one click. Read a past issue →
Action items
- → Upgrade Laravel Cloud CLI immediately - credential masking now blocks passwords in JSON output laravel/cloud-cli [immediate]
- → Patch Laravel AI to fix streamed tool-call usage reporting across all provider gateways laravel/ai [immediate]
- → Plan upgrade to Guzzle 8 support in framework to enable persistent connections on PHP 8.5+ laravel/framework [plan]
- → Review MCP 1.0.0-beta.1 breaking changes and upgrade guide if you use OAuth client registration laravel/mcp [plan]
References
- [1] [BUG] [0.x] Sum streamed usage across tool-call steps in all provider gateways ↗ laravel/ai
- [2] [BUG] [0.x] Sum streamed usage across tool-call steps in all provider gateways (#698) laravel/ai
- [3] Filter partially-orphaned tool calls when replaying conversation history ↗ laravel/ai
- [4] Filter partially-orphaned tool calls when replaying conversation history (#758) laravel/ai
- [5] Update Gemini default text model to gemini-3.7-flash ↗ laravel/ai
- [6] Fix database-cluster:update ignoring every option ↗ laravel/cloud-cli
- [7] Fix database-restore:create fataling on every invocation ↗ laravel/cloud-cli
- [8] Mask credentials in JSON output, not just environment variables ↗ laravel/cloud-cli
- [9] Rename hibernation to scale to zero across user-facing output ↗ laravel/cloud-cli
- [10] Respect CLOUD_BASE_URL in built binaries ↗ laravel/cloud-cli
- [11] [13.x] Introduce `Queue::forward()` ↗ laravel/framework
- [12] [13.x] Support Guzzle 8 ↗ laravel/framework
- [13] [13.x] Add a dedicated exception for idle process timeouts ↗ laravel/framework
- [14] v1.0.0-beta.1 ↗ laravel/mcp
- [15] Add 1.0 upgrade guide ↗ laravel/mcp
- [16] Prefer Client ID Metadata Documents over dynamic registration ↗ laravel/mcp
- [17] Prefer Client ID Metadata Documents over dynamic registration (#323) laravel/mcp