Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/phpaisdk/openai-compatible/llms.txt

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

ChatRequestBuilder and ImageRequestBuilder are designed around the portable aisdk/core contract. They handle the fields that are meaningful across every OpenAI-compatible provider: model, messages, temperature, tools, reasoning effort, image size, and so on. But OpenAI-compatible providers are not identical — one may accept a seed parameter for reproducibility, another may need a background field for image transparency, and a third may use a non-standard resolution key that has no portable equivalent. Rather than forking the shared builder for each provider, both builders expose a single, well-defined escape hatch: the raw key inside a provider-namespaced options array.

How providerOptions Works

TextModelRequest and ImageRequest both accept a providerOptions array keyed by provider name. At build time, the builder calls $request->providerOptionsFor($providerName) to retrieve only the options scoped to the current provider, ignoring every other provider’s namespace entirely.
// Pass raw options when constructing the request.
$request = new TextModelRequest(
    messages: [Message::user('Hello')],
    providerOptions: [
        'openai' => [
            'raw' => ['seed' => 42],
        ],
        'groq' => [
            'raw' => ['some_groq_field' => 'value'],
        ],
    ],
);

// When building for 'openai', only the 'openai' namespace is read.
// The 'groq' namespace is ignored entirely.
$body = ChatRequestBuilder::build('gpt-4o', 'openai', $request, stream: false);

The raw Key

Within the provider namespace, the raw key is reserved for arbitrary body overrides. If providerOptions[$providerName]['raw'] is an array, it is merged into the request body using array_replace() as the very last operation — after every portably-built field has already been set.
// From src/ChatRequestBuilder.php

// Single escape hatch: provider-namespaced raw overrides merged last.
$raw = $request->providerOptionsFor($providerName)['raw'] ?? null;
if (is_array($raw)) {
    $body = array_replace($body, $raw);
}
The same pattern is used in ImageRequestBuilder::build():
// From src/ImageRequestBuilder.php

$raw = $request->providerOptionsFor($providerName)['raw'] ?? null;
if (is_array($raw)) {
    $body = array_replace($body, $raw);
}
Because array_replace() gives precedence to the second argument, any key in raw that matches a portably-set key will overwrite it.

Chat Example: temperature and seed

The test suite demonstrates injecting temperature and seed into a chat request body via raw:
use AiSdk\Message;
use AiSdk\Requests\TextModelRequest;
use AiSdk\OpenAICompatible\ChatRequestBuilder;

$request = new TextModelRequest(
    messages: [Message::user('Hi')],
    providerOptions: [
        'openai' => [
            'raw' => ['temperature' => 0.1, 'seed' => 42],
        ],
    ],
);

$body = ChatRequestBuilder::build('gpt-4o', 'openai', $request, stream: false);

// $body['temperature'] === 0.1
// $body['seed']        === 42
temperature is also a portable field that ChatRequestBuilder sets earlier in the build process. Because raw is merged last, the value 0.1 from raw overwrites whatever the portable $request->temperature was.

Image Example: transparent background

Provider-specific image parameters that have no portable equivalent are a natural fit for raw:
use AiSdk\Requests\ImageRequest;
use AiSdk\OpenAICompatible\ImageRequestBuilder;

$body = ImageRequestBuilder::build(
    'image-model',
    'openai-compatible',
    new ImageRequest(
        prompt: 'A clean product photo',
        count: 2,
        size: '1024x1024',
        providerOptions: [
            'openai-compatible' => [
                'raw' => ['background' => 'transparent'],
            ],
        ],
    ),
);

// $body['background'] === 'transparent'
// All portable fields (model, prompt, n, size, response_format) are still present.

Provider-Specific Builder Options with raw: the xAI Example

ImageRequestBuilder::build() also accepts a fourth $options argument that lets provider packages configure the builder’s behavior (e.g., which parameter name to use for aspect ratio, whether to infer a size from the aspect ratio). The raw escape hatch works on top of whatever the builder produces from those options:
use AiSdk\Requests\ImageRequest;
use AiSdk\OpenAICompatible\ImageRequestBuilder;

$body = ImageRequestBuilder::build(
    'grok-imagine-image-quality',
    'xai',
    new ImageRequest(
        prompt: 'A city skyline',
        count: 1,
        aspectRatio: '16:9',
        providerOptions: [
            'xai' => [
                'raw' => ['resolution' => '2k'],
            ],
        ],
    ),
    [
        'aspectRatioParameter'    => 'aspect_ratio',   // use aspect_ratio instead of size
        'inferSizeFromAspectRatio' => false,            // do not convert 16:9 to 1536x1024
        'sizeParameter'           => null,             // omit size field entirely
    ],
);

// $body['aspect_ratio'] === '16:9'
// $body['resolution']   === '2k'   (injected via raw)
// $body does NOT contain 'size'
This pattern lets a provider package customize the builder’s portable behavior through $options while still using raw for any fields that the builder itself will never handle.
raw overrides are merged last using array_replace(), which means any key in your raw array will silently overwrite the corresponding portably-set field. For example, setting raw => ['model' => 'other-model'] will override the $modelId argument passed to the builder. Use raw only for fields that are genuinely not covered by the portable API.
Use raw when:
  • The field is specific to one provider and has no meaningful equivalent across other providers.
  • You need a quick workaround for a provider-specific quirk without changing shared package code.
  • You are building a provider package and need to expose an advanced option to end users before it is part of the portable contract.
Propose a new parameter to the portable contract when:
  • Multiple OpenAI-compatible providers support the same semantic concept under the same or similar field names.
  • The capability is something every caller of the PHP AI SDK would benefit from expressing portably (e.g., a new topK parameter, or structured output schema support).
  • You want the value to be validated, documented, and tested at the SDK level rather than hidden in a raw map.
The raw escape hatch is intentionally narrow — one key, merged last — to keep the boundary between portable and provider-specific behavior explicit and auditable.

Build docs developers (and LLMs) love