File size: 8,780 Bytes
6062397 | 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 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | # User Experience
UX patterns for streaming, error handling, and traceability.
## Real-time Streaming
### Agent Progress Display
The UI shows agent activity in real-time using a Claude Code-inspired format:
```
β π― **Triage Agent**
βββ Geocoding Address("Broadway and 42nd")
β βΏ β Manhattan, NYC
β π **Research Agent**
βββ Looking Up City Records...
β βΏ RD-MN-0042, 3 complaints
βββ Checking Nearby Reports...
β βΏ 2 reports (1 open)
βββ Getting Weather...
β βΏ 45Β°F, Clear
β π **Report Agent**
βββ Getting Department Info...
β βΏ DOT (24-48h response)
βββ Generating PDF Report...
β βΏ π FMN-20251129 (12.5KB)
`8.3s`
```
**Implementation** (`app.py:222-277`):
```python
def build_inline_progress(agent_states: dict, elapsed: float,
thinking: str = "", tool_history: list = None) -> str:
"""Build multi-agent style progress display."""
lines = []
for tool in tool_history:
agent = tool.get("agent")
name = tool.get("display_name")
result = tool.get("result_summary", "")
# Agent header
if agent != current_agent:
lines.append(f"β {icon} **{agent_name}**")
# Tool call line
lines.append(f" βββ {name}...")
# Result line
if result:
lines.append(f" β βΏ {result}")
return "\n".join(lines)
```
### Event-Driven Updates
Events flow from agents to UI via generator:
```python
# In controller.py
for event_type, data in orchestrator.process(message, image_analysis):
if event_type == "tool_call":
# Update UI immediately
yield build_outputs()
elif event_type == "agent_done":
# Show completion
yield build_outputs()
elif event_type == "complete":
# Final response
yield build_outputs()
```
### Result Summarization
Tool results are summarized for display (`app.py:68-198`):
| Tool | Raw Output | Display Summary |
|------|------------|-----------------|
| `validate_address` | `{"is_valid_nyc": true, "borough": "Manhattan", ...}` | `β Manhattan` |
| `weather_get_current` | `{"temp_f": 45, "conditions": "Clear", ...}` | `45Β°F, Clear` |
| `get_nearby_reports` | `{"total_reports": 2, "open_reports": 1, ...}` | `2 reports (1 open)` |
| `pdf_generate_report` | `{"report_id": "FMN-...", "size_kb": 12.5, ...}` | `π FMN-... (12.5KB)` |
## Reasoning Trace
### Visible Thinking
The Reasoning Trace panel shows the agent's thought process:
```
**π§ Autonomous Reasoning Trace**
[0.0s] π Received infrastructure report request
[0.2s] π Delegating full control to Controller agent
[1.5s] π Controller delegated to Triage Agent
[2.3s] π§ Agent calling: Geocoding Address
[3.1s] ποΈ Tool result: {"is_valid_nyc": true...
[3.2s] β
Triage Agent completed (1.7s) [confidence: 0.85]
[3.3s] π Controller delegated to Research Agent
...
[8.0s] β
Presenting Controller's response to user [confidence: 0.92]
---
**Final Quality Score:** 8.7/10
```
**Implementation** (`agents/reasoning.py`):
```python
@dataclass
class ReasoningTrace:
thoughts: List[Dict[str, Any]] = field(default_factory=list)
def think(self, thought: str, category: str = "reasoning") -> None:
"""Record a thought."""
self.thoughts.append({
"type": "thought",
"category": category,
"content": thought,
"timestamp": time.time() - self.start_time,
})
def to_display(self) -> str:
"""Format for UI display."""
lines = []
for t in self.thoughts:
icon = {"thought": "π", "decision": "β
", "observation": "ποΈ"}
lines.append(f"[{t['timestamp']:.1f}s] {icon} {t['content']}")
return "\n".join(lines)
```
### Self-Evaluation Display
Quality scores shown after completion:
```python
# In controller.py
quality_score = self._evaluate_response_quality(response, agent_states, trace)
# In app.py
if quality_score is not None:
current_reasoning += f"\n\n**Final Quality Score:** {quality_score * 10:.1f}/10"
```
## Error Handling
### Friendly Error Messages
Technical errors are mapped to user-friendly messages:
| Error Type | User Sees |
|------------|-----------|
| Rate limit | "You're sending requests too quickly. Please wait 30 seconds." |
| API timeout | "We're having trouble connecting. Please try again." |
| Invalid input | "Please provide a valid NYC address." |
| MCP server down | "The infrastructure tools server is temporarily unavailable." |
**Implementation** (`security/error_handler.py`):
```python
class ErrorHandler:
def handle(self, error: Exception, context: str = "") -> FriendlyError:
if isinstance(error, RateLimitExceeded):
return FriendlyError(
message="You're sending requests too quickly.",
suggestion=f"Please wait {error.wait_seconds} seconds.",
is_recoverable=True,
)
```
### Graceful Degradation
If services are unavailable:
```python
# MCP server check
mcp_available, mcp_error = self._check_mcp_server()
if not mcp_available:
yield ("needs_info", {
"message": "β οΈ **Service Temporarily Unavailable**\n\n"
"The NYC infrastructure tools server is offline.\n\n"
"Please wait a moment and try again."
})
return
```
### Input Validation Feedback
Clear feedback for invalid input:
```python
if not validation_result.is_valid:
error_msg = validation_result.get_friendly_message()
# "Please provide a description of the infrastructure issue."
# "Your message is too long. Please limit to 5000 characters."
```
## Multi-turn Conversation
### Context Awareness
The Controller sees full conversation history:
```python
# In prompts.py
CONVERSATION HISTORY (you have full context):
User: pothole on my street
Agent: I'd be happy to help! To file a report, I need the street address...
User: Broadway and 42nd St
```
### Follow-up Questions
Controller asks for missing information naturally:
```
User: "There's a pothole"
Agent: "I'd be happy to help you report that pothole! To file an accurate
report with NYC DOT, I need a bit more information:
**What's the street address?** (e.g., "Broadway and 42nd St" or
"123 Main Street, Brooklyn")
Once you provide the location, I can look up the city records and
generate an official report."
```
## Map Integration
### Real-time Location Updates
Map updates as soon as location is validated:
```python
elif event_type == "location_update":
lat = data.get("lat")
lon = data.get("lon")
if lat and lon:
current_map = create_issue_map(
lat=lat,
lon=lon,
borough=data.get("borough"),
address=data.get("address")
)
yield build_outputs()
```
### Folium Map Display
Interactive map with issue marker:
```python
# In ui/mapping.py
def create_issue_map(lat, lon, borough, address):
m = folium.Map(location=[lat, lon], zoom_start=15)
folium.Marker(
[lat, lon],
popup=f"{address}<br><b>{borough}</b>",
icon=folium.Icon(color="red", icon="exclamation-sign")
).add_to(m)
folium.Circle(
[lat, lon],
radius=50,
color="red",
fill=True,
).add_to(m)
return m._repr_html_()
```
## Agent Pipeline Display
### Status Cards
Each agent has a status card showing:
```
π **Research Agent** β
3.2s
*Classifies issue & gathers location data*
- β
Looking Up City Records (1.2s)
- β
Checking Nearby Reports (0.8s)
- β
Getting Weather (1.1s)
```
### Completion Summary
Final response includes execution summary:
```
**π€ Agent Execution**
β π― **Triage Agent**
ββ Geocoding Address β β Broadway & 42nd, Manhattan
β π **Research Agent**
ββ Looking Up City Records β RD-MN-0042, 3 complaints
ββ Checking Nearby Reports β 2 reports (1 open)
ββ Getting Weather β 45Β°F, Clear
β π **Report Agent**
ββ Getting Department Info β DOT (24-48h response)
ββ Generating PDF Report β π FMN-20251129
*Completed in 8.3s*
---
## Infrastructure Report
**Report ID:** FMN-20251129-001
**Issue Type:** Pothole
**Location:** Broadway & 42nd St, Manhattan
...
```
## Accessibility
### Clear Visual Hierarchy
- Agent names in **bold**
- Tool calls with tree-style indentation
- Results with checkmarks/icons
- Timing in subtle `code` format
### Status Icons
| Icon | Meaning |
|------|---------|
| β | Pending |
| β³ | Running |
| β
| Completed |
| β | Error |
| π | PDF generated |
| βοΈ | Email sent |
|