Secrets and values that change per environment go in your application’s .env file. Other package settings go in config/ai.php, under providers.workers-ai. Laravel AI’s own keys, such as default_for_classification, are at the top level of that file. You choose the provider name. The driver value is workers-ai.
Environment variables
Add the variables your route needs to your application’s .env file:
CLOUDFLARE_AI_API_TOKEN=
CLOUDFLARE_ACCOUNT_ID=
CLOUDFLARE_AI_GATEWAY=
CLOUDFLARE_AI_GATEWAY_TOKEN=
CLOUDFLARE_AI_URL=| Variable | Config key | Needed for |
|---|---|---|
CLOUDFLARE_AI_API_TOKEN |
key |
All routes |
CLOUDFLARE_ACCOUNT_ID |
account_id |
All routes except a custom URL |
CLOUDFLARE_AI_GATEWAY |
gateway |
The gateway route |
CLOUDFLARE_AI_GATEWAY_TOKEN |
gateway_token |
An authenticated gateway |
CLOUDFLARE_AI_URL |
url |
A custom URL |
The package does not read these variables by itself. Each one takes effect when config/ai.php reads it with env(), as in the example below. These names are a convention, so you can use others. See Direct and gateway routes for what each route needs.
Full example
'providers' => [
'workers-ai' => [
'driver' => 'workers-ai',
'key' => env('CLOUDFLARE_AI_API_TOKEN'),
'account_id' => env('CLOUDFLARE_ACCOUNT_ID'),
'gateway' => env('CLOUDFLARE_AI_GATEWAY'),
'default_max_tokens' => 4096,
'reasoning_effort' => 'low',
'throw_on_empty_response' => true,
'throw_on_truncation' => false,
'structured_output_retries' => 2,
'retry' => true,
'retry_attempts' => 3,
'retry_rate_limited' => true,
'models' => [
'text' => [
'default' => '@cf/meta/llama-3.3-70b-instruct-fp8-fast',
'cheapest' => '@cf/meta/llama-3.2-3b-instruct',
'smartest' => '@cf/moonshotai/kimi-k2.6',
],
'embeddings' => [
'default' => '@cf/baai/bge-large-en-v1.5',
'dimensions' => 1024,
],
'classification' => [
'default' => '@cf/cloudflare/clef',
'cheapest' => '@cf/cloudflare/clef-flash',
],
'extraction' => [
'default' => '@cf/cloudflare/clairic',
],
'reranking' => [
'default' => '@cf/baai/bge-reranker-base',
],
'image' => [
'default' => '@cf/black-forest-labs/flux-2-klein-4b',
],
'audio' => [
'default' => '@cf/deepgram/aura-2-en',
],
'transcription' => [
'default' => '@cf/openai/whisper-large-v3-turbo',
],
],
],
],Connection
| Key | Type | Default | Description |
|---|---|---|---|
driver |
string | none | Required. workers-ai. |
key |
string | none | Required. A Cloudflare API token with the permission named Account > Workers AI > Read in the dashboard. The old name api_key still works. If both are set, key wins. |
account_id |
string | none | Cloudflare account ID. Required unless you set url. Use the 32-character hex string, not a URL. |
gateway |
string | none | AI Gateway slug. Sends requests through the gateway. Clef and Clairic send it as the cf-aig-gateway-id header. |
gateway_path |
string | compat |
Path after the gateway slug. Set workers-ai/v1 for the provider path. Used only with gateway. |
gateway_token |
string | none | Optional. An AI Gateway token with Run permission. Needed only for chat and embeddings on an authenticated gateway. Sent as cf-aig-authorization. Cloudflare does not need it for Clef and Clairic, but the package still sends it if you set it. |
url |
string | none | Full endpoint URL. Do not set it with account_id. The package throws if both are set. For Clef and Clairic, the package derives the /ai/run URL from it. A /compat URL throws for those two. |
session_affinity |
string | none | Value for the x-session-affinity header. |
headers |
array | [] |
Extra HTTP headers. They replace package headers of the same name, matched without regard to case. Also receives headers set with Provider::withHeaders() on laravel/ai 1.x. |
The package resolves the endpoint in this order: url, then account_id with gateway, then account_id alone. See Routes.
Generation
| Key | Type | Default | Description |
|---|---|---|---|
default_max_tokens |
int or null | 4096 |
Sent as max_completion_tokens when the call or agent sets no cap. null sends no cap. |
reasoning_effort |
string or null | null |
low, medium or high. Other values throw InvalidArgumentException. |
structured_output_retries |
int | 2 |
Times the package re-asks for schema-valid output. 0 turns it off. |
models.text.default |
string | @cf/meta/llama-3.3-70b-instruct-fp8-fast |
Default text model. |
models.text.cheapest |
string | @cf/meta/llama-3.2-3b-instruct |
Model for #[UseCheapestModel]. |
models.text.smartest |
string | @cf/moonshotai/kimi-k2.6 |
Model for #[UseSmartestModel]. |
models.embeddings.default |
string | @cf/baai/bge-large-en-v1.5 |
Default embedding model. |
models.embeddings.dimensions |
int | 1024 |
Dimensions reported to Laravel AI. Not sent to Cloudflare. |
models.classification.default |
string | @cf/cloudflare/clef |
Clef model for Classification::of()->classify() when the call names none. Needs laravel/ai 1.0 or later. |
models.classification.cheapest |
string | @cf/cloudflare/clef-flash |
Returned by cheapestClassificationModel(). Not selected automatically. |
models.reranking.default |
string | @cf/baai/bge-reranker-base |
Reranking model. |
models.image.default |
string | @cf/black-forest-labs/flux-2-klein-4b |
Image model. |
models.audio.default |
string | @cf/deepgram/aura-2-en |
Speech model. |
models.transcription.default |
string | @cf/openai/whisper-large-v3-turbo |
Transcription model. |
convert_documents |
bool | false |
Convert document attachments on chat calls to Markdown. See Documents. |
models.extraction.default |
string | @cf/cloudflare/clairic |
Clairic model for Extraction::of()->extract() when the call names none. |
Default classification provider
This key belongs to Laravel AI, not to this package. Set it in config/ai.php at the top level, next to default.
| Key | Type | Default | Description |
|---|---|---|---|
ai.default_for_classification |
string | typesafe |
The provider that Classification::of()->classify() and Str::decide() use when you name none. Set it to workers-ai to run them on Clef. |
'default_for_classification' => 'workers-ai',Failure handling
| Key | Type | Default | Description |
|---|---|---|---|
throw_on_empty_response |
bool | true |
Throw EmptyResponseException when a step has no text and no tool calls. |
throw_on_truncation |
bool | false |
Throw TruncatedResponseException when a step ends with finish reason length. |
retry |
bool | true |
false turns off all retrying. |
retry_attempts |
int | 3 |
Total attempts, including the first. |
retry_rate_limited |
bool | true |
false makes an HTTP 429 fail at once. |
Per-agent settings
| Setting | Where | Description |
|---|---|---|
#[ReasoningEffort(ReasoningEffort::LOW)] |
Agent class | Sets reasoning_effort for this agent. Beats the config value. Import Meirdick\WorkersAi\Attributes\ReasoningEffort. |
#[MaxTokens(n)] |
Agent class | Sets the token cap. Beats default_max_tokens. |
#[Timeout(n)] |
Agent class | Sets the request timeout in seconds. |
#[Strict] |
Agent class | Sends strict: true with the JSON schema. |
providerOptions() |
Agent method | Adds fields to the request body. Beats the package fields. |
Provider names
The service provider registers the driver as workers-ai. It also registers the alias workersai, so a provider entry with 'driver' => 'workersai' works too.