autogen icon indicating copy to clipboard operation
autogen copied to clipboard

TextMentionTermination terminating team on initial user message

Open jcroucherMSFT opened this issue 6 months ago • 3 comments

What happened?

Describe the bug I asked two agents the same question where they had differing responses. I wanted both of them to discuss their viewpoints in a team and use TextMentionTermination once consensus had been reached. When initiating the team, my "user" message instructing the agents to discuss their views (which included instructions for using the TextMentionTermination phrase), but instead immediately ended the team because stop_reason="Text 'END_FEEDBACK_DISCUSSION' mentioned". the termination condition is TextMentionTermination("END_FEEDBACK_DISCUSSION")

I rewrote the team task prompt to not include the TextMentionTermination phrase and instead explained the phrase without using it verbatim within the prompt. This worked, but does not seem intuitive.

Surely I should be allowed to include the TextMentionTermination phrase within the initial user task to the team without it triggering an early exit?

To Reproduce

  1. Create two agents using AssistantAgent.
  2. Create a RoundRobinGroupChat and include both agents with the termination_condition set to the TextMentionTermination phrase.
  3. Ask both agents an opinionated question using agent.run(task=question) individually.
  4. Start a team discussion about their differences of opinion and ask them to include the TextMentionTermination phrase once they have reached consensus.

output = asyncio.run(Console(team.run_stream(task=prompts.ExtractContent.start_feedback_loop))) output TaskResult(messages=[TextMessage(id='9eca0ceb-1145-4571-91ef-7037a5ab9792', source='user', models_usage=None, metadata={}, created_at=datetime.datetime(2025, 7, 17, 10, 27, 45, 789119, tzinfo=datetime.timezone.utc), content='You both have differing opinions and responses on the question asked to you previously. **SHORTENED FOR BREVIETY**end the discussion by including the termination phrase in their response, which is: END_FEEDBACK_DISCUSSION\n\nPlease now start by explaining your reasoning for your previous response.', type='TextMessage')], stop_reason="Text 'END_FEEDBACK_DISCUSSION' mentioned")

When updating the team task prompt with END-FEEDBACK-DISCUSSION but change the hyphens to underscores, the agents discuss and correctly interpret the termination condition instructions.

Expected behavior I would like the presents of the TextMentionTermination phrase to not satisfy the termination condition when it's included within the original task to the team.

Which packages was the bug in?

Python AgentChat (autogen-agentchat>=0.4.0)

AutoGen library version.

Python 0.6.2

Other library version.

No response

Model used

o3 and gpt4.1

Model provider

Azure OpenAI

Other model provider

No response

Python version

3.12

.NET version

None

Operating system

Windows

jcroucherMSFT avatar Jul 17 '25 11:07 jcroucherMSFT

I've encountered the same issue. When setting a breakpoint in the __call__ function of TextMentionTermination, I observed that messages contains entries like:
ThoughtEvent(id='ec1de7e4-ad2d-4f5c-afca-56ba4dce99e0', ..., type='ThoughtEvent').

This occurs because both handle_start and handle_agent_response in BaseGroupChatManager invoke self._apply_termination_condition → self._termination_condition(), and the message stream naturally includes both start messages and thought events.

I'm unsure whether TextMentionTermination should remain unchanged. As a workaround, I can subclass it like this:

class TextMentionTerminationCritical(TextMentionTermination):
    async def __call__(self, messages: Sequence[BaseAgentEvent | BaseChatMessage]) -> StopMessage | None:
        messages_filter = [m for m in messages if isinstance(m, TextMessage)]
        return await super().__call__(messages=messages_filter)

Usage:
TextMentionTerminationCritical(text='APPROVE', sources=[critical.name])
(Here sources restricts checks to the specified critical agent)

gwlwmm avatar Jul 28 '25 03:07 gwlwmm

Perhaps documentation and examples shall be updated? Or I am using Autogen outside specified design? Not sureif it is formally correct, but my assumption is that there is no need for Planning Agent, while I believe planning itself can be handled by selector_prompt of SelectorGroupChat. Text termination is instructed to summary agent via system prompt. Following is the code example that works for me using selfhosted gpt-oss 20b via ollama.cpp.

import asyncio
from typing import Sequence
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.teams import SelectorGroupChat
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.ui import Console
from autogen_core.models import ModelFamily
from autogen_ext.code_executors.local import LocalCommandLineCodeExecutor
from autogen_ext.tools.code_execution import PythonCodeExecutionTool


async def main():
    llm_client = OpenAIChatCompletionClient(
            model="gpt-oss",
            base_url="http://localhost:11434/v1",
            api_key="placeholder",
            model_info={
                "vision": False,
                "function_calling": True,
                "json_output": False,
                "family": ModelFamily.O4,
                "structured_output": True,
            },
        )
    
    # summary agent
    summary_agent = AssistantAgent(
        name="SummaryAgent",
        description="An agent responsible for summarizing the findings of the analysis and code execution. Executed as last and only once, after all other agents have completed their tasks.",
        model_client=llm_client,
        system_message="""
        Reasoning: Low.
        You are a summary agent.
        Your job is to summarize the findings from the data analysis and code execution and end with "TASK_COMPLETE".
        """
    )

    # data analyst agent
    data_analyst = AssistantAgent(
        name="DataAnalyst",
        description="An agent performing data analysis, plans calculations and suggests code to run",
        model_client=llm_client,
        system_message="""
        Reasoning: Low.
        You are a data analyst. 
        - Analyze data, plan calculations, and suggest plain python code to run, no Jupyter.
        - If you need code execution, ask @PythonExecutor explicitly.
        """
    )

    #python code executor agent
    code_executor = PythonCodeExecutionTool(LocalCommandLineCodeExecutor(work_dir="coding"))
    python_executor = AssistantAgent(
        name="PythonExecutor",
        description="An agent executing provided Python code, returning output, and attempting to fix code errors and re-execute if necessary.",
        model_client=llm_client,
        tools=[code_executor],
        system_message="""
        Reasoning: Medium.
        You are a Python executor. 
        - Run the provided Python code and return the output.
        - If execution fails because of code error, try to fix and execute again.
        """
    )

    #termination conditions 
    termination = TextMentionTermination("TASK_COMPLETE")
    # team - Coordinator acts as selector
    selector_prompt = """
    You are the coordinator agent.
    Available agents:
    {participants}

    Roles:
    {roles}

    Read the conversation history {history}
    Your job is to select the most appropriate agent to handle the next task based on their roles and expertise.
    Selection criteria:
    - Expertise in the task domain
    - Availability and workload
    - Select one agent.
    - Avoid selecting the same agent multiple times in a row.
    Do not perform any actions outside of selecting an agent.
    
    """

    team = SelectorGroupChat(
        participants=[data_analyst, python_executor, summary_agent],
        model_client=llm_client,
        termination_condition=termination,
        selector_prompt=selector_prompt,
    )

    await Console(team.run_stream(
        task="""
        1. Generate a dummy random dataset with columns: product, price, quantity, Month for year 2024
        2. Compute revenue stats
        3. plot a simple bar chart. provide file name.
        4. summarize company performance for executive management.
        """
    ))

if __name__ == "__main__":
    asyncio.run(main())

janantos avatar Sep 01 '25 16:09 janantos

We recommend you to create your own class of termination conditions to help working with your scenarios. No need to limit to builtin conditions

ekzhu avatar Sep 16 '25 07:09 ekzhu