Skip to main content

Documentation Index

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

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

aisdk/core ships two test doubles — FakeTextModel and FakeImageModel — that implement the same interfaces as real provider models. They return predetermined responses, enabling fast and fully deterministic tests. The test suite itself uses Pest and can be run with composer test.
Call Generate::reset() in an afterEach() hook to clear the stored Sdk instance and default model between tests. Skipping this causes state to leak from one test into the next, producing hard-to-debug failures.
// At the top of every test file that touches Generate.
afterEach(fn() => Generate::reset());

FakeTextModel

FakeTextModel implements TextModelInterface. It is constructed with a TextModelResponse, an optional array of StreamPart objects for streaming tests, and an optional array of extra Capability cases.
use AiSdk\Tests\Fakes\FakeTextModel;
use AiSdk\Responses\TextModelResponse;
use AiSdk\Streaming\StreamPart;
use AiSdk\Capability;

new FakeTextModel(
    response:          TextModelResponse $response,
    streamParts:       array $streamParts = [],       // StreamPart[]
    extraCapabilities: array $extraCapabilities = [], // Capability[]
);
Default capabilities enabled on every FakeTextModel:
  • Capability::TextGeneration
  • Capability::Streaming
  • Capability::ToolCalling
  • Capability::StructuredOutput
  • Capability::TextInput
Extra capabilities (e.g. Capability::ImageInput) are appended to this list via $extraCapabilities.

Static factories

FactoryReturns
FakeTextModel::text(string $text)A fake pre-loaded with a single text response
FakeTextModel::textWithCapabilities(string $text, array $capabilities)Same, but with a custom capabilities list
textWithCapabilities() appends the capabilities you provide to the default list via extraCapabilities. Use it when you need to test that the SDK accepts a request only after the required capability (e.g. Capability::ImageInput) is present.

FakeImageModel

FakeImageModel implements ImageModelInterface. It exposes a public $lastRequest property so you can assert on the exact ImageRequest that was passed to it.
use AiSdk\Tests\Fakes\FakeImageModel;
use AiSdk\Responses\ImageResponse;
use AiSdk\Capability;

new FakeImageModel(
    response:     ImageResponse $response,
    capabilities: array $capabilities = [Capability::ImageGeneration],
);

Static factories

FactoryReturns
FakeImageModel::image(?string $base64 = 'aW1hZ2U=')A fake returning one PNG image
FakeImageModel::withoutImageGeneration()A fake with no capabilities (triggers CapabilityNotSupportedException)

Test patterns

Simple text assertion

use AiSdk\Generate;
use AiSdk\Tests\Fakes\FakeTextModel;

afterEach(fn() => Generate::reset());

it('generates a greeting', function () {
    $result = Generate::text('Say hello.')
        ->model(FakeTextModel::text('Hello!'))
        ->run();

    expect($result->text)->toBe('Hello!');
});

Testing the default model

it('uses the configured default model', function () {
    Generate::model(FakeTextModel::text('default reply'));

    $result = Generate::text('Hello')->run();

    expect($result->text)->toBe('default reply');
});

Testing streaming

Pass StreamPart objects as the second constructor argument. The stream() method yields them in order.
use AiSdk\FinishReason;
use AiSdk\Generate;
use AiSdk\Responses\TextModelResponse;
use AiSdk\Responses\Parts\TextPart;
use AiSdk\Streaming\TextDeltaPart;
use AiSdk\Streaming\FinishPart;
use AiSdk\Support\Usage;
use AiSdk\Tests\Fakes\FakeTextModel;

afterEach(fn() => Generate::reset());

