UI Simplification: Remove API Provider Dropdown
Issues: #52, #53 Priority: P1 - UX improvement for hackathon demo Estimated Time: 30 minutes Senior Review: β Approved with changes (incorporated below)
Problem
The current UI has confusing BYOK (Bring Your Own Key) settings:
- Provider dropdown is misleading - Shows "openai" but actually uses free tier when no key
- Examples table shows useless columns - API Key (empty), Provider (ignored)
- Anthropic doesn't work with Advanced mode - Only OpenAI has
agent-frameworksupport
Solution
Remove api_provider dropdown entirely. Auto-detect provider from key prefix.
Functionality preserved:
- Simple mode: Free tier, OpenAI, OR Anthropic (all work)
- Advanced mode: OpenAI only (Magentic multi-agent requires
OpenAIChatClient)
Implementation
File: src/app.py
Change 1: Update configure_orchestrator() signature (lines 23-28)
# BEFORE
def configure_orchestrator(
use_mock: bool = False,
mode: str = "simple",
user_api_key: str | None = None,
api_provider: str = "openai", # β REMOVE
) -> tuple[Any, str]:
# AFTER
def configure_orchestrator(
use_mock: bool = False,
mode: str = "simple",
user_api_key: str | None = None,
) -> tuple[Any, str]:
Change 2: Update docstring (lines 29-40)
# AFTER
"""
Create an orchestrator instance.
Args:
use_mock: If True, use MockJudgeHandler (no API key needed)
mode: Orchestrator mode ("simple" or "advanced")
user_api_key: Optional user-provided API key (BYOK) - auto-detects provider
Returns:
Tuple of (Orchestrator instance, backend_name)
"""
Change 3: Replace provider logic with auto-detection (lines 62-88)
# BEFORE (lines 62-88) - complex provider checking with api_provider param
# AFTER - auto-detect from key prefix
# 2. Paid API Key (User provided or Env)
elif user_api_key and user_api_key.strip():
# Auto-detect provider from key prefix
model: AnthropicModel | OpenAIModel
if user_api_key.startswith("sk-ant-"):
# Anthropic key
anthropic_provider = AnthropicProvider(api_key=user_api_key)
model = AnthropicModel(settings.anthropic_model, provider=anthropic_provider)
backend_info = "Paid API (Anthropic)"
elif user_api_key.startswith("sk-"):
# OpenAI key
openai_provider = OpenAIProvider(api_key=user_api_key)
model = OpenAIModel(settings.openai_model, provider=openai_provider)
backend_info = "Paid API (OpenAI)"
else:
raise ValueError(
"Invalid API key format. Expected sk-... (OpenAI) or sk-ant-... (Anthropic)"
)
judge_handler = JudgeHandler(model=model)
# 3. Environment API Keys (fallback)
elif os.getenv("OPENAI_API_KEY"):
judge_handler = JudgeHandler(model=None) # Uses env key
backend_info = "Paid API (OpenAI from env)"
elif os.getenv("ANTHROPIC_API_KEY"):
judge_handler = JudgeHandler(model=None) # Uses env key
backend_info = "Paid API (Anthropic from env)"
# 4. Free Tier (HuggingFace Inference)
else:
judge_handler = HFInferenceJudgeHandler()
backend_info = "Free Tier (Llama 3.1 / Mistral)"
Change 4: Update research_agent() signature (lines 105-111)
# BEFORE
async def research_agent(
message: str,
history: list[dict[str, Any]],
mode: str = "simple",
api_key: str = "",
api_provider: str = "openai", # β REMOVE
) -> AsyncGenerator[str, None]:
# AFTER
async def research_agent(
message: str,
history: list[dict[str, Any]],
mode: str = "simple",
api_key: str = "",
) -> AsyncGenerator[str, None]:
Change 5: Update docstring (lines 112-124)
# AFTER
"""
Gradio chat function that runs the research agent.
Args:
message: User's research question
history: Chat history (Gradio format)
mode: Orchestrator mode ("simple" or "advanced")
api_key: Optional user-provided API key (BYOK - auto-detects provider)
Yields:
Markdown-formatted responses for streaming
"""
Change 6: Fix Advanced mode check (line 139)
# BEFORE
if mode == "advanced" and not (has_openai or (has_user_key and api_provider == "openai")):
# AFTER - auto-detect OpenAI key from prefix
is_openai_user_key = user_api_key and user_api_key.startswith("sk-") and not user_api_key.startswith("sk-ant-")
if mode == "advanced" and not (has_openai or is_openai_user_key):
yield (
"β οΈ **Advanced mode requires OpenAI API key.** "
"Anthropic keys only work in Simple mode. Falling back to Simple.\n\n"
)
mode = "simple"
Change 7: Remove premature "Using your key" message (lines 146-151)
# BEFORE - uses api_provider which no longer exists
if has_user_key:
yield (
f"π **Using your {api_provider.upper()} API key** - "
"Your key is used only for this session and is never stored.\n\n"
)
# AFTER - remove this block entirely
# The backend_name from configure_orchestrator already shows "Paid API (OpenAI)" or "Paid API (Anthropic)"
# No need for duplicate messaging
Change 8: Update configure_orchestrator call (lines 165-170)
# BEFORE
orchestrator, backend_name = configure_orchestrator(
use_mock=False,
mode=mode,
user_api_key=user_api_key,
api_provider=api_provider, # β REMOVE
)
# AFTER
orchestrator, backend_name = configure_orchestrator(
use_mock=False,
mode=mode,
user_api_key=user_api_key,
)
Change 9: Simplify examples (lines 210-229)
# BEFORE - 4 items per example
examples=[
["What drugs improve female libido post-menopause?", "simple", "", "openai"],
["Clinical trials for erectile dysfunction alternatives to PDE5 inhibitors?", "simple", "", "openai"],
["Evidence for testosterone therapy in women with HSDD?", "simple", "", "openai"],
],
# AFTER - 2 items per example (query, mode) - API key always empty in examples
examples=[
["What drugs improve female libido post-menopause?", "simple"],
["Clinical trials for ED alternatives to PDE5 inhibitors?", "simple"],
["Evidence for testosterone therapy in women with HSDD?", "simple"],
],
Change 10: Update additional_inputs (lines 231-252)
# BEFORE - 3 inputs (mode, api_key, api_provider)
additional_inputs=[
gr.Radio(
choices=["simple", "advanced"],
value="simple",
label="Orchestrator Mode",
info="Simple: Linear (Free Tier Friendly) | Advanced: Multi-Agent (Requires OpenAI)",
),
gr.Textbox(
label="π API Key (Optional - BYOK)",
placeholder="sk-... or sk-ant-...",
type="password",
info="Enter your own API key. Never stored.",
),
gr.Radio( # β REMOVE THIS ENTIRE BLOCK
choices=["openai", "anthropic"],
value="openai",
label="API Provider",
info="Select the provider for your API key",
),
],
# AFTER - 2 inputs (mode, api_key)
additional_inputs=[
gr.Radio(
choices=["simple", "advanced"],
value="simple",
label="Orchestrator Mode",
info="Simple: Works with any key or free tier | Advanced: Requires OpenAI key",
),
gr.Textbox(
label="π API Key (Optional)",
placeholder="sk-... (OpenAI) or sk-ant-... (Anthropic)",
type="password",
info="Leave empty for free tier. Auto-detects provider from key prefix.",
),
],
Change 11: Update accordion label (line 230)
# BEFORE
additional_inputs_accordion=gr.Accordion(label="βοΈ Settings", open=False),
# AFTER
additional_inputs_accordion=gr.Accordion(label="βοΈ Settings (Free tier works without API key)", open=False),
Testing Checklist
Manual Tests
- No key: Shows "Free Tier (Llama 3.1 / Mistral)" in backend
- OpenAI key (sk-...): Shows "Paid API (OpenAI)" in backend
- Anthropic key (sk-ant-...): Shows "Paid API (Anthropic)" in backend
- Invalid key format: Shows error message
- Anthropic key + Advanced mode: Falls back to Simple with warning
- OpenAI key + Advanced mode: Uses full Magentic multi-agent
- Examples table: Shows only 2 columns (query, mode)
- MCP server: Still accessible at
/gradio_api/mcp/
Unit Test Updates
-
tests/unit/test_app_smoke.py- may need update if checking input count
Definition of Done
-
api_providerparameter removed fromconfigure_orchestrator() -
api_providerparameter removed fromresearch_agent() - Auto-detection logic works for
sk-andsk-ant-prefixes - Advanced mode check uses auto-detection (not removed param)
- "Using your X key" message removed (backend_name handles this)
- Examples table shows 2 columns
- Accordion label updated
- Placeholder text shows both key formats
- All existing tests pass
- MCP server still works
Mode Compatibility Matrix (Unchanged)
| Mode | No Key | OpenAI Key | Anthropic Key |
|---|---|---|---|
| Simple | β Free tier | β GPT-5.1 | β Claude Sonnet 4.5 |
| Advanced | β οΈ Falls back | β Full Magentic | β οΈ Falls back to Simple |
Related
- Issue #52: UI Polish - Examples table confusion
- Issue #53: API Provider Simplification
- Senior Review: Approved 2025-11-28