halilcosdu/laravel-chatbot
Add AI-powered chatbots to any Laravel app with this package. It ships chat models, migrations, and a customizable UI, letting you create assistants backed by OpenAI and give users context-aware conversations grounded in your application's data.
Start with the package install and configuration before touching any chatbot UI:
composer require halilcosdu/laravel-chatbotphp artisan vendor:publish --tag="chatbot-config" and php artisan vendor:publish --tag="chatbot-migrations"
php artisan migrateOPENAI_API_KEY and — new in 2.1 — OPENAI_PROJECT to .env. The package registers its own isolated OpenAI client, so you do not need to wire up a shared openai-php/laravel client for basic use.config/chatbot.php. In 2.1 you should ensure project, request_timeout (cast it, since it's read from env), and response_options keys exist if you published the config on an earlier version.First use case: a single conversational turn. Resolve the package's chat/thread entry point, create a new conversation, and send one message. For a UI, the fastest path is a controller that returns a streamed response from createThreadStreamed() and consumes it on the front end as SSE. If you want to confirm behaviour before building the UI, write a feature test that asserts a conversation and its messages rows are created — 2.1 ships coverage for exactly this, so mirroring those tests is the quickest way to understand the data model.
Where to look first:
config/chatbot.php — model class, foreign keys, owner scoping, timeouts, response options.owner_id column used for multi-tenancy.UPGRADE.md#210 and CHANGELOG.md — there is no new migration in 2.1, but published configs need three additions.New vs. existing conversations. Use createThreadStreamed() when the user starts a fresh chat, and updateThreadStreamed() when continuing one. Both now support managed Responses API streaming, which means the package owns conversation state — you pass user input, not raw API payloads. Persist the thread/conversation identifier in your own model or session so you can route follow-up turns back to updateThreadStreamed().
Per-request options vs. global options. 2.1 adds both a global response_options config array and per-request overrides. The useful pattern is: put stable defaults (model, temperature, tool definitions) in config/chatbot.php, and pass only the deltas per request — for example a higher max_output_tokens for a summarisation endpoint. The package deliberately protects its managed input, conversation, and stream keys, so you cannot accidentally clobber prompt/thread state via options. Treat that as a guardrail, not an obstacle: if an option silently doesn't take effect, it is probably a managed key.
Streaming integration. Return the streamed response directly from a controller route and consume it with EventSource or a fetch reader on the front end. Keep the controller thin — validation, authorisation, then delegate. Because the package manages stream state, don't try to mutate the response inside a middleware; do your logging and usage accounting in a listener or after the stream completes.
Multi-tenant / owner scoping. The owner_id column and config drive conversation visibility. If you scope chats per user or per team, set the owner explicitly at creation rather than relying on ambient auth state, and add your own policy checks on the conversation model before calling updateThreadStreamed() — the package scopes queries, but it cannot know your authorization rules. The 2.1 fix for owner ID 0 matters here: audit any historical assumption that id 0 means "unowned".
Custom models and foreign keys. If you subclass the package's conversation/message models, update the config's model class and foreign key names together. 2.1 fixed custom-model foreign key handling and raw list parameter forwarding, so custom model setups that previously needed workarounds can be simplified.
Timeouts. The effective default request timeout is now 30 seconds. For long generations, raise request_timeout per request or in config — but keep the front-end stream reader's timeout in sync, or the browser will give up before the server does. Cast the value to an integer in your published config; an un-cast string is a classic source of silent misbehaviour.
Client isolation. Because the package registers an isolated OpenAI client, you can inject a fake or a configured client into the container in tests without disturbing other packages using openai-php/laravel. Use this in feature tests rather than hitting the network.
project, cast request_timeout, and add response_options. Missing keys are the most likely cause of a broken upgrade.0 semantics changed. The scoping fix means rows with owner 0 now behave correctly rather than being treated as a wildcard/null. If you relied on the old behaviour — for example a "system" or "guest" owner stored as 0 — migrate those rows to a real sentinel value before deploying.migrate:fresh, then migrate:rollback) if you have customised the published migrations; earlier versions left state behind.response_options or a non-managed key instead.How can I help you explore Laravel packages today?