File size: 9,642 Bytes
b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 dfdeb30 b866967 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 |
# 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
|