DeepBoner / docs /bugs /archive /P0_REPR_BUG_ROOT_CAUSE_ANALYSIS.md
VibecoderMcSwaggins's picture
docs: Organize and archive resolved bug documentation
f9f62d4
|
raw
history blame
3.51 kB

P0: Event Handling Implementation Spec

Status: FIXED Priority: P0 Source of Truth: reference_repos/microsoft-agent-framework/python/samples/autogen-migration/orchestrations/04_magentic_one.py


Root Cause (One Sentence)

We were extracting content from MagenticAgentMessageEvent.message β€” the wrong event type β€” instead of using MagenticAgentDeltaEvent.text as the sole source of streaming content.


The Fix: Correct Event Handling Per Microsoft SSOT

Event Type Correct Usage What We Were Doing (Wrong)
MagenticAgentDeltaEvent Extract .text - This is the ONLY source of content Partially used, not accumulated
MagenticAgentMessageEvent Signal only - Agent turn complete. IGNORE .message Extracting .message.text (hits repr bug)
MagenticFinalResultEvent Extract .message.text - Final synthesis result Correct

Implementation: Accumulator Pattern

From Microsoft's 04_magentic_one.py (lines 108-138):

# Microsoft's Pattern
async for event in workflow.run_stream(task):
    if isinstance(event, MagenticAgentDeltaEvent):
        # STREAM CONTENT: Accumulate and display
        if event.text:
            print(event.text, end="", flush=True)

    elif isinstance(event, MagenticAgentMessageEvent):
        # SIGNAL ONLY: Agent done. Print newline. DO NOT read .message
        print()

    elif isinstance(event, MagenticFinalResultEvent):
        # FINAL RESULT: Safe to read .message.text
        print(event.message.text)

Our Implementation (src/orchestrators/advanced.py)

Status: βœ… IMPLEMENTED (lines 241-308)

# 1. Accumulate streaming content (ONLY source of truth)
if isinstance(event, MagenticAgentDeltaEvent):
    if event.text:
        current_message_buffer += event.text
        yield AgentEvent(type="streaming", message=event.text, ...)

# 2. Use buffer on completion signal (IGNORE event.message)
if isinstance(event, MagenticAgentMessageEvent):
    text_content = current_message_buffer or "Action completed (Tool Call)"
    yield AgentEvent(message=f"{agent_name}: {text_content[:200]}...", ...)
    current_message_buffer = ""  # Reset for next agent

# 3. Final result - safe to extract
if isinstance(event, MagenticFinalResultEvent):
    text = self._extract_text(event.message)
    yield AgentEvent(type="complete", message=text, ...)

Why This Eliminates the Repr Bug

The repr bug occurs at _magentic.py:1730:

text = last.text or str(last)  # Falls back to repr() for tool-only messages

By never reading MagenticAgentMessageEvent.message.text, we never hit this code path.

The repr bug is eliminated by correct implementation β€” no upstream fix required.


Verification Checklist

  • MagenticAgentDeltaEvent.text used as sole content source
  • MagenticAgentMessageEvent used as signal only (buffer consumed, not .message)
  • MagenticFinalResultEvent.message.text extracted for final result
  • Buffer reset on agent switch and completion
  • Remove dead code path in _process_event() that still calls _extract_text on MagenticAgentMessageEvent

Remaining Cleanup

βœ… DONE - Dead code paths for MagenticAgentMessageEvent and MagenticAgentDeltaEvent have been removed from _process_event(). Comments now explain these events are handled by the Accumulator Pattern in run().