…nAI-compat providers (fixes The-Pocket#170)
Two bugs in _call_llm_provider:
1. URL double-/v1: when XAI_BASE_URL (or any provider's BASE_URL) already
ends with /v1 (e.g. https://openrouter.ai/api/v1), the code appended
another /v1/chat/completions, producing an invalid URL. The fix checks
for a trailing /v1 and omits the extra prefix.
2. JSON-before-raise_for_status: response.json() was called before
raise_for_status(), so an HTTP error with a non-JSON (e.g. empty) body
caused a confusing JSONDecodeError instead of a clear HTTP error message.
The fix parses JSON first (best-effort, for logging), then calls
raise_for_status(), and surfaces the raw response text when JSON is absent.
Also corrects the README env var name from XAI_URL to XAI_BASE_URL and
adds examples showing that both https://api.x.ai and https://api.x.ai/v1
are accepted as BASE_URL values.
Co-Authored-By: Octopus <liyuan851277048@icloud.com>
Fixes #170
Problem
Two bugs in _call_llm_provider affect users who configure non-Gemini providers (xAI, Ollama, OpenRouter):
1. Double /v1/ in the constructed URL
When XAI_BASE_URL (or any provider's BASE_URL) already ends with /v1 — as OpenRouter and the xAI API both recommend — the code appended another /v1/chat/completions, producing an invalid URL like:
This caused the API to return an empty or non-JSON response body, which then triggered the second bug.
2. response.json() called before raise_for_status()
Because response.json() was called before raise_for_status(), an HTTP error whose body happened to be empty (or plain-text HTML) raised a cryptic JSONDecodeError (caught as RequestException) instead of a clear HTTP error message:
3. README documents wrong env var name
The README instructed users to set XAI_URL, but the code reads XAI_BASE_URL, so users following the README could never configure a non-Gemini provider.
Solution
Testing
Manually verified the URL-construction logic for all four input patterns: