KEMBAR78
fix:Prevent Async Event Loop from Running Indefinitely by wfge · Pull Request #6530 · microsoft/autogen · GitHub
Skip to content

Conversation

@wfge
Copy link
Contributor

@wfge wfge commented May 14, 2025

Why are these changes needed?

Prevent Async Event Loop from Running Indefinitely

Description

This pull request addresses a bug in the python/packages/autogen-core/src/autogen_core/_single_threaded_agent_runtime.py async send_message function where messages were being queued for recipients that were not recognized. The current implementation sets an exception on the future object when the recipient is not found, but continues to enqueue the message, potentially leading to inconsistent states.

Changes Made

  • Added a return statement immediately after setting the exception when the recipient is not found. This ensures that the function exits early, preventing further processing of the message and avoiding unnecessary operations.
  • This fix also addresses an issue where the asynchronous event loop could potentially continue running indefinitely without terminating, due to the future not being properly handled when an unknown recipient is encountered.

Impact

This fix prevents messages from being sent to unknown recipients. It also ensures that the event loop can terminate correctly without being stuck in an indefinite state.

Testing

Ensure that the function correctly handles cases where the recipient is not recognized by returning the exception without enqueuing the message, and verify that the event loop terminates as expected.

Related issue number

Checks

@ekzhu ekzhu requested a review from jackgerrits May 16, 2025 00:07
@wfge
Copy link
Contributor Author

wfge commented May 16, 2025

from __future__ import annotations

import uuid
import asyncio
from pydantic import BaseModel
from typing import List

from autogen_core import (
    SingleThreadedAgentRuntime,
    TypeSubscription,
)
from autogen_core.models import AssistantMessage, LLMMessage
from autogen_core import (
    MessageContext,
    RoutedAgent,
    TopicId,
    AgentId,
    message_handler,
)


INTERACTION_AGENT_TOPIC_TYPE = 'INTERACTION_AGENT_TOPIC_TYPE'


class OutputMessage(BaseModel):
    source: str
    context: List[LLMMessage]


class InteractionAgent(RoutedAgent):
    def __init__(self,
                 description):
        super(InteractionAgent, self).__init__(description=description)

    @message_handler
    async def handle_input(self, message: OutputMessage, ctx: MessageContext) -> None:
        """
        处理规划型任务
        Returns:

        """

        user_input = "test_task"
        publish_msg = message
        await self.send_message(publish_msg, recipient=AgentId('not_exists_agent_name', 'Test'))


def interaction_agent_factory() -> InteractionAgent:
    return InteractionAgent(
        description='A agent to be used to interact with human',
    )


async def main():

    runtime = SingleThreadedAgentRuntime()

    interaction_agent_type = await InteractionAgent.register(runtime=runtime, type=INTERACTION_AGENT_TOPIC_TYPE,
                                                             factory=interaction_agent_factory)

    await runtime.add_subscription(
        TypeSubscription(topic_type=INTERACTION_AGENT_TOPIC_TYPE, agent_type=interaction_agent_type))

    runtime.start()
    session_id = str(uuid.uuid4())

    start_msg = AssistantMessage(content='Hello, how can i help you.', source='assistant')
    start_message = OutputMessage(source='system',
                                  context=[start_msg])

    await runtime.publish_message(start_message, topic_id=TopicId(INTERACTION_AGENT_TOPIC_TYPE, source=session_id))
    await runtime.stop_when_idle()
    await runtime.close()

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

    # loop = asyncio.get_event_loop()
    #
    # loop.run_until_complete(main())

Here is a minimal example to reproduce the bug.

And I believe this bug only occurs when the send_message function is used internally within the Agent.

The following image shows the program's output, where the asynchronous event loop never terminates.
image

@jackgerrits jackgerrits enabled auto-merge (squash) May 20, 2025 20:23
@jackgerrits jackgerrits merged commit ec45dca into microsoft:main May 20, 2025
63 checks passed
@codecov
Copy link

codecov bot commented May 20, 2025

Codecov Report

Attention: Patch coverage is 0% with 1 line in your changes missing coverage. Please review.

Project coverage is 79.52%. Comparing base (f0b7344) to head (253001b).
Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
...src/autogen_core/_single_threaded_agent_runtime.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6530      +/-   ##
==========================================
- Coverage   79.52%   79.52%   -0.01%     
==========================================
  Files         225      225              
  Lines       16623    16624       +1     
==========================================
  Hits        13220    13220              
- Misses       3403     3404       +1     
Flag Coverage Δ
unittests 79.52% <0.00%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants