Commit
Β·
3599f0a
1
Parent(s):
5441526
fix: enhance UX with "thinking" state and API key persistence
Browse files1. Added a "thinking" state yield before blocking calls in Magentic orchestrator to improve user feedback during long processing times.
2. Updated Gradio examples to include explicit None values for API key inputs, ensuring persistence across example clicks.
3. Set temperature explicitly to 1.0 for compatibility with reasoning models in Magentic agents.
All tests passing.
- docs/bugs/P1_MULTIPLE_UX_BUGS.md +23 -148
- docs/bugs/P2_MAGENTIC_THINKING_STATE.md +232 -0
- src/agents/magentic_agents.py +4 -5
- src/app.py +8 -3
- src/orchestrator_magentic.py +11 -0
- src/utils/models.py +2 -0
docs/bugs/P1_MULTIPLE_UX_BUGS.md
CHANGED
|
@@ -5,170 +5,45 @@
|
|
| 5 |
- **Priority:** P1 (Multiple user-facing issues)
|
| 6 |
- **Components:** `src/app.py`, `src/orchestrator_magentic.py`
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
## Bug 1: API Key Cleared When Clicking Examples
|
| 11 |
-
|
| 12 |
-
### Symptoms
|
| 13 |
-
- User enters API key in textbox
|
| 14 |
-
- User clicks an example prompt
|
| 15 |
-
- API key textbox is cleared/reset
|
| 16 |
-
|
| 17 |
-
### Root Cause
|
| 18 |
-
Despite examples only having 2 columns `[message, mode]`, Gradio's ChatInterface still resets `additional_inputs` that aren't in the examples list. The comment on line 273-274 was incorrect:
|
| 19 |
-
|
| 20 |
-
```python
|
| 21 |
-
# API key persists because examples only include [message, mode] columns,
|
| 22 |
-
# so Gradio doesn't overwrite the api_key textbox when examples are clicked.
|
| 23 |
-
```
|
| 24 |
|
| 25 |
-
|
|
|
|
| 26 |
|
| 27 |
-
###
|
| 28 |
-
|
| 29 |
-
```python
|
| 30 |
-
examples=[
|
| 31 |
-
["What drugs improve female libido?", "simple", ""],
|
| 32 |
-
...
|
| 33 |
-
]
|
| 34 |
-
```
|
| 35 |
|
| 36 |
-
|
|
|
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
### Research Needed
|
| 41 |
-
- Gradio ChatInterface 2025 behavior with partial examples
|
| 42 |
-
- Whether `cache_examples=False` affects this
|
| 43 |
|
| 44 |
---
|
| 45 |
|
| 46 |
-
##
|
| 47 |
-
|
| 48 |
-
### Symptoms
|
| 49 |
-
- User submits query
|
| 50 |
-
- UI shows "π STARTED:" message but nothing else
|
| 51 |
-
- No spinner, no "thinking...", no indication work is happening
|
| 52 |
-
- User thinks it's frozen
|
| 53 |
-
|
| 54 |
-
### Container Logs Show
|
| 55 |
-
Work IS happening:
|
| 56 |
-
```
|
| 57 |
-
[info] Creating orchestrator mode=advanced
|
| 58 |
-
[info] Starting Magentic orchestrator query='...'
|
| 59 |
-
[info] Embedding service enabled
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
But user sees nothing for 30+ seconds.
|
| 63 |
-
|
| 64 |
-
### Root Cause
|
| 65 |
-
The Gradio ChatInterface doesn't show intermediate yields quickly enough, and we don't yield a "β³ Processing..." message immediately.
|
| 66 |
-
|
| 67 |
-
### Proposed Fix
|
| 68 |
-
Add immediate feedback in `research_agent()`:
|
| 69 |
-
```python
|
| 70 |
-
yield "β³ **Processing...** Searching PubMed, ClinicalTrials.gov, Europe PMC..."
|
| 71 |
-
```
|
| 72 |
-
|
| 73 |
-
---
|
| 74 |
-
|
| 75 |
-
## Bug 3: Advanced Mode Temperature Error
|
| 76 |
-
|
| 77 |
-
### Error
|
| 78 |
-
```
|
| 79 |
-
Unsupported value: 'temperature' does not support 0.3 with this model.
|
| 80 |
-
Only the default (1) value is supported.
|
| 81 |
-
```
|
| 82 |
-
|
| 83 |
-
### Root Cause
|
| 84 |
-
The `agent_framework` (Magentic) is using `temperature=0.3` but some OpenAI models (like `o3`, `o1`, reasoning models) only support `temperature=1`.
|
| 85 |
-
|
| 86 |
-
### Location
|
| 87 |
-
Likely in `src/orchestrator_magentic.py` or agent-framework configuration.
|
| 88 |
-
|
| 89 |
-
### Proposed Fix
|
| 90 |
-
1. Detect model type and skip temperature for reasoning models
|
| 91 |
-
2. Or: Remove explicit temperature setting, use model defaults
|
| 92 |
-
3. Or: Catch this error and fall back to default temperature
|
| 93 |
-
|
| 94 |
-
---
|
| 95 |
-
|
| 96 |
-
## Bug 4: HSDD Acronym Not Spelled Out
|
| 97 |
-
|
| 98 |
-
### Issue
|
| 99 |
-
Example prompt says:
|
| 100 |
-
```
|
| 101 |
-
"Evidence for testosterone therapy in women with HSDD?"
|
| 102 |
-
```
|
| 103 |
-
|
| 104 |
-
**HSDD = Hypoactive Sexual Desire Disorder** (low libido condition)
|
| 105 |
-
|
| 106 |
-
Most users (including doctors!) won't know this acronym.
|
| 107 |
-
|
| 108 |
-
### Fix
|
| 109 |
-
Change to:
|
| 110 |
-
```
|
| 111 |
-
"Evidence for testosterone therapy in women with HSDD (Hypoactive Sexual Desire Disorder)?"
|
| 112 |
-
```
|
| 113 |
-
|
| 114 |
-
Also update README if it uses this acronym.
|
| 115 |
-
|
| 116 |
-
---
|
| 117 |
-
|
| 118 |
-
## Bug 5: Free Tier Quota Exhausted (Expected Behavior)
|
| 119 |
-
|
| 120 |
-
### Logs
|
| 121 |
-
```
|
| 122 |
-
[error] HF Quota Exhausted error='402 Client Error: Payment Required...'
|
| 123 |
-
```
|
| 124 |
-
|
| 125 |
-
### This is NOT a bug
|
| 126 |
-
HuggingFace free tier has limited credits. When exhausted:
|
| 127 |
-
- User should enter their own API key
|
| 128 |
-
- The app correctly falls back to showing evidence without LLM analysis
|
| 129 |
-
|
| 130 |
-
### UX Improvement
|
| 131 |
-
Show clearer message to user when quota is exhausted:
|
| 132 |
-
```
|
| 133 |
-
β οΈ Free tier quota exceeded. Enter your OpenAI/Anthropic API key above for full analysis.
|
| 134 |
-
```
|
| 135 |
-
|
| 136 |
-
---
|
| 137 |
-
|
| 138 |
-
## Bug 6: Asyncio File Descriptor Warnings (Low Priority)
|
| 139 |
-
|
| 140 |
-
### Error
|
| 141 |
-
```
|
| 142 |
-
ValueError: Invalid file descriptor: -1
|
| 143 |
-
Exception ignored in: <function BaseEventLoop.__del__>
|
| 144 |
-
```
|
| 145 |
-
|
| 146 |
-
### Root Cause
|
| 147 |
-
Event loop cleanup issue in async code. Common when mixing sync/async or when event loops are garbage collected.
|
| 148 |
|
| 149 |
-
###
|
| 150 |
-
**
|
| 151 |
|
| 152 |
-
###
|
| 153 |
-
|
| 154 |
|
| 155 |
---
|
| 156 |
|
| 157 |
-
## Priority Order
|
| 158 |
|
| 159 |
-
1. **Bug 4 (HSDD)** -
|
| 160 |
-
2. **Bug 2 (Loading indicator)** -
|
| 161 |
-
3. **Bug 3 (Temperature)** -
|
| 162 |
-
4. **Bug 1 (API key)** -
|
| 163 |
-
5. **Bug 5 (Quota message)** - Nice to have
|
| 164 |
-
6. **Bug 6 (Asyncio)** - Low priority, cosmetic
|
| 165 |
|
| 166 |
---
|
| 167 |
|
| 168 |
## Test Plan
|
| 169 |
-
- [
|
| 170 |
-
- [
|
| 171 |
-
- [
|
| 172 |
-
- [
|
| 173 |
- [ ] Run `make check`
|
| 174 |
- [ ] Deploy and test on HuggingFace Spaces
|
|
|
|
| 5 |
- **Priority:** P1 (Multiple user-facing issues)
|
| 6 |
- **Components:** `src/app.py`, `src/orchestrator_magentic.py`
|
| 7 |
|
| 8 |
+
## Resolved Issues (Fixed 2025-11-29)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
+
### Bug 1: API Key Cleared When Clicking Examples
|
| 11 |
+
**Fixed.** Updated `examples` in `app.py` to include explicit `None` values for additional inputs. Gradio preserves values when the example value is `None`.
|
| 12 |
|
| 13 |
+
### Bug 2: No Loading/Processing Indicator
|
| 14 |
+
**Fixed.** `research_agent` yields an immediate "β³ Processing..." message before starting the orchestrator.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
+
### Bug 3: Advanced Mode Temperature Error
|
| 17 |
+
**Fixed.** Explicitly set `temperature=1.0` for all Magentic agents in `src/agents/magentic_agents.py`. This is compatible with OpenAI reasoning models (o1/o3) which require `temperature=1` and were rejecting the default (likely 0.3 or None).
|
| 18 |
|
| 19 |
+
### Bug 4: HSDD Acronym Not Spelled Out
|
| 20 |
+
**Fixed.** Updated example text in `app.py` to "HSDD (Hypoactive Sexual Desire Disorder)".
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
---
|
| 23 |
|
| 24 |
+
## Open / Deferred Issues
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
+
### Bug 5: Free Tier Quota Exhausted (UX Improvement)
|
| 27 |
+
**Deferred.** Currently shows standard error message. Improve if users report confusion.
|
| 28 |
|
| 29 |
+
### Bug 6: Asyncio File Descriptor Warnings
|
| 30 |
+
**Won't Fix.** Cosmetic issue only.
|
| 31 |
|
| 32 |
---
|
| 33 |
|
| 34 |
+
## Priority Order (Completed)
|
| 35 |
|
| 36 |
+
1. **Bug 4 (HSDD)** - Fixed
|
| 37 |
+
2. **Bug 2 (Loading indicator)** - Fixed
|
| 38 |
+
3. **Bug 3 (Temperature)** - Fixed
|
| 39 |
+
4. **Bug 1 (API key)** - Fixed
|
|
|
|
|
|
|
| 40 |
|
| 41 |
---
|
| 42 |
|
| 43 |
## Test Plan
|
| 44 |
+
- [x] Fix HSDD acronym
|
| 45 |
+
- [x] Add loading indicator yield
|
| 46 |
+
- [x] Test advanced mode with temperature fix (Static analysis/Code change)
|
| 47 |
+
- [x] Research Gradio example behavior for API key (Implemented None fix)
|
| 48 |
- [ ] Run `make check`
|
| 49 |
- [ ] Deploy and test on HuggingFace Spaces
|
docs/bugs/P2_MAGENTIC_THINKING_STATE.md
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# P2 Bug Report: Advanced Mode Missing "Thinking" State
|
| 2 |
+
|
| 3 |
+
## Status
|
| 4 |
+
- **Date:** 2025-11-29
|
| 5 |
+
- **Priority:** P2 (UX polish, not blocking functionality)
|
| 6 |
+
- **Component:** `src/orchestrator_magentic.py`, `src/app.py`
|
| 7 |
+
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
## Symptoms
|
| 11 |
+
|
| 12 |
+
User experience in **Advanced (Magentic) mode**:
|
| 13 |
+
1. Click example or submit query
|
| 14 |
+
2. See: `π **STARTED**: Starting research (Magentic mode)...`
|
| 15 |
+
3. **2+ minutes of nothing** (no spinner, no progress, no indication work is happening)
|
| 16 |
+
4. Eventually see: `π§ **JUDGING**: Manager (user_task)...`
|
| 17 |
+
|
| 18 |
+
**User perception:** "Is it frozen? Did it crash?"
|
| 19 |
+
|
| 20 |
+
### Container Logs Confirm Work IS Happening
|
| 21 |
+
```
|
| 22 |
+
14:54:22 [info] Starting Magentic orchestrator query='...'
|
| 23 |
+
14:54:22 [info] Embedding service enabled
|
| 24 |
+
... 2+ MINUTES OF SILENCE (agent-framework doing internal LLM calls) ...
|
| 25 |
+
14:56:38 [info] Creating orchestrator mode=advanced
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
The silence is because `workflow.run_stream()` doesn't yield events during its setup phase.
|
| 29 |
+
|
| 30 |
+
---
|
| 31 |
+
|
| 32 |
+
## Root Cause Analysis
|
| 33 |
+
|
| 34 |
+
### Current Flow (`src/orchestrator_magentic.py`)
|
| 35 |
+
```python
|
| 36 |
+
async def run(self, query: str) -> AsyncGenerator[AgentEvent, None]:
|
| 37 |
+
# 1. Immediately yields "started"
|
| 38 |
+
yield AgentEvent(type="started", message=f"Starting research (Magentic mode): {query}")
|
| 39 |
+
|
| 40 |
+
# 2. Setup (fast, no yield needed)
|
| 41 |
+
embedding_service = self._init_embedding_service()
|
| 42 |
+
init_magentic_state(embedding_service)
|
| 43 |
+
workflow = self._build_workflow()
|
| 44 |
+
|
| 45 |
+
# 3. GAP: workflow.run_stream() blocks for 2+ minutes before first event
|
| 46 |
+
async for event in workflow.run_stream(task): # <-- THE BOTTLENECK
|
| 47 |
+
yield self._process_event(event)
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
The `agent-framework`'s `workflow.run_stream()` is calling OpenAI's API, building the manager prompt, coordinating agents, etc. **It doesn't yield events during this setup phase**.
|
| 51 |
+
|
| 52 |
+
---
|
| 53 |
+
|
| 54 |
+
## Gold Standard UX (What We'd Want)
|
| 55 |
+
|
| 56 |
+
### Gradio's Native Thinking Support
|
| 57 |
+
|
| 58 |
+
Per [Gradio Chatbot Docs](https://www.gradio.app/docs/gradio/chatbot):
|
| 59 |
+
|
| 60 |
+
> "The Gradio Chatbot can natively display intermediate thoughts and tool usage in a collapsible accordion next to a chat message. This makes it perfect for creating UIs for LLM agents and chain-of-thought (CoT) or reasoning demos."
|
| 61 |
+
|
| 62 |
+
**Features available:**
|
| 63 |
+
- `gr.ChatMessage` with `metadata={"status": "pending"}` shows spinner
|
| 64 |
+
- `metadata={"title": "Thinking...", "status": "pending"}` creates collapsible accordion
|
| 65 |
+
- Nested thoughts via `id` and `parent_id`
|
| 66 |
+
- `duration` metadata shows time spent
|
| 67 |
+
|
| 68 |
+
**Example from Gradio docs:**
|
| 69 |
+
```python
|
| 70 |
+
import gradio as gr
|
| 71 |
+
|
| 72 |
+
def chat_fn(message, history):
|
| 73 |
+
# Yield thinking state with spinner
|
| 74 |
+
yield gr.ChatMessage(
|
| 75 |
+
role="assistant",
|
| 76 |
+
metadata={"title": "π§ Thinking...", "status": "pending"}
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
# Do work...
|
| 80 |
+
|
| 81 |
+
# Update with completed thought
|
| 82 |
+
yield gr.ChatMessage(
|
| 83 |
+
role="assistant",
|
| 84 |
+
content="Analysis complete",
|
| 85 |
+
metadata={"title": "π§ Thinking...", "status": "done", "duration": 5.2}
|
| 86 |
+
)
|
| 87 |
+
|
| 88 |
+
yield "Here's the final answer..."
|
| 89 |
+
```
|
| 90 |
+
|
| 91 |
+
---
|
| 92 |
+
|
| 93 |
+
## Why This is Complex for DeepBoner
|
| 94 |
+
|
| 95 |
+
### Constraint 1: ChatInterface Returns Strings
|
| 96 |
+
Our `research_agent()` yields plain strings:
|
| 97 |
+
```python
|
| 98 |
+
yield "π§ **Backend**: {backend_name}\n\n"
|
| 99 |
+
yield "β³ **Processing...** Searching PubMed...\n"
|
| 100 |
+
yield "\n\n".join(response_parts)
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
Converting to `gr.ChatMessage` objects would require refactoring the entire response pipeline.
|
| 104 |
+
|
| 105 |
+
### Constraint 2: Agent-Framework is the Bottleneck
|
| 106 |
+
The 2-minute gap is inside `workflow.run_stream(task)`, which is the `agent-framework` library. We can't inject yields into a third-party library's blocking call.
|
| 107 |
+
|
| 108 |
+
### Constraint 3: ChatInterface vs Blocks
|
| 109 |
+
`gr.ChatInterface` is a convenience wrapper. The full `gr.ChatMessage` metadata features work best with raw `gr.Blocks` + `gr.Chatbot` components.
|
| 110 |
+
|
| 111 |
+
---
|
| 112 |
+
|
| 113 |
+
## Options
|
| 114 |
+
|
| 115 |
+
### Option A: Yield "Thinking" Before Blocking Call (Recommended)
|
| 116 |
+
**Effort:** 5 minutes
|
| 117 |
+
**Impact:** Users see *something* while waiting
|
| 118 |
+
|
| 119 |
+
```python
|
| 120 |
+
# In src/orchestrator_magentic.py
|
| 121 |
+
async def run(self, query: str) -> AsyncGenerator[AgentEvent, None]:
|
| 122 |
+
yield AgentEvent(type="started", message=f"Starting research (Magentic mode): {query}")
|
| 123 |
+
|
| 124 |
+
# NEW: Yield thinking state before the blocking call
|
| 125 |
+
yield AgentEvent(
|
| 126 |
+
type="thinking", # New event type
|
| 127 |
+
message="π§ Agents are reasoning... This may take 2-5 minutes for complex queries.",
|
| 128 |
+
iteration=0,
|
| 129 |
+
)
|
| 130 |
+
|
| 131 |
+
# ... rest of setup ...
|
| 132 |
+
|
| 133 |
+
async for event in workflow.run_stream(task):
|
| 134 |
+
yield self._process_event(event)
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
**Pros:**
|
| 138 |
+
- Simple, doesn't require Gradio changes
|
| 139 |
+
- Works with current string-based approach
|
| 140 |
+
- Sets user expectations ("2-5 minutes")
|
| 141 |
+
|
| 142 |
+
**Cons:**
|
| 143 |
+
- No spinner/animation (static text)
|
| 144 |
+
- Doesn't show real-time progress during the gap
|
| 145 |
+
|
| 146 |
+
### Option B: Use `gr.ChatMessage` with Metadata (Major Refactor)
|
| 147 |
+
**Effort:** 2-4 hours
|
| 148 |
+
**Impact:** Full gold-standard UX
|
| 149 |
+
|
| 150 |
+
Would require:
|
| 151 |
+
1. Changing `research_agent()` to yield `gr.ChatMessage` objects
|
| 152 |
+
2. Adding thinking states with `metadata={"status": "pending"}`
|
| 153 |
+
3. Updating all event handlers to produce proper ChatMessage objects
|
| 154 |
+
|
| 155 |
+
### Option C: Heartbeat/Polling (Over-Engineering)
|
| 156 |
+
**Effort:** 4+ hours
|
| 157 |
+
**Impact:** Spinner during blocking call
|
| 158 |
+
|
| 159 |
+
Create a background task that yields "still working..." every 10 seconds while waiting for the agent-framework. Requires:
|
| 160 |
+
- `asyncio.create_task()` for heartbeat
|
| 161 |
+
- Task cancellation when real events arrive
|
| 162 |
+
- Proper cleanup
|
| 163 |
+
|
| 164 |
+
**Verdict:** Over-engineering for a demo.
|
| 165 |
+
|
| 166 |
+
### Option D: Accept the Limitation (Document It)
|
| 167 |
+
**Effort:** 0
|
| 168 |
+
**Impact:** None (users still confused)
|
| 169 |
+
|
| 170 |
+
Just document that Advanced mode takes 2-5 minutes and users should wait.
|
| 171 |
+
|
| 172 |
+
---
|
| 173 |
+
|
| 174 |
+
## Recommendation
|
| 175 |
+
|
| 176 |
+
**Implement Option A** - Add a "thinking" yield before the blocking call.
|
| 177 |
+
|
| 178 |
+
It's:
|
| 179 |
+
1. Minimal code change (5 minutes)
|
| 180 |
+
2. Sets user expectations clearly
|
| 181 |
+
3. Doesn't require Gradio refactoring
|
| 182 |
+
4. Better than silence
|
| 183 |
+
|
| 184 |
+
---
|
| 185 |
+
|
| 186 |
+
## Implementation Plan
|
| 187 |
+
|
| 188 |
+
### Step 1: Add "thinking" Event Type
|
| 189 |
+
```python
|
| 190 |
+
# In src/utils/models.py
|
| 191 |
+
class AgentEvent(BaseModel):
|
| 192 |
+
type: Literal[
|
| 193 |
+
"started", "thinking", "searching", ... # Add "thinking"
|
| 194 |
+
]
|
| 195 |
+
```
|
| 196 |
+
|
| 197 |
+
### Step 2: Yield Thinking Event in Magentic Orchestrator
|
| 198 |
+
```python
|
| 199 |
+
# In src/orchestrator_magentic.py, run() method
|
| 200 |
+
yield AgentEvent(
|
| 201 |
+
type="thinking",
|
| 202 |
+
message="π§ Multi-agent reasoning in progress... This may take 2-5 minutes.",
|
| 203 |
+
iteration=0,
|
| 204 |
+
)
|
| 205 |
+
```
|
| 206 |
+
|
| 207 |
+
### Step 3: Handle in App
|
| 208 |
+
```python
|
| 209 |
+
# In src/app.py, research_agent()
|
| 210 |
+
if event.type == "thinking":
|
| 211 |
+
yield f"β³ {event.message}"
|
| 212 |
+
```
|
| 213 |
+
|
| 214 |
+
---
|
| 215 |
+
|
| 216 |
+
## Test Plan
|
| 217 |
+
|
| 218 |
+
- [ ] Add `"thinking"` to AgentEvent type literals
|
| 219 |
+
- [ ] Add yield before `workflow.run_stream()`
|
| 220 |
+
- [ ] Handle in app.py
|
| 221 |
+
- [ ] `make check` passes
|
| 222 |
+
- [ ] Manual test: Advanced mode shows "reasoning in progress" message
|
| 223 |
+
- [ ] Deploy to HuggingFace, verify UX improvement
|
| 224 |
+
|
| 225 |
+
---
|
| 226 |
+
|
| 227 |
+
## References
|
| 228 |
+
|
| 229 |
+
- [Gradio ChatInterface Docs](https://www.gradio.app/docs/gradio/chatinterface)
|
| 230 |
+
- [Gradio Chatbot Metadata](https://www.gradio.app/docs/gradio/chatbot)
|
| 231 |
+
- [Agents and Tool Usage Guide](https://www.gradio.app/guides/agents-and-tool-usage)
|
| 232 |
+
- [GitHub Issue: Streaming text not working](https://github.com/gradio-app/gradio/issues/11443)
|
src/agents/magentic_agents.py
CHANGED
|
@@ -46,8 +46,7 @@ Be thorough - search multiple databases when appropriate.
|
|
| 46 |
Focus on finding: mechanisms of action, clinical evidence, and specific drug candidates.""",
|
| 47 |
chat_client=client,
|
| 48 |
tools=[search_pubmed, search_clinical_trials, search_preprints],
|
| 49 |
-
#
|
| 50 |
-
# which only support temperature=1
|
| 51 |
)
|
| 52 |
|
| 53 |
|
|
@@ -86,7 +85,7 @@ Be rigorous but fair. Look for:
|
|
| 86 |
- Safety data
|
| 87 |
- Drug-drug interactions""",
|
| 88 |
chat_client=client,
|
| 89 |
-
#
|
| 90 |
)
|
| 91 |
|
| 92 |
|
|
@@ -123,7 +122,7 @@ def create_hypothesis_agent(chat_client: OpenAIChatClient | None = None) -> Chat
|
|
| 123 |
|
| 124 |
Focus on mechanistic plausibility and existing evidence.""",
|
| 125 |
chat_client=client,
|
| 126 |
-
#
|
| 127 |
)
|
| 128 |
|
| 129 |
|
|
@@ -181,5 +180,5 @@ Format them as a numbered list.
|
|
| 181 |
Be comprehensive but concise. Cite evidence for all claims.""",
|
| 182 |
chat_client=client,
|
| 183 |
tools=[get_bibliography],
|
| 184 |
-
#
|
| 185 |
)
|
|
|
|
| 46 |
Focus on finding: mechanisms of action, clinical evidence, and specific drug candidates.""",
|
| 47 |
chat_client=client,
|
| 48 |
tools=[search_pubmed, search_clinical_trials, search_preprints],
|
| 49 |
+
temperature=1.0, # Explicitly set for reasoning model compatibility (o1/o3)
|
|
|
|
| 50 |
)
|
| 51 |
|
| 52 |
|
|
|
|
| 85 |
- Safety data
|
| 86 |
- Drug-drug interactions""",
|
| 87 |
chat_client=client,
|
| 88 |
+
temperature=1.0, # Explicitly set for reasoning model compatibility
|
| 89 |
)
|
| 90 |
|
| 91 |
|
|
|
|
| 122 |
|
| 123 |
Focus on mechanistic plausibility and existing evidence.""",
|
| 124 |
chat_client=client,
|
| 125 |
+
temperature=1.0, # Explicitly set for reasoning model compatibility
|
| 126 |
)
|
| 127 |
|
| 128 |
|
|
|
|
| 180 |
Be comprehensive but concise. Cite evidence for all claims.""",
|
| 181 |
chat_client=client,
|
| 182 |
tools=[get_bibliography],
|
| 183 |
+
temperature=1.0, # Explicitly set for reasoning model compatibility
|
| 184 |
)
|
src/app.py
CHANGED
|
@@ -247,15 +247,20 @@ def create_demo() -> tuple[gr.ChatInterface, gr.Accordion]:
|
|
| 247 |
[
|
| 248 |
"What drugs improve female libido post-menopause?",
|
| 249 |
"simple",
|
| 250 |
-
|
|
|
|
| 251 |
],
|
| 252 |
[
|
| 253 |
"Clinical trials for erectile dysfunction alternatives to PDE5 inhibitors?",
|
| 254 |
"advanced",
|
|
|
|
|
|
|
| 255 |
],
|
| 256 |
[
|
| 257 |
"Testosterone therapy for HSDD (Hypoactive Sexual Desire Disorder)?",
|
| 258 |
"simple",
|
|
|
|
|
|
|
| 259 |
],
|
| 260 |
],
|
| 261 |
additional_inputs_accordion=additional_inputs_accordion,
|
|
@@ -276,8 +281,8 @@ def create_demo() -> tuple[gr.ChatInterface, gr.Accordion]:
|
|
| 276 |
],
|
| 277 |
)
|
| 278 |
|
| 279 |
-
# API key persists because examples
|
| 280 |
-
#
|
| 281 |
|
| 282 |
return demo, additional_inputs_accordion
|
| 283 |
|
|
|
|
| 247 |
[
|
| 248 |
"What drugs improve female libido post-menopause?",
|
| 249 |
"simple",
|
| 250 |
+
None,
|
| 251 |
+
None,
|
| 252 |
],
|
| 253 |
[
|
| 254 |
"Clinical trials for erectile dysfunction alternatives to PDE5 inhibitors?",
|
| 255 |
"advanced",
|
| 256 |
+
None,
|
| 257 |
+
None,
|
| 258 |
],
|
| 259 |
[
|
| 260 |
"Testosterone therapy for HSDD (Hypoactive Sexual Desire Disorder)?",
|
| 261 |
"simple",
|
| 262 |
+
None,
|
| 263 |
+
None,
|
| 264 |
],
|
| 265 |
],
|
| 266 |
additional_inputs_accordion=additional_inputs_accordion,
|
|
|
|
| 281 |
],
|
| 282 |
)
|
| 283 |
|
| 284 |
+
# API key persists because examples include [message, mode, None, None].
|
| 285 |
+
# The explicit None values tell Gradio to NOT overwrite those inputs.
|
| 286 |
|
| 287 |
return demo, additional_inputs_accordion
|
| 288 |
|
src/orchestrator_magentic.py
CHANGED
|
@@ -156,6 +156,17 @@ Focus on:
|
|
| 156 |
|
| 157 |
The final output should be a structured research report."""
|
| 158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
iteration = 0
|
| 160 |
try:
|
| 161 |
async for event in workflow.run_stream(task):
|
|
|
|
| 156 |
|
| 157 |
The final output should be a structured research report."""
|
| 158 |
|
| 159 |
+
# UX FIX: Yield thinking state before blocking workflow call
|
| 160 |
+
# The workflow.run_stream() blocks for 2+ minutes on first LLM call
|
| 161 |
+
yield AgentEvent(
|
| 162 |
+
type="thinking",
|
| 163 |
+
message=(
|
| 164 |
+
"Multi-agent reasoning in progress... "
|
| 165 |
+
"This may take 2-5 minutes for complex queries."
|
| 166 |
+
),
|
| 167 |
+
iteration=0,
|
| 168 |
+
)
|
| 169 |
+
|
| 170 |
iteration = 0
|
| 171 |
try:
|
| 172 |
async for event in workflow.run_stream(task):
|
src/utils/models.py
CHANGED
|
@@ -106,6 +106,7 @@ class AgentEvent(BaseModel):
|
|
| 106 |
|
| 107 |
type: Literal[
|
| 108 |
"started",
|
|
|
|
| 109 |
"searching",
|
| 110 |
"search_complete",
|
| 111 |
"judging",
|
|
@@ -128,6 +129,7 @@ class AgentEvent(BaseModel):
|
|
| 128 |
"""Format event as markdown for chat display."""
|
| 129 |
icons = {
|
| 130 |
"started": "π",
|
|
|
|
| 131 |
"searching": "π",
|
| 132 |
"search_complete": "π",
|
| 133 |
"judging": "π§ ",
|
|
|
|
| 106 |
|
| 107 |
type: Literal[
|
| 108 |
"started",
|
| 109 |
+
"thinking", # Multi-agent reasoning in progress (before first event)
|
| 110 |
"searching",
|
| 111 |
"search_complete",
|
| 112 |
"judging",
|
|
|
|
| 129 |
"""Format event as markdown for chat display."""
|
| 130 |
icons = {
|
| 131 |
"started": "π",
|
| 132 |
+
"thinking": "β³", # Hourglass for thinking/waiting
|
| 133 |
"searching": "π",
|
| 134 |
"search_complete": "π",
|
| 135 |
"judging": "π§ ",
|