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
| Factory | Returns |
|---|
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
| Factory | Returns |
|---|
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');
});
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: