PHPackages                             halilcosdu/laravel-chatbot - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. halilcosdu/laravel-chatbot

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

halilcosdu/laravel-chatbot
==========================

A Laravel-native OpenAI chatbot powered by the Responses and Conversations APIs.

v2.1.0(4w ago)656.2k↓25.8%6[5 PRs](https://github.com/halilcosdu/laravel-chatbot/pulls)MITPHPPHP ^8.2CI failing

Since Apr 17Pushed 4mo ago2 watchersCompare

[ Source](https://github.com/halilcosdu/laravel-chatbot)[ Packagist](https://packagist.org/packages/halilcosdu/laravel-chatbot)[ Docs](https://github.com/halilcosdu/laravel-chatbot)[ Fund](https://www.buymeacoffee.com/halilcosdu5)[ RSS](/packages/halilcosdu-laravel-chatbot/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (10)Dependencies (41)Versions (22)Used By (0)

Laravel Chatbot
===============

[](#laravel-chatbot)

[![Latest Version on Packagist](https://camo.githubusercontent.com/fbef2aeba5a2fab19698a2a46eb1bb46073e9c42ab053df6ad96992dcb05f273/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68616c696c636f7364752f6c61726176656c2d63686174626f742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/halilcosdu/laravel-chatbot)[![Total Downloads](https://camo.githubusercontent.com/f1b728778236367d6ece301e5aa77e79a2476559fb3810b61574b101b7a15f0c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68616c696c636f7364752f6c61726176656c2d63686174626f742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/halilcosdu/laravel-chatbot)[![License](https://camo.githubusercontent.com/96ee3edda18cdaf257a019ca9bbefde7960d14998c8d9f3e3d72ae87c02800e0/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f68616c696c636f7364752f6c61726176656c2d63686174626f742e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)

A Laravel-native, stateful chatbot built on OpenAI's **Responses** and **Conversations** APIs. It manages the remote conversation, keeps a local Eloquent transcript, scopes threads to your users, and supports both synchronous and streamed responses through one facade.

Version 2.x does not use the deprecated Assistants API. If you are upgrading from 1.x, read the [upgrade guide](UPGRADE.md) and migrate before the Assistants API shuts down on August 26, 2026.

What you get
------------

[](#what-you-get)

- Responses + Conversations API integration through `openai-php/laravel`.
- Local `Thread` and `ThreadMessage` models with configurable model classes.
- Create, continue, search, paginate, inspect, and delete conversations.
- Single-use text streams for both new and existing threads.
- Automatic transcript persistence after a response completes successfully.
- Per-request Responses API options without allowing callers to replace managed input or conversation state.
- Optional owner scoping for multi-user applications.
- Raw Conversation and Response methods when you need the underlying SDK objects.
- An idempotent command for migrating 1.x Assistants threads from their local transcript.

Compatibility
-------------

[](#compatibility)

LaravelSupported PHP versionsTestbench11.x (`11.29+`, legacy)8.2, 8.3, 8.49.x12.x (`12.12+`)8.2, 8.3, 8.4, **8.5**10.x13.x8.3, 8.4, **8.5**11.xThe CI matrix tests every compatible combination above with both lowest and stable dependency sets. Laravel 11 reached upstream security end-of-life on March 12, 2026. Version 2.1 retains Laravel 11 runtime compatibility for migrations, but production applications should upgrade to Laravel 12 or 13. The Laravel 11 CI jobs use Composer's `--no-blocking` option solely to resolve that end-of-life framework; the package does not weaken a consuming application's Composer security policy.

Laravel 11 is not listed with PHP 8.5 because [Laravel's support policy](https://laravel.com/docs/13.x/releases#support-policy) ends its PHP range at 8.4; use Laravel 12 or 13 when deploying on PHP 8.5.

Additional requirements:

- `openai-php/laravel` `^0.20`
- An OpenAI API key
- A database supported by your Laravel version

Installation
------------

[](#installation)

Install the package with Composer:

```
composer require halilcosdu/laravel-chatbot
```

Publish its configuration and migrations, then migrate:

```
php artisan vendor:publish --tag=chatbot-config
php artisan vendor:publish --tag=chatbot-migrations
php artisan migrate
```

Laravel discovers the service provider and `ChatBot` facade automatically.

### Environment

[](#environment)

At minimum, configure your API key:

```
OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-5.4-mini
OPENAI_TIMEOUT=30
```

Optional values:

```
OPENAI_INSTRUCTIONS="You are a concise support assistant."
OPENAI_ORGANIZATION=
OPENAI_PROJECT=
```

`OPENAI_PROMPT_ID` remains available for applications already using reusable prompt objects. OpenAI's [deprecation schedule](https://developers.openai.com/api/docs/deprecations) says reusable prompts will shut down on November 30, 2026, so new integrations should keep instructions in application configuration instead.

### Configuration

[](#configuration)

The published `config/chatbot.php` contains:

```
use HalilCosdu\ChatBot\Models\Thread;
use HalilCosdu\ChatBot\Models\ThreadMessage;

return [
    'model' => env('OPENAI_MODEL', 'gpt-5.4-mini'),
    'instructions' => env('OPENAI_INSTRUCTIONS'),
    'prompt_id' => env('OPENAI_PROMPT_ID'),

    'api_key' => env('OPENAI_API_KEY'),
    'organization' => env('OPENAI_ORGANIZATION'),
    'project' => env('OPENAI_PROJECT'),
    'request_timeout' => (int) env('OPENAI_TIMEOUT', 30),

    'response_options' => [],

    'models' => [
        'thread' => env('CHATBOT_THREAD_MODEL', Thread::class),
        'thread_messages' => env('CHATBOT_THREAD_MESSAGE_MODEL', ThreadMessage::class),
    ],
];
```

Put options shared by every managed response in `response_options`:

```
'response_options' => [
    'max_output_tokens' => 1200,
    'reasoning' => ['effort' => 'low'],
],
```

The package always supplies `input` and `conversation`, and it chooses streaming internally. Those keys cannot be replaced through managed thread methods.

The chatbot client is container-isolated from `openai-php/laravel`'s application-level `ClientContract`. Your application's own OpenAI binding and `config/openai.php` can therefore coexist without replacing the credentials or timeout used by this package.

Quick start
-----------

[](#quick-start)

```
use HalilCosdu\ChatBot\Facades\ChatBot;

$thread = ChatBot::createThread(
    'Explain why the sky is blue.',
    ownerId: auth()->id(),
);

$assistantMessage = ChatBot::updateThread(
    'Why does it turn red at sunset?',
    id: $thread->getKey(),
    ownerId: auth()->id(),
);

echo $assistantMessage->content;
```

The package creates one remote Conversation and stores the user and assistant messages locally. Later calls reuse the remote conversation ID so OpenAI retains the conversation state.

Managed API
-----------

[](#managed-api)

MethodResultPurpose`createThread($subject, $ownerId, $options)`Eloquent threadCreate a conversation and wait for the first answer.`createThreadStreamed($subject, $ownerId, $options)``StreamedThreadResponse`Create a conversation and iterate its first answer as text deltas.`updateThread($message, $id, $ownerId, $options)`Eloquent messageContinue a conversation and wait for the answer.`updateThreadStreamed($message, $id, $ownerId, $options)``StreamedThreadResponse`Continue a conversation and iterate text deltas.`listThreads($ownerId, $search, $appends)`paginatorList newest threads, optionally scoped and searched.`thread($id, $ownerId)`Eloquent threadRetrieve a thread with its messages.`deleteThread($id, $ownerId)``void`Delete the remote Conversation and local thread.### Per-request options

[](#per-request-options)

The final `$options` argument is merged over `response_options`. It is useful for changing a model, token budget, reasoning effort, metadata, or supported tools for one request:

```
$message = ChatBot::updateThread(
    message: 'Give me the short version.',
    id: $thread->getKey(),
    ownerId: auth()->id(),
    options: [
        'model' => 'gpt-5.4-mini',
        'max_output_tokens' => 300,
        'reasoning' => ['effort' => 'low'],
        'metadata' => ['feature' => 'support-chat'],
    ],
);
```

Passing a `model` explicitly bypasses a configured `prompt_id`. Passing a `prompt` uses that prompt and omits `model` and `instructions`, matching the package's existing prompt behavior.

Streaming responses
-------------------

[](#streaming-responses)

Streaming uses the Responses API's [semantic events](https://developers.openai.com/api/docs/guides/streaming-responses) internally and exposes only text deltas. The returned object also gives you the local thread immediately:

```
$stream = ChatBot::createThreadStreamed(
    'Write a short welcome message.',
    ownerId: auth()->id(),
);

$threadId = $stream->thread->getKey();

foreach ($stream as $delta) {
    echo $delta;
}

// Available only after the stream has completed.
$savedMessage = $stream->assistantMessage();
$completed = $stream->completed();
```

`StreamedThreadResponse` is intentionally single-use. A successful terminal `response.completed` event is required before the package stores the assistant message. If the stream fails, ends early, or the consumer disconnects, the user message remains in the local transcript but no incomplete assistant message is invented.

### Laravel streamed HTTP response

[](#laravel-streamed-http-response)

```
use HalilCosdu\ChatBot\Facades\ChatBot;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/chat', function (Request $request) {
    $stream = ChatBot::createThreadStreamed(
        subject: $request->string('message')->toString(),
        ownerId: $request->user()->getAuthIdentifier(),
    );

    return response()->stream(function () use ($stream): void {
        foreach ($stream as $delta) {
            echo $delta;

            if (ob_get_level() > 0) {
                ob_flush();
            }

            flush();
        }
    }, 200, [
        'Cache-Control' => 'no-cache, no-transform',
        'Content-Type' => 'text/plain; charset=utf-8',
        'X-Accel-Buffering' => 'no',
        'X-Chatbot-Thread' => (string) $stream->thread->getKey(),
    ]);
});
```

Reverse proxies may buffer output even when PHP flushes it. Disable buffering for this endpoint in your web server or proxy configuration. Streaming partial output also makes moderation harder than moderating a completed answer; account for that in production applications.

Listing and owner isolation
---------------------------

[](#listing-and-owner-isolation)

```
$threads = ChatBot::listThreads(
    ownerId: auth()->id(),
    search: 'invoice',
    appends: request()->query(),
);

$thread = ChatBot::thread($id, ownerId: auth()->id());
ChatBot::deleteThread($id, ownerId: auth()->id());
```

Pass the authenticated owner's ID to every read, update, stream, and delete call. The package applies the owner condition in the database query, including valid IDs such as `0`; a mismatched owner receives Laravel's normal `ModelNotFoundException`.

Local data and custom models
----------------------------

[](#local-data-and-custom-models)

`threads` stores the owner, short subject, and remote Conversation ID. `thread_messages` stores the ordered local transcript and is deleted with its parent thread.

To add casts, relationships, or tenant behavior, extend the package models:

```
namespace App\Models;

use HalilCosdu\ChatBot\Models\Thread as BaseThread;

class ChatThread extends BaseThread
{
    protected $table = 'threads';
}
```

Then configure the class:

```
CHATBOT_THREAD_MODEL="App\Models\ChatThread"
CHATBOT_THREAD_MESSAGE_MODEL="App\Models\ChatThreadMessage"
```

Custom classes must be Eloquent models. Extending the package models is recommended so their relationship methods and bundled factories remain available. The package always uses the stable `thread_id` foreign key, even when your custom class has a different name.

Raw OpenAI access
-----------------

[](#raw-openai-access)

Raw methods return the SDK's typed response objects and do not write local models:

```
ChatBot::createConversationAsRaw(['metadata' => ['tenant' => 'acme']]);
ChatBot::conversationAsRaw($conversationId);
ChatBot::updateConversationAsRaw($conversationId, ['metadata' => ['state' => 'active']]);
ChatBot::listConversationItemsAsRaw($conversationId, ['limit' => 20]);
ChatBot::deleteConversationAsRaw($conversationId);

ChatBot::createResponseAsRaw([
    'model' => 'gpt-5.4-mini',
    'input' => 'Hello',
]);

$events = ChatBot::createResponseStreamedAsRaw([
    'model' => 'gpt-5.4-mini',
    'input' => 'Hello',
]);

foreach ($events as $event) {
    // Inspect $event->event and the typed $event->response payload.
}

ChatBot::responseAsRaw($responseId);
```

Use the managed methods when you want conversation continuity and local persistence. Use the raw methods when you need API features that the managed text workflow does not interpret.

Migrating from 1.x
------------------

[](#migrating-from-1x)

Version 1.x used Assistants threads (`thread_*`); version 2.x uses Conversations (`conv_*`). These IDs are not interchangeable.

After publishing and running the 2.x migrations, inspect and migrate your local transcripts:

```
php artisan chatbot:migrate-to-conversations --dry-run
php artisan chatbot:migrate-to-conversations
```

Useful options:

```
php artisan chatbot:migrate-to-conversations --limit=100
```

The command:

- selects only threads without `remote_conversation_id`;
- reconstructs user messages as `input_text` and assistant messages as `output_text`;
- skips empty transcripts;
- continues after individual API failures and returns a failing exit code if any fail;
- is idempotent, so it can be run again safely.

See [UPGRADE.md](UPGRADE.md) for the complete 1.x to 2.x migration guide.

Error handling
--------------

[](#error-handling)

Managed responses throw `HalilCosdu\ChatBot\Exceptions\ChatBotException` when OpenAI returns a failed or incomplete response, produces no text, or ends a stream without a completion event.

```
use HalilCosdu\ChatBot\Exceptions\ChatBotException;

try {
    $message = ChatBot::updateThread('Hello', $threadId, auth()->id());
} catch (ChatBotException $exception) {
    report($exception);

    return back()->withErrors(['chat' => 'The assistant could not complete its response.']);
}
```

Transport and authentication errors from the underlying SDK are not hidden. Laravel's `ModelNotFoundException` is also preserved for missing or incorrectly scoped threads.

Testing and quality
-------------------

[](#testing-and-quality)

Run the complete local quality gate:

```
composer test-all
```

Or run checks independently:

```
composer test
composer analyse
composer format-test
composer test-coverage
```

The GitHub compatibility workflow covers PHP 8.2 through 8.5 across Laravel 11, 12, and 13 using each framework's supported PHP range.

Security
--------

[](#security)

Please do not publish API keys, prompts containing secrets, or sensitive transcript data in issues. Report vulnerabilities privately using the process in [SECURITY.md](SECURITY.md).

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for release history.

Credits
-------

[](#credits)

- [Halil Cosdu](https://github.com/halilcosdu)
- [All contributors](https://github.com/halilcosdu/laravel-chatbot/graphs/contributors)

License
-------

[](#license)

Laravel Chatbot is open-sourced software licensed under the [MIT license](LICENSE.md).

###  Health Score

54

—

FairBetter than 97% of packages

Maintenance85

Actively maintained with recent releases

Popularity38

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity63

Established project with proven stability

 Bus Factor1

Top contributor holds 58.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~54 days

Recently: every ~23 days

Total

16

Last Release

28d ago

Major Versions

v1.3.1 → v2.0.02026-07-03

### Community

Maintainers

![](https://www.gravatar.com/avatar/eb33d4d47ce7f6f885331f34e8ed984e57866237d54526a2e3c97bdcbb11ecbb?d=identicon)[halilcosdu](/maintainers/halilcosdu)

---

Top Contributors

[![halilcosdu](https://avatars.githubusercontent.com/u/6373017?v=4)](https://github.com/halilcosdu "halilcosdu (42 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (15 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (12 commits)")[![rashidlaasri](https://avatars.githubusercontent.com/u/36804104?v=4)](https://github.com/rashidlaasri "rashidlaasri (2 commits)")[![gracieuxsikuly](https://avatars.githubusercontent.com/u/80897404?v=4)](https://github.com/gracieuxsikuly "gracieuxsikuly (1 commits)")

---

Tags

laravelaiopenaichatbotlaravel-chatbotresponses-api

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/halilcosdu-laravel-chatbot/health.svg)

```
[![Health](https://phpackages.com/badges/halilcosdu-laravel-chatbot/health.svg)](https://phpackages.com/packages/halilcosdu-laravel-chatbot)
```

###  Alternatives

[codewithdennis/filament-select-tree

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

329575.9k33](/packages/codewithdennis-filament-select-tree)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3915.5k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
