From f9d6dc1ac96b3ae4114af0df95381ae60318bd27 Mon Sep 17 00:00:00 2001 From: Jackp0t <16182712+jackkp0t@user.noreply.gitee.com> Date: Tue, 22 Sep 2026 19:37:15 +0800 Subject: [PATCH] fix: harden orchestrator parsing defaults --- tests/agents/test_orchestrator_chain.py | 17 +++++++++++++++++ utu/agents/common.py | 2 +- utu/agents/orchestrator/chain.py | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/agents/test_orchestrator_chain.py diff --git a/tests/agents/test_orchestrator_chain.py b/tests/agents/test_orchestrator_chain.py new file mode 100644 index 00000000..6d4a20f9 --- /dev/null +++ b/tests/agents/test_orchestrator_chain.py @@ -0,0 +1,17 @@ +import pytest + +from utu.agents.common import TaskRecorder +from utu.agents.orchestrator.chain import ChainPlanner +from utu.agents.orchestrator.common import Recorder + + +def test_parse_reports_missing_plan_block() -> None: + planner = object.__new__(ChainPlanner) + recorder = Recorder(input="summarize the report") + + with pytest.raises(AssertionError, match="No tasks parsed from plan"): + planner._parse("the response was truncated", recorder) + + +def test_task_recorder_defaults_input_to_list() -> None: + assert TaskRecorder().input == [] diff --git a/utu/agents/common.py b/utu/agents/common.py index 9f816729..33e04e33 100644 --- a/utu/agents/common.py +++ b/utu/agents/common.py @@ -92,7 +92,7 @@ def to_dict(self): class TaskRecorder(DataClassWithStreamEvents): task: str = "" trace_id: str = "" - input: str | list[TResponseInputItem] = field(default_factory=dict) + input: str | list[TResponseInputItem] = field(default_factory=list) # from RunResultStreaming final_output: str = "" diff --git a/utu/agents/orchestrator/chain.py b/utu/agents/orchestrator/chain.py index c8236ceb..b91888b6 100644 --- a/utu/agents/orchestrator/chain.py +++ b/utu/agents/orchestrator/chain.py @@ -82,7 +82,7 @@ def _parse(self, text: str, recorder: Recorder) -> Plan: analysis = match.group(1).strip() if match else "" match = re.search(r"\s*\[(.*?)\]\s*", text, re.DOTALL) - plan_content = match.group(1).strip() + plan_content = match.group(1).strip() if match else "" tasks: list[Task] = [] task_pattern = r'\{"name":\s*"([^"]+)",\s*"task":\s*"([^"]+)"\s*\}' task_matches = re.findall(task_pattern, plan_content, re.IGNORECASE)