Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agent name termination #4123

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions python/packages/autogen-ext/src/autogen_ext/task/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from ._source_match_termination import SourceMatchTermination

__all__ = ["SourceMatchTermination"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from typing import Sequence, List

from autogen_agentchat.base import TerminationCondition, TerminatedException
from autogen_agentchat.messages import StopMessage, AgentMessage


class SourceMatchTermination(TerminationCondition):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry. I initially misunderstood the trigger. Since the trigger is the last source mentioned. I am wondering, if we don't need to limit to the last message's source. Any message that matches the source can trigger termination. The scenario I have in mind is that a summary agent finishes responding then the group chat terminates.

What's the scenario you have in mind for the trigger?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have the same senario. The only difference is allowing the user to start another conversation with the same chat history.
So, in my case, I need to check the last message, but not any message

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The termination condition is applied after the messages have been processed by the agent. So, the chat history is preserved.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, but if we have chat history from last conversation and then check any message that matches the source, conversation will alway terminate after 1 agent talking even if it's not the summary agent that we wanted. because the summary agent message existed in history

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The termination condition is invoked on the delta since the last time it was invoked rather than the whole history. So it won't see the same message twice.

Copy link
Author

@thainduy thainduy Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, so the messages: Sequence[AgentMessage] param in __call__ function is only come from the last agent and not entire group chat history right? in that case, yes, you was right, we can check any message match the source but i think it would make no difference since all message come from same agent? 🤔

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since all message come from same agent? 🤔

When the agents are not nesting another team inside, then yes. But an agent can contain a team, which will produce messages from multiple agents -- when that get sent to the parent team the termination condition will see multiple agents' messages

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you're right. Sorry, i missed the senario Nested chat. In that scenario, if we check any message to match the source, then this will allow terminate conversation when specific agents are involved in nested chat. Is that what you mean? I think that makes sense.

I can update this logic on the next commit if you want. Please let me know.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Let's change the logic to terminate whenever an agent source is matched.

this will allow terminate conversation when specific agents are involved in nested chat. Is that what you mean?

yes. just to keep it simple, the termination condition in the parent team will be applied on the flattened messages from all agents.

"""Terminate the conversation after a specific agent responds.

Args:
agents (List[str]): List of agent names to terminate the conversation.

Raises:
TerminatedException: If the termination condition has already been reached.
"""

def __init__(self, agents: List[str]) -> None:
ekzhu marked this conversation as resolved.
Show resolved Hide resolved
self._agents = agents
self._terminated = False

@property
def terminated(self) -> bool:
return self._terminated

async def __call__(self, messages: Sequence[AgentMessage]) -> StopMessage | None:
if self._terminated:
raise TerminatedException("Termination condition has already been reached")
if not messages:
return None
last_message = messages[-1]
if last_message.source in self._agents:
self._terminated = True
return StopMessage(content=f"Agent '{last_message.source}' answered", source="SourceMatchTermination")
return None

async def reset(self) -> None:
self._terminated = False
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import pytest

from autogen_agentchat.base import TerminatedException
from autogen_agentchat.messages import TextMessage, StopMessage
from autogen_ext.task import SourceMatchTermination


@pytest.mark.asyncio
async def test_agent_name_termination() -> None:
termination = SourceMatchTermination(agents=["Assistant"])
assert await termination([]) is None

continue_messages = [
TextMessage(content="Hello", source="Assistant"),
TextMessage(content="Hello", source="user")
]
assert await termination(continue_messages) is None

terminate_messages = [
TextMessage(content="Hello", source="user"),
TextMessage(content="Hello", source="Assistant")
]
result = await termination(terminate_messages)
assert isinstance(result, StopMessage)
assert termination.terminated
with pytest.raises(TerminatedException):
await termination([])
await termination.reset()
assert not termination.terminated