it('streams text chunks in order', function () {
    $response = new TextModelResponse(
        parts: [new TextPart('Hello world')],
        finishReason: FinishReason::Stop,
        usage: new Usage(5, 3),
    );

    $fake = new FakeTextModel(
        response: $response,
        streamParts: [
            new TextDeltaPart('Hello'),
            new TextDeltaPart(' world'),
            new FinishPart(FinishReason::Stop, new Usage(5, 3)),
        ],
    );

    $chunks = [];

    $stream = Generate::text('Tell me a story.')
        ->model($fake)
        ->stream();

    $stream->onChunk(function (string $chunk) use (&$chunks) {
        $chunks[] = $chunk;
    });

    $result = $stream->run();

    expect($chunks)->toBe(['Hello', ' world'])
        ->and($result->text)->toBe('Hello world');
});

Testing tool-calling responses

use AiSdk\FinishReason;
use AiSdk\Generate;
use AiSdk\Responses\Parts\ToolCallPart;
use AiSdk\Responses\TextModelResponse;
use AiSdk\Support\Usage;
use AiSdk\Tests\Fakes\FakeTextModel;

afterEach(fn() => Generate::reset());

it('handles a tool call response', function () {
    $response = new TextModelResponse(
        parts: [
            new ToolCallPart(id: 'call_1', name: 'weather', arguments: ['city' => 'Lahore']),
        ],
        finishReason: FinishReason::ToolCalls,
        usage: new Usage(10, 5),
    );

    $fake = new FakeTextModel(response: $response);

    $result = Generate::text('What is the weather in Lahore?')
        ->model($fake)
        ->run();

    expect($result->toolCalls)->toHaveCount(1)
        ->and($result->toolCalls[0]->name)->toBe('weather')
        ->and($result->toolCalls[0]->arguments)->toBe(['city' => 'Lahore']);
});

Testing capability exceptions

Use FakeTextModel::textWithCapabilities() to create a model that appends extra capabilities to the default set, then assert that the SDK accepts or rejects requests based on whether the required capability (e.g. Capability::ImageInput) is present.
use AiSdk\Capability;
use AiSdk\Content;
use AiSdk\Exceptions\CapabilityNotSupportedException;
use AiSdk\Generate;
use AiSdk\Message;
use AiSdk\Tests\Fakes\FakeTextModel;

afterEach(fn() => Generate::reset());

it('throws when the model does not support image input', function () {
    Generate::text()
        ->messages([
            Message::user([
                Content::text('Describe this image.'),
                Content::image('raw-image', mimeType: 'image/png'),
            ]),
        ])
        ->model(FakeTextModel::text('nope')) // no ImageInput capability
        ->run();
})->throws(CapabilityNotSupportedException::class);

it('succeeds when the model supports image input', function () {
    $result = Generate::text()
        ->messages([
            Message::user([
                Content::text('Describe this image.'),
                Content::image('raw-image', mimeType: 'image/png'),
            ]),
        ])
        ->model(FakeTextModel::textWithCapabilities('ok', [Capability::ImageInput]))
        ->run();

    expect($result->text)->toBe('ok');
});

Testing image generation

use AiSdk\Exceptions\CapabilityNotSupportedException;
use AiSdk\Generate;
use AiSdk\Tests\Fakes\FakeImageModel;

afterEach(fn() => Generate::reset());

it('generates an image and returns base64 data', function () {
    $model = FakeImageModel::image(); // default base64: 'aW1hZ2U='

    $result = Generate::image('A red cube')
        ->model($model)
        ->count(2)
        ->size('1024x1024')
        ->run();

    expect($result->output->base64)->toBe('aW1hZ2U=')
        ->and($model->lastRequest?->prompt)->toBe('A red cube')
        ->and($model->lastRequest?->count)->toBe(2)
        ->and($model->lastRequest?->size)->toBe('1024x1024');
});

it('throws when the model has no image generation capability', function () {
    Generate::image('A red cube')
        ->model(FakeImageModel::withoutImageGeneration())
        ->run();
})->throws(CapabilityNotSupportedException::class);

Running the test suite

The SDK uses Pest. Run the full test suite with:
composer test

Build docs developers (and LLMs) love