feat(core/agent): 添加 Step 和 LoopResult 数据类
保真 TRM4 算法 #11,Step 新增 call_id 字段。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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"
|
||||||
@@ -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
|
||||||
Reference in New Issue
Block a user