Skip to content

Auto-detect DEFAULT_PROVIDER from whichever LLM API key is set#18

Closed
mkonopelski-gd wants to merge 1 commit into
mainfrom
fix/llm-provider-change
Closed

Auto-detect DEFAULT_PROVIDER from whichever LLM API key is set#18
mkonopelski-gd wants to merge 1 commit into
mainfrom
fix/llm-provider-change

Conversation

@mkonopelski-gd

Copy link
Copy Markdown
Contributor

Summary

  • Hand-editing .env to switch from OPENROUTER_API_KEY to ANTHROPIC_API_KEY (without re-running specflow-init.sh) left DEFAULT_PROVIDER unset. docker-compose's hardcoded ${DEFAULT_PROVIDER:-openrouter} fallback then forced openrouter, failing backend startup validation (Missing environment variables: OPENROUTER_API_KEY) even though a valid Anthropic key was present.
  • This also produced a confusing symptom in specflow tui: /health/ready returned 503 (backend up but not ready), and the startup gate reused the "containers aren't running" screen for that case, making it look like Docker/container detection was broken when it wasn't.
  • Settings now infers DEFAULT_PROVIDER from whichever of ANTHROPIC_API_KEY / OPENROUTER_API_KEY is actually set, on every construction — not just once at init time — matching the contract already documented in .env.quickstart.example ("set ONE of the two keys ... if both are set, OpenRouter is used by default"). An explicit DEFAULT_PROVIDER still wins.
  • docker-compose.yml now passes DEFAULT_PROVIDER through blank when unset instead of baking in openrouter, so the new inference isn't pre-empted before it reaches the backend.

Test plan

  • backend/test/core/test_enums.py::TestDefaultProviderInference — new cases: anthropic-only, openrouter-only, both-set, neither-set, explicit-override-wins, blank-string-still-infers (mirrors compose's ${DEFAULT_PROVIDER:-}).
  • backend/test/services/test_startup_validation.py::test_anthropic_only_passes_without_explicit_default_provider — regression test reproducing the exact original failure.
  • make unit-tests — backend (1897 passed, 40 skipped) + mcp_server (569 passed), all green.
  • make check-complexity-diff — average CC unchanged (3.66 → 3.66); only the new method (_infer_default_provider_from_keys, CC 5) added.

Hand-editing .env to switch from OPENROUTER_API_KEY to ANTHROPIC_API_KEY
(without re-running specflow-init.sh) left DEFAULT_PROVIDER unset, and
docker-compose's hardcoded `${DEFAULT_PROVIDER:-openrouter}` fallback
silently forced openrouter — failing startup validation even though a
valid Anthropic key was present, which also made the TUI startup gate
misreport containers as "not running" (backend never reached ready).

Settings now infers DEFAULT_PROVIDER from ANTHROPIC_API_KEY/
OPENROUTER_API_KEY presence on every construction (not just at one-time
init), matching the contract already documented in
.env.quickstart.example. Explicit DEFAULT_PROVIDER still overrides.
docker-compose passes through blank instead of baking in "openrouter" so
that inference isn't pre-empted.
Comment on lines +238 to +241
@model_validator(mode="before")
@classmethod
def _infer_default_provider_from_keys(cls, data: object) -> object:
"""Infer DEFAULT_PROVIDER from whichever API key is set, when not explicit.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how is this hooked to the DEFAULT_PROVIDER field?? I dont see direct connection

Comment on lines +243 to +248
Single source of truth for the auto-detection documented in
.env.quickstart.example ("set ONE of the two keys ... if both are set,
OpenRouter is used by default"). Runs on every Settings() construction —
not only at `specflow-init.sh` time — so switching keys by hand later
(without re-running init) still resolves to the right provider instead
of silently falling back to OpenRouter and failing startup validation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this logic will be buried here - better to remove this docstring and just explain this in Settings class as it is now. And make sure README / QUICKSTART have same wording

@awrobel-gd awrobel-gd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left some comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants