File size: 4,954 Bytes
d36ce3c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# P3 Bug Report: Advanced Mode Missing Termination Guarantee

## Status
- **Date:** 2025-11-29
- **Priority:** P3 (Edge case, but confusing UX)
- **Component:** `src/orchestrator_magentic.py`
- **Resolution:** Fixed (Guarantee termination event)

---

## Symptoms

In **Advanced (Magentic) mode** with OpenAI API key:

1. Workflow runs for many iterations (up to 10 rounds)
2. Agents search, judge, hypothesize repeatedly
3. Eventually... **nothing happens**
   - No "complete" event
   - No error message
   - UI just stops updating

**User perception:** "Did it finish? Did it crash? What happened?"

### Observed Behavior

When workflow hits `max_round_count=10`:
- `workflow.run_stream(task)` iterator ends
- NO `MagenticFinalResultEvent` is emitted by agent-framework
- Our code yields nothing after the loop
- User is left hanging

---

## Root Cause Analysis

### Code Path (`src/orchestrator_magentic.py:170-186`)

```python
iteration = 0
try:
    async for event in workflow.run_stream(task):
        agent_event = self._process_event(event, iteration)
        if agent_event:
            if isinstance(event, MagenticAgentMessageEvent):
                iteration += 1
            yield agent_event
    # BUG: NO FALLBACK HERE!
    # If loop ends without FinalResultEvent, user sees nothing

except Exception as e:
    logger.error("Magentic workflow failed", error=str(e))
    yield AgentEvent(
        type="error",
        message=f"Workflow error: {e!s}",
        iteration=iteration,
    )
# BUG: NO FINALLY BLOCK TO GUARANTEE TERMINATION EVENT
```

### Workflow Configuration (`src/orchestrator_magentic.py:110-116`)

```python
.with_standard_manager(
    chat_client=manager_client,
    max_round_count=self._max_rounds,  # 10 - can hit this limit
    max_stall_count=3,                  # If agents repeat 3x
    max_reset_count=2,                  # Workflow reset limit
)
```

### Failure Modes

| Scenario | What Happens | User Sees |
|----------|--------------|-----------|
| `MagenticFinalResultEvent` emitted | `_process_event` yields "complete" | Final report |
| Max rounds (10) reached, no final event | Loop ends silently | **Nothing** |
| `max_stall_count` triggered | Workflow ends | **Nothing** |
| `max_reset_count` triggered | Workflow ends | **Nothing** |
| OpenAI API error | Exception caught | Error message |

---

## The Fix

Add guaranteed termination event after the loop:

```python
iteration = 0
final_event_received = False

try:
    async for event in workflow.run_stream(task):
        agent_event = self._process_event(event, iteration)
        if agent_event:
            if isinstance(event, MagenticAgentMessageEvent):
                iteration += 1
            if agent_event.type == "complete":
                final_event_received = True
            yield agent_event

except Exception as e:
    logger.error("Magentic workflow failed", error=str(e))
    yield AgentEvent(
        type="error",
        message=f"Workflow error: {e!s}",
        iteration=iteration,
    )
    final_event_received = True  # Error is a form of termination

finally:
    # GUARANTEE: Always emit termination event
    if not final_event_received:
        logger.warning(
            "Workflow ended without final event",
            iterations=iteration,
        )
        yield AgentEvent(
            type="complete",
            message=(
                f"Research completed after {iteration} agent rounds. "
                "Max iterations reached - results may be partial. "
                "Try a more specific query for better results."
            ),
            data={"iterations": iteration, "reason": "max_rounds_reached"},
            iteration=iteration,
        )
```

---

## Alternative: Increase Max Rounds

The default `max_rounds=10` might be too low for complex queries.

In `src/orchestrator_factory.py:52-53`:
```python
return orchestrator_cls(
    max_rounds=config.max_iterations if config else 10,  # Could increase to 15-20
    api_key=api_key,
)
```

**Trade-off:** More rounds = more API cost, but better chance of complete results.

---

## Test Plan

- [ ] Add fallback yield after async for loop
- [ ] Add `final_event_received` flag tracking
- [ ] Log warning when fallback is used
- [ ] Test with `max_rounds=2` to force hitting limit
- [ ] Verify user always sees termination event
- [ ] `make check` passes

---

## Related Files

- `src/orchestrator_magentic.py` - Main fix location
- `src/orchestrator_factory.py` - Max rounds configuration
- `src/utils/models.py` - AgentEvent types
- `docs/bugs/P2_MAGENTIC_THINKING_STATE.md` - Related UX issue (implemented)

---

## Priority Justification

**P3** because:
- Advanced mode is working for most queries
- Only hits edge case when max rounds reached without synthesis
- User CAN retry with different query
- Not blocking hackathon demo (free tier Simple mode works)

Would be P2 if:
- This happened frequently
- No workaround existed