DeepBoner / docs /bugs /FIX_UI_SIMPLIFICATION.md
VibecoderMcSwaggins's picture
docs: update UI simplification spec with senior review fixes
b866967
|
raw
history blame
9.64 kB
# 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:
1. **Provider dropdown is misleading** - Shows "openai" but actually uses free tier when no key
2. **Examples table shows useless columns** - API Key (empty), Provider (ignored)
3. **Anthropic doesn't work with Advanced mode** - Only OpenAI has `agent-framework` support
## 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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)
```python
# 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_provider` parameter removed from `configure_orchestrator()`
- [ ] `api_provider` parameter removed from `research_agent()`
- [ ] Auto-detection logic works for `sk-` and `sk-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