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)

# 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_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