diff --git a/core/agent/types.py b/core/agent/types.py new file mode 100644 index 0000000..b0075f0 --- /dev/null +++ b/core/agent/types.py @@ -0,0 +1,31 @@ +"""AgentLoop 数据类型。""" +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any + + +@dataclass +class Step: + """Agent 单步决策记录。""" + + thought: str + reflect: dict[str, Any] + plan: dict[str, Any] + tool_call: dict[str, Any] + tool_output: str + raw_content: str + call_id: str + + +@dataclass +class LoopResult: + """AgentLoop 完整运行结果。""" + + result: dict[str, Any] | None = None + steps: list[Step] = field(default_factory=list) + steps_used: int = 0 + token_usage: dict[str, int] = field( + default_factory=lambda: {"prompt_tokens": 0, "completion_tokens": 0} + ) + stop_reason: str = "finished" diff --git a/tests/unit/test_agent_types.py b/tests/unit/test_agent_types.py new file mode 100644 index 0000000..6449f1c --- /dev/null +++ b/tests/unit/test_agent_types.py @@ -0,0 +1,50 @@ +"""core/agent/types.py 单元测试。""" +from __future__ import annotations + +from core.agent.types import LoopResult, Step + + +class TestStep: + def test_creation(self) -> None: + step = Step( + thought="thinking...", + reflect={"key": "value"}, + plan={"next": "do something"}, + tool_call={"tool": "search", "args": {"query": "test"}}, + tool_output="result text", + raw_content='{"reflect": {}, "plan": {}, "action": {}}', + call_id="uuid-1", + ) + assert step.thought == "thinking..." + assert step.tool_call["tool"] == "search" + assert step.call_id == "uuid-1" + + +class TestLoopResult: + def test_defaults(self) -> None: + lr = LoopResult() + assert lr.result is None + assert lr.steps == [] + assert lr.steps_used == 0 + assert lr.token_usage == {"prompt_tokens": 0, "completion_tokens": 0} + assert lr.stop_reason == "finished" + + def test_with_steps(self) -> None: + step = Step( + thought="t", reflect={}, plan={}, + tool_call={"tool": "t", "args": {}}, + tool_output="o", raw_content="r", call_id="c", + ) + lr = LoopResult( + result={"answer": "42"}, steps=[step], steps_used=1, + token_usage={"prompt_tokens": 100, "completion_tokens": 50}, + stop_reason="finished", + ) + assert lr.result == {"answer": "42"} + assert len(lr.steps) == 1 + + def test_separate_instances_have_independent_lists(self) -> None: + lr1 = LoopResult() + lr2 = LoopResult() + lr1.steps.append(Step("t", {}, {}, {"tool": "x", "args": {}}, "o", "r", "c")) + assert len(lr2.steps) == 0