Summary
The Setup Wizard stores the raw endpoint URL entered by the user (e.g., https://api.openai.com) without normalizing it to include the required /v1 API version path. This causes OpenAiProvider::testConnection() and all API calls to fail with "Invalid URL (GET /models)" because requests go to https://api.openai.com/models instead of https://api.openai.com/v1/models.
Root Cause
There is an inconsistency between how the Setup Wizard and the Provider classes handle the endpoint URL:
Setup Wizard (ModelDiscovery, ConfigurationGenerator) appends /v1/ itself when making API calls:
// ModelDiscovery.php:115
$request = $this->requestFactory->createRequest('GET', $endpoint . '/v1/models')
// ConfigurationGenerator.php:289
default => $provider->endpoint . '/v1/chat/completions',
OpenAiProvider (AbstractProvider::sendRequest) expects /v1 to already be part of baseUrl:
// AbstractProvider.php:200
$url = rtrim($this->baseUrl, '/') . '/' . ltrim($endpoint, '/');
// OpenAiProvider.php:52
return 'https://api.openai.com/v1'; // getDefaultBaseUrl includes /v1
SetupWizardController::saveAction stores the raw endpoint without normalization:
// SetupWizardController.php:280
$providerEndpoint = is_string($providerData['endpoint'] ?? null) ? $providerData['endpoint'] : '';
// ...
$provider->setEndpointUrl($providerEndpoint); // stored as-is
So the wizard works fine (it appends /v1 itself), but the stored provider breaks because OpenAiProvider doesn't append /v1 — it expects it in the base URL.
Steps to Reproduce
- Open the LLM Setup Wizard
- Enter
https://api.openai.com as the endpoint (without /v1)
- Complete the wizard — detection and model discovery work fine
- Go to Providers module → click "Test Connection"
- Result:
Connection Failed — Invalid URL (GET /models)
Expected Behavior
The Setup Wizard should normalize the endpoint URL before storing it. For known providers, it should ensure the required API version path is included:
| Provider |
User enters |
Should store |
| OpenAI |
https://api.openai.com |
https://api.openai.com/v1 |
| OpenAI |
https://api.openai.com/v1 |
https://api.openai.com/v1 |
| Anthropic |
https://api.anthropic.com |
https://api.anthropic.com |
| Ollama |
http://localhost:11434 |
http://localhost:11434 |
Suggested Fix
Option A (recommended): Normalize the endpoint URL in SetupWizardController::saveAction() or in ProviderDetector::normalizeEndpoint() based on detected adapter type — append /v1 for OpenAI-compatible providers if not already present.
Option B: Make OpenAiProvider append /v1 itself if the base URL doesn't already contain it (defensive, but shifts responsibility).
Workaround
Manually edit the provider record and change endpoint_url from https://api.openai.com to https://api.openai.com/v1.
Summary
The Setup Wizard stores the raw endpoint URL entered by the user (e.g.,
https://api.openai.com) without normalizing it to include the required/v1API version path. This causesOpenAiProvider::testConnection()and all API calls to fail with "Invalid URL (GET /models)" because requests go tohttps://api.openai.com/modelsinstead ofhttps://api.openai.com/v1/models.Root Cause
There is an inconsistency between how the Setup Wizard and the Provider classes handle the endpoint URL:
Setup Wizard (
ModelDiscovery,ConfigurationGenerator) appends/v1/itself when making API calls:OpenAiProvider (
AbstractProvider::sendRequest) expects/v1to already be part ofbaseUrl:SetupWizardController::saveAction stores the raw endpoint without normalization:
So the wizard works fine (it appends
/v1itself), but the stored provider breaks becauseOpenAiProviderdoesn't append/v1— it expects it in the base URL.Steps to Reproduce
https://api.openai.comas the endpoint (without/v1)Connection Failed — Invalid URL (GET /models)Expected Behavior
The Setup Wizard should normalize the endpoint URL before storing it. For known providers, it should ensure the required API version path is included:
https://api.openai.comhttps://api.openai.com/v1https://api.openai.com/v1https://api.openai.com/v1https://api.anthropic.comhttps://api.anthropic.comhttp://localhost:11434http://localhost:11434Suggested Fix
Option A (recommended): Normalize the endpoint URL in
SetupWizardController::saveAction()or inProviderDetector::normalizeEndpoint()based on detected adapter type — append/v1for OpenAI-compatible providers if not already present.Option B: Make
OpenAiProviderappend/v1itself if the base URL doesn't already contain it (defensive, but shifts responsibility).Workaround
Manually edit the provider record and change
endpoint_urlfromhttps://api.openai.comtohttps://api.openai.com/v1.