Describe the bug
The admin endpoint POST /api/settings/test-connection (for service=openrouter) can never succeed. It calls LLMService.test_connection(), but that method does not exist on LLMService, so the handler raises AttributeError and returns a generic failure:
backend_api_python/app/routes/settings.py
result = llm.test_connection() # -> AttributeError
ERROR app.routes.settings: Connection test failed: 'LLMService' object has no attribute 'test_connection'
Response: {"code":0,"msg":"Test failed: 'LLMService' object has no attribute 'test_connection'"}
This is not a regression from a recent change — the method has never existed:
$ git log --oneline -S'def test_connection' -- backend_api_python/app/services/llm.py
# (no commits: the definition was never added)
Steps to reproduce
- Settings -> AI / LLM: select OpenRouter and save a valid API key.
- Click Test OpenRouter connection.
- The request fails with the
AttributeError above, regardless of whether the key is valid.
Expected behaviour
A connectivity probe that actually validates the configured provider + credential and reports a meaningful reason on failure.
Impact
- Operators cannot verify an LLM key from the UI; the button is effectively dead.
- Because the handler short-circuits with an
AttributeError, a genuinely bad key and a broken endpoint look identical from the UI.
Related: aiGenerate silently falls back to a template
POST /api/indicator/aiGenerate swallows model failures and returns its built-in template with HTTP 200. That template passes validation, so debug.returned_candidate is "initial" and the client cannot distinguish a failed model call from a successful response — the UI reports success. Suggest surfacing the fallback reason (currently only in edit_plan["error"]) in the streamed debug frame.
Suggested fix (from a local patch)
Add LLMService.test_connection() and validate against an authenticated endpoint. Two traps worth noting, both verified while fixing this against OpenRouter:
- OpenRouter's
GET /api/v1/models is public — it returns 200 even without a key, so it cannot validate credentials. Use GET /api/v1/auth/key instead.
- OpenRouter provisioning / management keys pass
/auth/key (200) but are rejected by chat completions (401, "User not found"). Detecting is_provisioning_key / is_management_key in the /auth/key payload gives an actionable error instead of a misleading "reachable".
Happy to open a PR with the patch if that is useful.
Environment
- QuantDinger
v5.5.4
- Backend:
backend_api_python (Flask), provider openrouter
Describe the bug
The admin endpoint
POST /api/settings/test-connection(forservice=openrouter) can never succeed. It callsLLMService.test_connection(), but that method does not exist onLLMService, so the handler raisesAttributeErrorand returns a generic failure:Response:
{"code":0,"msg":"Test failed: 'LLMService' object has no attribute 'test_connection'"}This is not a regression from a recent change — the method has never existed:
Steps to reproduce
AttributeErrorabove, regardless of whether the key is valid.Expected behaviour
A connectivity probe that actually validates the configured provider + credential and reports a meaningful reason on failure.
Impact
AttributeError, a genuinely bad key and a broken endpoint look identical from the UI.Related:
aiGeneratesilently falls back to a templatePOST /api/indicator/aiGenerateswallows model failures and returns its built-in template with HTTP 200. That template passes validation, sodebug.returned_candidateis"initial"and the client cannot distinguish a failed model call from a successful response — the UI reports success. Suggest surfacing the fallback reason (currently only inedit_plan["error"]) in the streameddebugframe.Suggested fix (from a local patch)
Add
LLMService.test_connection()and validate against an authenticated endpoint. Two traps worth noting, both verified while fixing this against OpenRouter:GET /api/v1/modelsis public — it returns200even without a key, so it cannot validate credentials. UseGET /api/v1/auth/keyinstead./auth/key(200) but are rejected by chat completions (401,"User not found"). Detectingis_provisioning_key/is_management_keyin the/auth/keypayload gives an actionable error instead of a misleading "reachable".Happy to open a PR with the patch if that is useful.
Environment
v5.5.4backend_api_python(Flask), provideropenrouter