Repository: microsoft/autogen
Pull request: Add sources field to TextMentionTermination
<!-- Thank you for your contribution! Please review https://microsoft.github.io/autogen/docs/Contribute before opening a pull request. -->

<!-- Please add a reviewer to the assignee section when you create a PR. If you don't have the access to it, we will shortly find a reviewer and assign them to your PR. -->

## Why are these changes needed?

See #4807. In many practical scenarios, we only want to stop a dialog, when a specific agent says something e.g. not stop when the keyword is part of the prompt for instance. This PR allows this by adding a list of sources, where a user can specify the agent names.

<!-- Please give a short summary of the change and the problem this solves. -->

## Related issue number

Closes  #4807

## Checks

- [ ] I've included any doc changes needed for https://microsoft.github.io/autogen/. See https://microsoft.github.io/autogen/docs/Contribute#documentation to build and test documentation locally.
- [ ] I've added tests (if relevant) corresponding to the changes introduced in this PR.
- [ ] I've made sure all auto checks have passed.


Problem statement:
Stop Conditions for specific agents only
### What feature would you like to be added?

It would be nice if `TextMentionTermination("...")` in v4 could be defined for specific agents i.e. it should only stop if the specific agent sends / receives (tbd) the mentioned text.

### Why is this needed?

More often than not the prompt contains instructions for the agent how it can stop the agent. The TextMentionTermination is currently triggered by the prompt already, which is not the intention. While a straightforward solution would be ignoring the prompt, I would suggest something more flexible, where one can specify the agent(s) that needs to send the stop condition.

Hints from issue discussion:
Usually the prompt is set in system message so it won't show up in the message stream. Though I agree adding an `source` field can be useful for allowing only one agent to trigger the termination. 

Happy to accept a PR for this. 
Really? I heard that system message is mostly used for generic instructions. But for instance few shot examples are part of the prompt. I couldn't find official information of openai for this though. In my experiments both seems to work okay.

Depending on how you are using the agent I guess. A system message can contain instruction regarding termination -- it has been used a lot in the past in many AutoGen examples. 
I will probably do a PR once my other stuff is merged, but if someone already needs it:
```py
class TextMentionTermination(TerminationCondition):
    def __init__(self, text: str, sources: list[str] | None = None) -> None:
        self._text = text
        self._terminated = False
        self._sources = sources

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

    async def __call__(self, messages: list[AgentMessage]) -> StopMessage | None:
        if self._terminated:
            raise TerminatedException("Termination condition has already been reached")
        for message in messages:
            if self._sources is not None and message.source not in self._sources:
                continue

            if isinstance(message, TextMessage | StopMessage) and self._text in message.content:
                self._terminated = True
                return StopMessage(content=f"Text '{self._text}' mentioned", source="TextMentionTermination")
            elif isinstance(message, MultiModalMessage):
                for item in message.content:
                    if isinstance(item, str) and self._text in item:
                        self._terminated = True
                        return StopMessage(content=f"Text '{self._text}' mentioned", source="TextMentionTermination")
        return None

    async def reset(self) -> None:
        self._terminated = False
```

Commit message: Add sources field to TextMentionTermination

Patch to review:
diff --git a/python/packages/autogen-agentchat/src/autogen_agentchat/conditions/_terminations.py b/python/packages/autogen-agentchat/src/autogen_agentchat/conditions/_terminations.py
index e33f2fcb70a7..4f8fd82644ee 100644
--- a/python/packages/autogen-agentchat/src/autogen_agentchat/conditions/_terminations.py
+++ b/python/packages/autogen-agentchat/src/autogen_agentchat/conditions/_terminations.py
@@ -100,14 +100,16 @@ class TextMentionTermination(TerminationCondition, Component[TextMentionTerminat
 
     Args:
         text: The text to look for in the messages.
+        sources: Check only messages of the specified agents for the text to look for.
     """
 
     component_config_schema = TextMentionTerminationConfig
     component_provider_override = "autogen_agentchat.conditions.TextMentionTermination"
 
-    def __init__(self, text: str) -> None:
+    def __init__(self, text: str, sources: list[str] | None = None) -> None:
         self._text = text
         self._terminated = False
+        self._sources = sources
 
     @property
     def terminated(self) -> bool:
@@ -117,6 +119,9 @@ async def __call__(self, messages: Sequence[AgentEvent | ChatMessage]) -> StopMe
         if self._terminated:
             raise TerminatedException("Termination condition has already been reached")
         for message in messages:
+            if self._sources is not None and message.source not in self._sources:
+                continue
+
             if isinstance(message.content, str) and self._text in message.content:
                 self._terminated = True
                 return StopMessage(content=f"Text '{self._text}' mentioned", source="TextMentionTermination")


Code review comments:
diff_hunk: @@ -100,14 +100,16 @@ class TextMentionTermination(TerminationCondition, Component[TextMentionTerminat
 
     Args:
         text: The text to look for in the messages.
+        sources: Check only messages of the specified agents for the text to look for.
     """
 
     component_config_schema = TextMentionTerminationConfig
     component_provider_override = "autogen_agentchat.conditions.TextMentionTermination"
 
-    def __init__(self, text: str) -> None:
+    def __init__(self, text: str, sources: list[str] | None = None) -> None:
path: python/packages/autogen-agentchat/src/autogen_agentchat/conditions/_terminations.py
text: @user1:
Nit: use Sequence type hint.