Configuration
You configure the package with environment variables in .env. The only thing you need is the API key of at least one provider, and AI_GENERATOR_DRIVER when that provider is not OpenAI. The wizard, php artisan ai-generator:install, writes these for you; see Installation.
General settings
| Config key | Environment variable | Default | What it does |
|---|---|---|---|
default_language | AI_GENERATOR_LANGUAGE | nl | Language of a request without language, as an ISO 639-1 code. |
defaults.max_words | AI_GENERATOR_MAX_WORDS | 900 | Word limit of a request without maxWords. |
defaults.reading_level | AI_GENERATOR_LEVEL | general | Reading level of a request without readingLevel: simple, general or expert. |
defaults.tone | AI_GENERATOR_TONE | informal | Tone of a request without tone: informal, neutral or formal. |
driver | AI_GENERATOR_DRIVER | openai | The driver that writes the text: openai, anthropic, gemini or xai, or an alias (chatgpt, claude, google, grok). See Multiple providers. |
fallbacks | AI_GENERATOR_FALLBACKS | empty | Drivers to try in order when the text call fails, comma separated, for example openai,gemini. |
image_driver | AI_GENERATOR_IMAGE_DRIVER | empty | The driver that makes images: openai, gemini or xai. Empty follows the text driver, and uses OpenAI when the text driver cannot make images. |
mcp.enabled | AI_GENERATOR_MCP | true | Register the local MCP server when laravel/mcp is installed. |
mcp.handle | AI_GENERATOR_MCP_HANDLE | ai-generator | The name of that server, for php artisan mcp:start. |
The default language is nl, Dutch. Set AI_GENERATOR_LANGUAGE=en when your site is in English.
Settings per provider
Every provider has its own block under drivers. You only fill in the providers you use.
| Setting | OpenAI | Claude (Anthropic) | Gemini (Google) | Grok (xAI) |
|---|---|---|---|---|
| API key | OPENAI_API_KEY | ANTHROPIC_API_KEY | GEMINI_API_KEY | XAI_API_KEY |
| Text model | OPENAI_MODEL, default gpt-4.1-mini | ANTHROPIC_MODEL, default claude-sonnet-5 | GEMINI_MODEL, default gemini-3.8-flash | XAI_MODEL, default grok-4.7 |
| Image model | OPENAI_IMAGE_MODEL, default gpt-image-2 | none, Claude makes no images | GEMINI_IMAGE_MODEL, default gemini-3.1-flash-image | XAI_IMAGE_MODEL, default grok-imagine-image-2.0 |
| Temperature | OPENAI_TEMPERATURE, default 0.7 | ANTHROPIC_TEMPERATURE, default none | GEMINI_TEMPERATURE, default none | XAI_TEMPERATURE, default none |
| Timeout in seconds | OPENAI_TIMEOUT, default 45 | ANTHROPIC_TIMEOUT, default 45 | GEMINI_TIMEOUT, default 45 | XAI_TIMEOUT, default 45 |
| Base URL | OPENAI_BASE_URL, default https://api.openai.com/v1 | ANTHROPIC_BASE_URL, default https://api.anthropic.com/v1 | GEMINI_BASE_URL, default https://generativelanguage.googleapis.com/v1beta | XAI_BASE_URL, default https://api.x.ai/v1 |
Claude has two more settings:
| Config key | Environment variable | Default | What it does |
|---|---|---|---|
drivers.anthropic.max_tokens | ANTHROPIC_MAX_TOKENS | 8192 | The maximum length of Claude’s answer, in tokens. Claude requires a limit. |
drivers.anthropic.version | ANTHROPIC_VERSION | 2023-06-01 | The value of the anthropic-version header. |
Temperature. An empty temperature sends none. The newest Claude models reject a temperature, so none is sent to Claude, Gemini or Grok unless you set one. OpenAI gets 0.7. OpenAI reasoning models reject a temperature too; set OPENAI_TEMPERATURE= (empty) when you use one.
Timeout. It counts per attempt, and both requests inside generate() (text and image) are tried twice. generateImage() does not use it: that method has a fixed timeout of 120 seconds and tries once.
Models age. Providers retire models. OpenAI shuts down gpt-image-1 on 2026-10-23, so since 1.3.0 the default image model is gpt-image-2, the replacement OpenAI names. Is OPENAI_IMAGE_MODEL set to gpt-image-1 in your .env? Change it to gpt-image-2, or remove the line to follow the default. The wizard lists the image models your key may use.
An example .env
# The keys of the providers you use
ANTHROPIC_API_KEY=your-claude-key
OPENAI_API_KEY=your-openai-key
# Who writes, who draws, who takes over
AI_GENERATOR_DRIVER=anthropic
AI_GENERATOR_IMAGE_DRIVER=openai
AI_GENERATOR_FALLBACKS=openai
# Optional: models
ANTHROPIC_MODEL=claude-sonnet-5
OPENAI_MODEL=gpt-4.1-mini
OPENAI_IMAGE_MODEL=gpt-image-2
# Optional: defaults for a request
AI_GENERATOR_LANGUAGE=en
AI_GENERATOR_TONE=neutral
AI_GENERATOR_LEVEL=general
AI_GENERATOR_MAX_WORDS=600
After a change in .env on a server that caches its config, run php artisan config:clear or php artisan config:cache again. Until then the application keeps the old values.
The config file
You don’t need the file in your application. Publish it when you want to set a value in PHP:
php artisan vendor:publish --tag=ai-generator-config
You get config/ai-generator.php, with the keys in alphabetical order within every group:
return [
'default_language' => env('AI_GENERATOR_LANGUAGE', 'nl'),
'defaults' => [
'max_words' => env('AI_GENERATOR_MAX_WORDS', 900),
'reading_level' => env('AI_GENERATOR_LEVEL', 'general'),
'tone' => env('AI_GENERATOR_TONE', 'informal'),
],
'driver' => env('AI_GENERATOR_DRIVER', 'openai'),
'drivers' => [
'anthropic' => [
'api_key' => env('ANTHROPIC_API_KEY'),
'base_url' => env('ANTHROPIC_BASE_URL', 'https://api.anthropic.com/v1'),
'max_tokens' => env('ANTHROPIC_MAX_TOKENS', 8192),
'model' => env('ANTHROPIC_MODEL', 'claude-sonnet-5'),
'temperature' => env('ANTHROPIC_TEMPERATURE'),
'timeout' => env('ANTHROPIC_TIMEOUT', 45),
'version' => env('ANTHROPIC_VERSION', '2023-06-01'),
],
'gemini' => [
'api_key' => env('GEMINI_API_KEY'),
'base_url' => env('GEMINI_BASE_URL', 'https://generativelanguage.googleapis.com/v1beta'),
'image_model' => env('GEMINI_IMAGE_MODEL', 'gemini-3.1-flash-image'),
'model' => env('GEMINI_MODEL', 'gemini-3.8-flash'),
'temperature' => env('GEMINI_TEMPERATURE'),
'timeout' => env('GEMINI_TIMEOUT', 45),
],
'openai' => [
'api_key' => env('OPENAI_API_KEY'),
'base_url' => env('OPENAI_BASE_URL', 'https://api.openai.com/v1'),
'image_model' => env('OPENAI_IMAGE_MODEL', 'gpt-image-2'),
'model' => env('OPENAI_MODEL', 'gpt-4.1-mini'),
'temperature' => env('OPENAI_TEMPERATURE', 0.7),
'timeout' => env('OPENAI_TIMEOUT', 45),
],
'xai' => [
'api_key' => env('XAI_API_KEY'),
'base_url' => env('XAI_BASE_URL', 'https://api.x.ai/v1'),
'image_model' => env('XAI_IMAGE_MODEL', 'grok-imagine-image-2.0'),
'model' => env('XAI_MODEL', 'grok-4.7'),
'temperature' => env('XAI_TEMPERATURE'),
'timeout' => env('XAI_TIMEOUT', 45),
],
],
'fallbacks' => env('AI_GENERATOR_FALLBACKS', ''),
'image_driver' => env('AI_GENERATOR_IMAGE_DRIVER'),
'mcp' => [
'enabled' => env('AI_GENERATOR_MCP', true),
'handle' => env('AI_GENERATOR_MCP_HANDLE', 'ai-generator'),
],
];
A value you write into this file instead of env(...) wins over .env. Keep that in mind when a change in .env seems to do nothing.
A config file you published with an older version keeps working: no key was renamed or removed. A provider block that is missing from your file falls back to the defaults of the package. Publish again (with --force, after saving your changes) to see the new blocks.
A request option beats the config
The config only fills what a request leaves empty. Pass the value in the request when it differs per text:
use Darvis\LaravelAiGenerator\AiGenerator;
use Darvis\LaravelAiGenerator\ContentRequest;
$result = app(AiGenerator::class)->generate(new ContentRequest(
topic: 'Your topic',
tone: 'formal',
readingLevel: 'expert',
includeImage: false,
));
Read a setting in your own code
The package reads its config in one class, Darvis\LaravelAiGenerator\Support\AiGeneratorConfig. Use the same class when your code needs a package setting, so the default is the same everywhere:
use Darvis\LaravelAiGenerator\Support\AiGeneratorConfig;
use Darvis\LaravelAiGenerator\Support\Provider;
AiGeneratorConfig::defaultLanguage(); // 'nl'
AiGeneratorConfig::model(Provider::Anthropic); // 'claude-sonnet-5'
AiGeneratorConfig::apiKey(Provider::OpenAi); // null when the key is empty or not set
The API reference lists every accessor.
Another endpoint
<PREFIX>_BASE_URL sends the requests of a provider to another host, for example a proxy of your own. The endpoint has to accept exactly what the provider accepts:
- OpenAI:
/responsesfor the text and/images/generationsfor the image, with the key as anAuthorization: Bearerheader. - Claude:
/messages, with the key in anx-api-keyheader. - Gemini:
/models/<model>:generateContent, with the key in anx-goog-api-keyheader. - Grok:
/chat/completionsand/images/generations, with the key as a Bearer token.
A trailing slash in the URL is removed.