fix(runtime): enforce main event loop ownership (#6424)

This commit is contained in:
InfinityPacer
2026-08-23 20:14:31 +08:00
committed by GitHub
parent c72b4fe88e
commit 1d2984b95f
14 changed files with 181 additions and 55 deletions
+28 -7
View File
@@ -11,7 +11,7 @@ from app.agent.tools.impl.ask_user_choice import (
)
from app.agent.tools.impl.send_message import SendMessageTool
from app.chain.message import MessageChain
from app.runtime.config import settings
from app.runtime.config import global_vars, settings
from app.db import SessionFactory
from app.db.oper.message import MessageOper
from app.db.models.message import Message
@@ -28,6 +28,13 @@ def _clear_messages() -> None:
db.commit()
def _running_loop_stub() -> Mock:
"""提供满足主程序生命周期合同的事件循环替身。"""
return Mock(
**{"is_running.return_value": True, "is_closed.return_value": False}
)
def test_explicit_ai_message_bypasses_pending_media_interaction():
"""显式 /ai 消息应绕过误触发的媒体交互状态并回到 Agent 会话。"""
chain = MessageChain()
@@ -69,7 +76,9 @@ def test_explicit_ai_message_is_not_recorded_to_message_history():
chain.runtime_config = replace(chain.runtime_config, ai_agent_enable=True)
manager = Mock(process_message=AsyncMock())
with patch.object(settings, "AI_AGENT_ENABLE", True), patch.object(
with patch.object(
global_vars, "CURRENT_EVENT_LOOP", _running_loop_stub()
), patch.object(settings, "AI_AGENT_ENABLE", True), patch.object(
chain, "_record_user_message"
) as record_user_message, patch(
"app.chain.message.get_running_agent_manager", return_value=manager
@@ -101,7 +110,11 @@ def test_agent_queue_full_is_reported_to_the_originating_channel():
coro.close()
return failed
with patch.object(settings, "AI_AGENT_ENABLE", True), patch(
with patch.object(
global_vars, "CURRENT_EVENT_LOOP", _running_loop_stub()
), patch.object(
settings, "AI_AGENT_ENABLE", True
), patch(
"app.chain.message.get_running_agent_manager", return_value=manager
), patch(
"app.chain.message.asyncio.run_coroutine_threadsafe",
@@ -127,7 +140,9 @@ def test_message_chain_passes_stable_channel_admin_principal_to_agent():
chain.runtime_config = replace(chain.runtime_config, ai_agent_enable=True)
manager = Mock(process_message=AsyncMock())
with patch.object(settings, "AI_AGENT_ENABLE", True), patch(
with patch.object(
global_vars, "CURRENT_EVENT_LOOP", _running_loop_stub()
), patch.object(settings, "AI_AGENT_ENABLE", True), patch(
"app.chain.message.get_running_agent_manager", return_value=manager
), patch(
"app.chain.message.asyncio.run_coroutine_threadsafe",
@@ -151,7 +166,9 @@ def test_message_chain_does_not_trust_channel_display_username():
chain.runtime_config = replace(chain.runtime_config, ai_agent_enable=True)
manager = Mock(process_message=AsyncMock())
with patch.object(settings, "AI_AGENT_ENABLE", True), patch(
with patch.object(
global_vars, "CURRENT_EVENT_LOOP", _running_loop_stub()
), patch.object(settings, "AI_AGENT_ENABLE", True), patch(
"app.chain.message.get_running_agent_manager", return_value=manager
), patch(
"app.chain.message.asyncio.run_coroutine_threadsafe",
@@ -175,7 +192,9 @@ def test_message_chain_uses_same_admin_contract_for_slack():
chain.runtime_config = replace(chain.runtime_config, ai_agent_enable=True)
manager = Mock(process_message=AsyncMock())
with patch.object(settings, "AI_AGENT_ENABLE", True), patch(
with patch.object(
global_vars, "CURRENT_EVENT_LOOP", _running_loop_stub()
), patch.object(settings, "AI_AGENT_ENABLE", True), patch(
"app.chain.message.get_running_agent_manager", return_value=manager
), patch(
"app.chain.message.asyncio.run_coroutine_threadsafe",
@@ -295,7 +314,9 @@ def test_agent_choice_callback_is_not_recorded_to_message_history():
manager = Mock(process_message=AsyncMock())
try:
with patch.object(settings, "AI_AGENT_ENABLE", True), patch.object(
with patch.object(
global_vars, "CURRENT_EVENT_LOOP", _running_loop_stub()
), patch.object(settings, "AI_AGENT_ENABLE", True), patch.object(
chain, "_record_user_message"
) as record_user_message, patch.object(
chain, "edit_message", return_value=True