Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Client Laravel Package

openai-php/client

OpenAI PHP is a community-maintained PHP client for the OpenAI API, giving Laravel and PHP applications typed, framework-agnostic access to chat, responses, embeddings, images, audio, files, and streaming, backed by an active community and thousands of GitHub stars.

View on GitHub
Deep Wiki
Context7

Getting Started

Updated for openai-php/client v0.21.0. This release adds Responses API support for programmatic tool calling and the apply_patch tool, improves streamed response processing, allows nullable file-search options, exposes cache_write_tokens, and supports web search image results/settings. No breaking changes are listed in the release notes, but agent/tool and streaming code paths should be re-tested.

Install the package:

composer require openai-php/client

If your app does not already have a PSR-18 HTTP client, add Guzzle:

composer require guzzlehttp/guzzle

Configure the client in config/openai.php:

return [
    'api_key' => env('OPENAI_API_KEY'),
    'base_uri' => env('OPENAI_BASE_URI', 'https://api.openai.com/v1'),
    'default_model' => env('OPENAI_MODEL', 'gpt-4o-mini'),
    'timeout' => (int) env('OPENAI_TIMEOUT', 30),
];

First call using the Responses API, which is the modern default for chat-style work:

use OpenAI\Client;

$client = OpenAI::client(config('openai.api_key'));

$response = $client->responses()->create([
    'model' => config('openai.default_model'),
    'input' => 'Summarize the following support ticket in two sentences: ...',
]);

return $response->outputText;

Where to look first:

  • responses() for most day-to-day text generation, chat, tools, and multimodal flows.
  • models() for model availability checks.
  • files() and related resources for upload-backed workflows.
  • For v0.21.0, inspect the Responses tool payloads, streamed response handling, file-search tool options, usage details, and web-search output handling.

Common first use case: wrap responses()->create() in a Laravel service and use it for support summaries, drafting, classification, or retrieval-augmented answers.

Implementation Patterns

Bind a configured client once so services do not read env() at runtime:

use OpenAI\Client;

public function register(): void
{
    $this->app->singleton(Client::class, function () {
        return OpenAI::factory()
            ->withApiKey(config('openai.api_key'))
            ->withBaseUri(config('openai.base_uri'))
            ->withHttpClient(new \GuzzleHttp\Client([
                'timeout' => config('openai.timeout'),
            ]))
            ->make();
    });
}

Service-layer wrapper:

class OpenAIService
{
    public function __construct(private Client $client) {}

    public function answer(string $input): string
    {
        $response = $this->client->responses()->create([
            'model' => config('openai.default_model'),
            'input' => $input,
            'temperature' => 0.7,
        ]);

        return $response->outputText;
    }
}

Function tools and follow-ups: define normal function tools in the tools array, execute the returned function call in your app, then send the tool result back to the model. Keep a maximum tool-call/agent-turn budget to avoid runaway loops.

$response = $this->client->responses()->create([
    'model' => config('openai.default_model'),
    'input' => 'What is the weather in Barcelona?',
    'tools' => [[
        'type' => 'function',
        'name' => 'fetch_weather',
        'description' => 'Fetch current weather for a city.',
        'parameters' => [
            'type' => 'object',
            'properties' => [
                'city' => ['type' => 'string'],
            ],
            'required' => ['city'],
        ],
    ]],
]);

foreach ($response->output as $item) {
    if (($item->type ?? null) === 'function_call') {
        $args = json_decode($item->arguments, true);
        $weather = $this->fetchWeather($args['city']);

        // Send function_call_output back in a follow-up Responses request.
    }
}

Programmatic tool calling (v0.21.0): use this when you want the model to orchestrate tool use within the Responses flow rather than driving every step manually in PHP. Treat it as an agent workflow: validate every tool input, authorize tool execution against the current user, cap turns, and log each tool call. Start with a small allow-list of tools instead of exposing all application actions.

Apply-patch tool (v0.21.0): useful for code-editing/agent workflows, but do not apply model-generated patches directly to production files. Run patches in a sandbox or temporary branch, validate the diff, run tests, and require review before merging.

File search with optional nulls (v0.21.0): ranking_options and max_num_results may now be null in the FileSearchTool. If your config builder uses optional values, avoid forcing empty arrays or placeholder values:

'tools' => [[
    'type' => 'file_search',
    'vector_store_ids' => [$vectorStoreId],
    'max_num_results' => $maxResults ?: null,
    'ranking_options' => $rankingOptions ?: null,
]],

Web search image results/settings (v0.21.0): web search responses may now contain image content and additional settings. If you render results in Blade/Inertia/Livewire, handle non-text content blocks instead of assuming every output item is plain text.

Streaming: createStreamed() is still the right choice for chat UIs. v0.21.0 includes streamed-response processing optimizations, but UI code should still treat chunk boundaries as arbitrary:

$stream = $client->responses()->createStreamed([
    'model' => config('openai.default_model'),
    'input' => 'Explain Laravel middleware briefly.',
]);

$buffer = '';

foreach ($stream as $chunk) {
    $buffer .= $chunk->delta->content[0]->text ?? '';

    if (preg_match('/[.!?]\s*$/', $buffer)) {
        echo $buffer;
        flush();
        $buffer = '';
    }
}

Usage and cost logging: account for the new cache_write_tokens field in prompt token details. It affects cost estimates when prompt caching is used:

$usage = $response->usage;

Log::info('OpenAI usage', [
    'input_tokens' => $usage->inputTokens ?? null,
    'output_tokens' => $usage->outputTokens ?? null,
    'cache_write_tokens' => $usage->inputTokensDetails->cacheWriteTokens ?? null,
]);

Multi-turn conversations: use previous_response_id to continue from a prior response, or persist your own message/tool-call history. Store the response ID alongside the Laravel conversation/session record.

Error handling: centralize OpenAI/transport failures in Laravel’s exception handler or a dedicated service. Return safe API errors to clients, log request context, and do not leak prompts or API keys.

Gotchas and Tips

  • No breaking changes in v0.21.0, but re-test tool loops and streaming. The new tool features and streamed-response optimization can change timing and response shape in agent code.
  • Do not trust apply_patch output directly. Treat patches as untrusted code changes. Apply only after validation, tests, and review.
  • Cap programmatic tool calling. Add max-turn, max-token, and per-user rate limits. Log tool name, arguments, result summary, and latency.
  • Validate function/tool arguments. JSON-decode defensively and validate against a schema before calling internal services.
  • Use config() inside services. env() should live in config files; run php artisan config:cache in deployment and clear config after changing values.
  • Handle image content from web search. v0.21.0 adds image results/settings, so output renderers should support text plus image blocks.
  • Do not force file-search defaults. ranking_options and max_num_results can be null now; only send values your application actually needs.
  • Log cache_write_tokens. Existing token/cost dashboards may undercount prompt-cache writes until updated.
  • Streaming chunks are not sentence boundaries. Buffer text for UI coherence; do not assume one chunk equals one token, word, or sentence.
  • Set explicit timeouts. Streaming and tool-heavy requests can exceed default HTTP timeouts. Configure Guzzle timeouts and retry policies deliberately.
  • Respect rate limits. Catch package/transport exceptions, honor retry-after headers where available, and queue non-interactive jobs.
  • Keep API keys server-side. Never expose the key to frontend JavaScript. Use Laravel policies/auth checks before allowing users to trigger expensive model calls.
  • Pin and monitor models. Model availability and pricing change; keep model names in config and avoid hardcoding them across the codebase.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums