File size: 4,620 Bytes
67bdc5a
 
 
fd7948d
67bdc5a
 
 
 
fd7948d
67bdc5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fd7948d
 
 
 
67bdc5a
fd7948d
 
 
 
 
67bdc5a
fd7948d
 
67bdc5a
fd7948d
 
 
 
67bdc5a
fd7948d
 
 
 
 
 
67bdc5a
fd7948d
 
 
 
 
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
"""Test for AdvancedOrchestrator event processing (P1 Bug)."""

import pytest
from agent_framework import MagenticOrchestratorMessageEvent

from src.orchestrators.advanced import AdvancedOrchestrator


@pytest.mark.unit
class TestAdvancedEventProcessing:
    """Test event processing logic in AdvancedOrchestrator."""

    @pytest.fixture
    def orchestrator(self) -> AdvancedOrchestrator:
        """Create an orchestrator instance with mocks."""
        # Bypass __init__ logic that requires keys/env vars
        orch = AdvancedOrchestrator.__new__(AdvancedOrchestrator)
        # Minimal setup
        orch._max_rounds = 5
        orch._timeout_seconds = 300.0
        return orch

    def test_filters_internal_task_ledger_events(self, orchestrator: AdvancedOrchestrator) -> None:
        """
        Bug P1: Internal 'task_ledger' events should be filtered out.

        Current behavior: Returns AgentEvent(type='judging', message='Manager (task_ledger): ...')
        Desired behavior: Returns None (filtered)
        """
        # Create a raw internal framework event
        raw_event = MagenticOrchestratorMessageEvent(
            kind="task_ledger",
            message="We are working to address the following user request: Research sildenafil...",
        )

        # Process the event
        result = orchestrator._process_event(raw_event, iteration=1)

        # FAIL if the event is NOT filtered (i.e., if it returns an event)
        assert result is None, f"Should filter 'task_ledger' events, but got: {result}"

    def test_filters_internal_instruction_events(self, orchestrator: AdvancedOrchestrator) -> None:
        """
        Bug P1: Internal 'instruction' events should be filtered out.

        Current behavior: Returns AgentEvent(type='judging', message='Manager (instruction): ...')
        Desired behavior: Returns None (filtered)
        """
        raw_event = MagenticOrchestratorMessageEvent(
            kind="instruction", message="Conduct targeted searches on PubMed..."
        )

        result = orchestrator._process_event(raw_event, iteration=1)

        assert result is None, f"Should filter 'instruction' events, but got: {result}"

    def test_transforms_user_task_events(self, orchestrator: AdvancedOrchestrator) -> None:
        """
        Bug P1: 'user_task' events should be transformed to user-friendly messages.

        Current behavior: 'Manager (user_task): Research...' (truncated, type='judging')
        Desired behavior: 'Manager assigning research task...' (type='progress')
        """
        raw_event = MagenticOrchestratorMessageEvent(
            kind="user_task",
            message="Research sexual health and wellness interventions for: sildenafil mechanism",
        )

        result = orchestrator._process_event(raw_event, iteration=1)

        assert result is not None
        assert result.type == "progress"  # NOT "judging"
        assert "Manager assigning research task" in result.message
        # Should use the generic friendly message
        assert "sildenafil mechanism" not in result.message

    def test_prevents_mid_sentence_truncation(self, orchestrator: AdvancedOrchestrator) -> None:
        """
        Bug P1: Long messages should be smart-truncated at sentence boundaries.

        Tests _smart_truncate directly to ensure regression protection.
        The function truncates at sentence boundary if period is after halfway point.
        """
        # First sentence ends at position ~55, which is > 50 (100//2)
        long_text = (
            "This is a longer first sentence that ends past the midpoint. "
            "Second sentence continues with more text that would be cut."
        )

        # Call the helper directly to test its behavior explicitly
        truncated = orchestrator._smart_truncate(long_text, max_len=100)

        # Should truncate at the end of the first sentence (period > max_len//2)
        assert truncated.endswith("midpoint.")
        assert "Second sentence" not in truncated
        assert len(truncated) <= 100

    def test_smart_truncate_word_boundary_fallback(
        self, orchestrator: AdvancedOrchestrator
    ) -> None:
        """Test that truncation falls back to word boundary when no sentence end."""
        # No sentence ending in the first 80 chars
        long_text = "This is a very long text without any sentence ending in the limit"

        truncated = orchestrator._smart_truncate(long_text, max_len=50)

        # Should end with "..." and not cut mid-word
        assert truncated.endswith("...")
        assert len(truncated) <= 53  # 50 + "..."