"""带 Schema 校验、步数上限和工具白名单的最小 Agent 循环。"""
from dataclasses import dataclass, field
from typing import Any, Callable


@dataclass
class State:
    goal: str
    observations: list[dict[str, Any]] = field(default_factory=list)


def run_agent(
    model: Callable[[State], dict[str, Any]],
    tools: dict[str, Callable[..., Any]],
    goal: str,
    max_steps: int = 5,
):
    state = State(goal=goal)
    for _ in range(max_steps):
        decision = model(state)
        kind = decision.get("type")
        if kind == "final":
            return {"status": "ok", "answer": decision.get("answer", ""), "trace": state.observations}
        if kind != "tool" or decision.get("name") not in tools:
            state.observations.append({"error": "invalid decision"})
            continue
        args = decision.get("arguments")
        if not isinstance(args, dict):
            state.observations.append({"error": "arguments must be an object"})
            continue
        try:
            result = tools[decision["name"]](**args)
            state.observations.append({"tool": decision["name"], "result": result})
        except Exception as exc:  # 生产系统应映射为稳定错误码，并避免泄露敏感堆栈。
            state.observations.append({"tool": decision["name"], "error": type(exc).__name__})
    return {"status": "max_steps", "trace": state.observations}
