Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -152,19 +152,20 @@ def produced_message_types(self) -> Sequence[type[BaseChatMessage]]:
return self._wrapped_agent.produced_message_types

def _apply_filter(self, messages: Sequence[BaseChatMessage]) -> Sequence[BaseChatMessage]:
result: List[BaseChatMessage] = []
selected: set[int] = set()

for source_filter in self._filter.per_source:
msgs = [m for m in messages if m.source == source_filter.source]
indexed = [(i, m) for i, m in enumerate(messages) if m.source == source_filter.source]

if source_filter.position == "first" and source_filter.count:
msgs = msgs[: source_filter.count]
indexed = indexed[: source_filter.count]
elif source_filter.position == "last" and source_filter.count:
msgs = msgs[-source_filter.count :]
indexed = indexed[-source_filter.count :]

result.extend(msgs)
for i, _ in indexed:
selected.add(i)

return result
return [m for i, m in enumerate(messages) if i in selected]

async def on_messages(
self,
Expand Down
31 changes: 31 additions & 0 deletions python/packages/autogen-agentchat/tests/test_group_chat_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,37 @@ async def test_message_filter_agent_with_position_none_gets_all() -> None:
assert {m.content for m in inner_agent.received_messages} == {"A", "B"} # type: ignore[attr-defined]


@pytest.mark.asyncio
async def test_message_filter_agent_preserves_chronological_order() -> None:
"""Regression #7971: filtered messages must arrive in original chronological order.

When per_source lists 'A' before 'user', the result must still be ordered by
each message's position in the original conversation, not by filter-config order.
"""
inner_agent = _TestMessageFilterAgent("inner")
wrapper = MessageFilterAgent(
name="wrapper",
wrapped_agent=inner_agent,
filter=MessageFilterConfig(
per_source=[
PerSourceFilter(source="A", position="last", count=1),
PerSourceFilter(source="user", position="first", count=1),
]
),
)
messages = [
TextMessage(source="user", content="user-first"),
TextMessage(source="A", content="A-first"),
TextMessage(source="A", content="A-second"),
]
await wrapper.on_messages(messages, CancellationToken())
received = inner_agent.received_messages
assert len(received) == 2
# user message came first in the original list, so it must arrive first
assert received[0].content == "user-first" # type: ignore[attr-defined]
assert received[1].content == "A-second" # type: ignore[attr-defined]


@pytest.mark.asyncio
async def test_digraph_group_chat() -> None:
inner_agent = _TestMessageFilterAgent("agent")
Expand Down