Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/phpaisdk/google/llms.txt

Use this file to discover all available pages before exploring further.

Instead of waiting for a complete response, you can stream text tokens from Gemini as they are generated. The aisdk/google package uses Server-Sent Events (SSE) under the hood — it appends ?alt=sse to the interactions URL so that Gemini emits a stream of JSON delta events. The SDK parses each event and yields typed StreamPart objects that your application can consume one at a time. Tokens arrive as TextDeltaPart events, making it straightforward to echo output to users progressively.

Basic Streaming Example

Call ->stream() instead of ->run(). You get back a stream handle. Iterate $stream->chunks() to receive each text delta as a plain string, then call $stream->run() once the loop is done to get the final TextModelResponse with complete usage data.
use AiSdk\Generate;
use AiSdk\Google;

Google::create(['apiKey' => env('GOOGLE_GENERATIVE_AI_API_KEY')]);

$stream = Generate::text('Tell me a short story about a PHP developer.')
    ->model(Google::model('gemini-3.5-flash'))
    ->stream();

foreach ($stream->chunks() as $chunk) {
    echo $chunk;
    ob_flush();
    flush();
}

$result = $stream->run();

echo "\n\n--- Done ---\n";
echo "Input tokens:  {$result->usage->inputTokens}\n";
echo "Output tokens: {$result->usage->outputTokens}\n";
->chunks() is a convenience wrapper that filters the raw part stream and yields only the text content of each TextDeltaPart. For full control over every event type, iterate the raw parts directly (see below).

Stream Parts

Every event yielded by the underlying Generator is a StreamPart instance. The following part types are emitted by the Google provider:

TextDeltaPart

A fragment of the model’s text output. These arrive in order and can be concatenated to reconstruct the full response.
use AiSdk\Streaming\TextDeltaPart;

// $part->text — the incremental text fragment

ReasoningDeltaPart

A fragment of the model’s internal reasoning or “thinking” output. Only emitted by thinking-capable models (e.g. gemini-3.5-flash with reasoning enabled). These deltas arrive interleaved with or before the main text deltas.
use AiSdk\Streaming\ReasoningDeltaPart;

// $part->text — the incremental reasoning fragment

ToolCallStartPart / ToolCallDeltaPart

Emitted when the model decides to call a tool. ToolCallStartPart signals a new call and carries the tool’s index, ID, and name. ToolCallDeltaPart follows immediately with the JSON-encoded arguments.
use AiSdk\Streaming\ToolCallStartPart;
use AiSdk\Streaming\ToolCallDeltaPart;

// ToolCallStartPart: $part->index, $part->id, $part->name
// ToolCallDeltaPart: $part->index, $part->arguments (JSON string), $part->id, $part->name

ProviderMetadataPart

Carries raw Gemini metadata — id, model, finish_reason, and usage_metadata — extracted from the final SSE event. The provider key is always 'google'.
use AiSdk\Streaming\ProviderMetadataPart;

// $part->provider  — 'google'
// $part->metadata  — associative array of raw Gemini fields

FinishPart

Always the last part yielded. Contains the normalised FinishReason enum value and a Usage object with final token counts accumulated across all SSE events.
use AiSdk\Streaming\FinishPart;

// $part->finishReason — FinishReason enum
// $part->usage       — Usage object (inputTokens, outputTokens, totalTokens, …)

Iterating Raw Parts

When you need to handle tool calls, reasoning deltas, or metadata in addition to text, iterate the stream as a Generator and switch on the part type:
use AiSdk\Generate;
use AiSdk\Google;
use AiSdk\Streaming\FinishPart;
use AiSdk\Streaming\ProviderMetadataPart;
use AiSdk\Streaming\ReasoningDeltaPart;
use AiSdk\Streaming\TextDeltaPart;
use AiSdk\Streaming\ToolCallDeltaPart;
use AiSdk\Streaming\ToolCallStartPart;

Google::create(['apiKey' => env('GOOGLE_GENERATIVE_AI_API_KEY')]);

$stream = Generate::text('What is 17 × 34? Think step by step.')
    ->model(Google::model('gemini-3.5-flash'))
    ->stream();

foreach ($stream as $part) {
    if ($part instanceof TextDeltaPart) {
        echo $part->text;
    }

    if ($part instanceof ReasoningDeltaPart) {
        // Optionally surface thinking tokens in a UI sidebar
        // echo '[thinking] ' . $part->text;
    }

    if ($part instanceof ToolCallStartPart) {
        echo "\n[Tool call: {$part->name} (id={$part->id})]\n";
    }

    if ($part instanceof ToolCallDeltaPart) {
        echo "  args: {$part->arguments}\n";
    }

    if ($part instanceof ProviderMetadataPart) {
        // $part->metadata['model'], $part->metadata['finish_reason'], …
    }

    if ($part instanceof FinishPart) {
        echo "\n\nFinish reason: {$part->finishReason->value}\n";
        echo "Tokens used:   {$part->usage->totalTokens}\n";
    }
}

Final Result After Streaming

After the loop, call $stream->run() to retrieve a TextModelResponse that aggregates everything collected during streaming. It exposes the same properties as a non-streaming response:
$result = $stream->run();

echo $result->text;                          // Full concatenated text
echo $result->usage->inputTokens;            // Prompt token count
echo $result->usage->outputTokens;           // Generated token count
echo $result->finishReason->value;           // Normalised finish reason
echo $result->providerMetadata['google']['model']; // Model name from Gemini
When a function_call delta is detected during streaming, the SDK immediately sets the FinishReason to ToolCalls — even before the FinishPart is emitted — so downstream consumers can detect tool-call responses as early as possible. The FinishPart at the end of the stream will also carry FinishReason::ToolCalls.

Build docs developers (and LLMs) love