fix: honor strict workflow agent entry mode
This commit is contained in:
@@ -867,6 +867,66 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
self.assertEqual(brain._flow_tool(timeout_tool, "start").timeout_secs, 7.0)
|
||||
self.assertIsNone(brain._flow_tool(session_tool, "start").timeout_secs)
|
||||
|
||||
async def test_flow_transition_honors_strict_agent_entry_mode(self):
|
||||
brain = WorkflowBrain(
|
||||
{
|
||||
"specVersion": 3,
|
||||
"settings": {},
|
||||
"nodes": [
|
||||
{"id": "start", "type": "start", "data": {}},
|
||||
{
|
||||
"id": "waiting",
|
||||
"type": "agent",
|
||||
"data": {"entryMode": "wait_user"},
|
||||
},
|
||||
{
|
||||
"id": "immediate",
|
||||
"type": "agent",
|
||||
"data": {"entryMode": "generate"},
|
||||
},
|
||||
],
|
||||
"edges": [],
|
||||
}
|
||||
)
|
||||
|
||||
async def queue_frame(_frame):
|
||||
pass
|
||||
|
||||
brain._runtime = BrainRuntime(
|
||||
context=LLMContext(messages=[]),
|
||||
llm=FakeLLM(),
|
||||
queue_frame=queue_frame,
|
||||
set_system_prompt=lambda _prompt: None,
|
||||
set_tools=lambda _tools: None,
|
||||
call_end=FakeCallEnd(),
|
||||
)
|
||||
|
||||
brain._state.begin_user_turn("完成上一阶段")
|
||||
waiting_config = brain._flow_managed_transition_config(
|
||||
{"name": "waiting"},
|
||||
triggering_user_text="完成上一阶段",
|
||||
)
|
||||
waiting_action = waiting_config["pre_actions"][0]
|
||||
|
||||
self.assertFalse(waiting_config["respond_immediately"])
|
||||
self.assertTrue(waiting_action["consume_triggering_turn"])
|
||||
await waiting_action["handler"](waiting_action, SimpleNamespace())
|
||||
self.assertEqual(brain._state.status, WorkflowStatus.WAITING_USER)
|
||||
self.assertIsNone(brain._state.pending_user_turn)
|
||||
|
||||
brain._state.begin_user_turn("请立即处理")
|
||||
immediate_config = brain._flow_managed_transition_config(
|
||||
{"name": "immediate"},
|
||||
triggering_user_text="请立即处理",
|
||||
)
|
||||
immediate_action = immediate_config["pre_actions"][0]
|
||||
|
||||
self.assertTrue(immediate_config["respond_immediately"])
|
||||
self.assertFalse(immediate_action["consume_triggering_turn"])
|
||||
await immediate_action["handler"](immediate_action, SimpleNamespace())
|
||||
self.assertEqual(brain._state.status, WorkflowStatus.RUNNING_AGENT)
|
||||
self.assertIsNotNone(brain._state.pending_user_turn)
|
||||
|
||||
async def test_session_update_refreshes_current_agent_without_routing(self):
|
||||
cfg = prepare_dynamic_config(
|
||||
AssistantConfig(
|
||||
@@ -1614,6 +1674,7 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
"data": {
|
||||
"prompt": "处理用户输入",
|
||||
"contextPolicy": "fresh",
|
||||
"entryMode": "generate",
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -1874,6 +1935,9 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
for message in manager.configs[-1]["task_messages"]
|
||||
)
|
||||
)
|
||||
runs_before_second_transition = sum(
|
||||
isinstance(frame, LLMRunFrame) for frame in queued
|
||||
)
|
||||
|
||||
# The user-turn processor must return while the second Message is
|
||||
# still waiting for its transport playback boundary.
|
||||
@@ -1892,7 +1956,12 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
if manager.current_node == "agent2":
|
||||
break
|
||||
self.assertEqual(manager.current_node, "agent2")
|
||||
self.assertTrue(any(isinstance(frame, LLMRunFrame) for frame in queued))
|
||||
self.assertEqual(
|
||||
sum(isinstance(frame, LLMRunFrame) for frame in queued),
|
||||
runs_before_second_transition,
|
||||
)
|
||||
self.assertEqual(brain._state.status, WorkflowStatus.WAITING_USER)
|
||||
self.assertIsNone(brain._state.pending_user_turn)
|
||||
self.assertEqual(
|
||||
manager.configs[-1]["task_messages"],
|
||||
[
|
||||
@@ -1906,7 +1975,6 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
],
|
||||
)
|
||||
|
||||
await brain.on_assistant_text_end("agent2-turn", "信息确认完成", False)
|
||||
await brain.on_user_turn_end("结束通话")
|
||||
self.assertEqual(manager.current_node, "end")
|
||||
self.assertTrue(call_end.finished)
|
||||
@@ -2031,7 +2099,7 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
)
|
||||
)
|
||||
|
||||
async def test_start_llm_conditions_wait_for_and_route_first_user_turn(self):
|
||||
async def test_waiting_agent_does_not_reply_to_transitioning_user_turn(self):
|
||||
brain = WorkflowBrain(
|
||||
{
|
||||
"specVersion": 3,
|
||||
@@ -2161,9 +2229,16 @@ class WorkflowBrainTests(unittest.IsolatedAsyncioTestCase):
|
||||
image_message,
|
||||
manager.config["task_messages"],
|
||||
)
|
||||
self.assertTrue(any(isinstance(frame, LLMRunFrame) for frame in queued))
|
||||
self.assertFalse(any(isinstance(frame, LLMRunFrame) for frame in queued))
|
||||
self.assertEqual(brain._state.status, WorkflowStatus.WAITING_USER)
|
||||
self.assertIsNone(brain._state.pending_user_turn)
|
||||
self.assertIn("我想吃饭", brain._store.values["system__conversation_history"])
|
||||
|
||||
await brain.on_user_turn_end("我要一份米饭")
|
||||
|
||||
self.assertTrue(any(isinstance(frame, LLMRunFrame) for frame in queued))
|
||||
self.assertEqual(brain._state.status, WorkflowStatus.RUNNING_AGENT)
|
||||
|
||||
async def test_start_expression_condition_also_waits_for_user_turn(self):
|
||||
brain = WorkflowBrain(
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user