config/ai.php. Each provider has one class in
app/Services/LLM, and each entry in the config carries a base URL, a default model, a
batch_supported flag and a model catalogue with cost metadata.
Providers
Claude is the only provider with
batch_supported => true. OpenAI’s is set to false with a
comment noting batch was turned off in favour of realtime processing — so enabling
AI_BATCH_ENABLED does not change OpenAI’s behaviour.
SerpApi is not an LLM — it is how the app reads Google’s AI Overview and AI Mode
surfaces, billed per search (
cost_per_search of 0.01 for both) rather than per token.SEMRUSH_API_KEY, SEMRUSH_BASE_URL) but is a
keyword-data source, not an LLM. The Suggest Prompts flow falls back to it when a campaign has
no Search Console connection. Neither variable is in .env.example — add them by hand if you
need that fallback path.
Model defaults
ONBOARDING_MODEL is separate on purpose. The whole setup wizard — brand name, business
description, topics, prompts, variants — runs on the cheapest fast Gemini model so onboarding
stays snappy and does not consume the OpenAI quota.
Adding a model means adding it to that provider’s models array with a name,
context_window and cost_per_1k_tokens. The cost figure is what TokenUsageTracker uses to
derive spend, so an omitted or stale value silently produces wrong cost reporting.
Rate limits
Configured per provider underrate_limits, as requests and tokens per minute:
These are the app’s own ceilings, not the providers’ published limits. Raise them only after
confirming your account’s actual quota.
Batch settings
check_interval_minutes and retry_attempts are hardcoded — change them in
config/ai.php rather than looking for an environment variable.
Prompt configuration
Ten default prompt categories drive generation:
alternatives, comparison, reviews,
tutorials, pricing, updates, troubleshooting, integrations, plans and security.
Visibility detection
Thevisibility block tunes how VisibilityDetector reads answers:
blog.example.com and
www.example.com count as the same domain.