from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum

class Status(str, Enum):
    CREATED = "CREATED"
    RUNNING = "RUNNING"
    SUCCEEDED = "SUCCEEDED"
    DENIED = "DENIED"
    BUDGET_EXCEEDED = "BUDGET_EXCEEDED"

@dataclass
class Run:
    run_id: str
    max_steps: int = 3
    status: Status = Status.CREATED
    steps: int = 0
    events: list = field(default_factory=list)

class Engine:
    def __init__(self, allowed_tools):
        self.allowed_tools = dict(allowed_tools)

    def execute(self, run, proposals):
        run.status = Status.RUNNING
        run.events.append(("RUN_STARTED", run.run_id))
        for action in proposals:
            if run.steps >= run.max_steps:
                run.status = Status.BUDGET_EXCEEDED
                run.events.append(("BUDGET_EXCEEDED", run.steps))
                return run
            run.steps += 1
            if action["type"] == "final":
                run.status = Status.SUCCEEDED
                run.events.append(("RUN_SUCCEEDED", action["text"]))
                return run
            if action["type"] != "tool" or action.get("name") not in self.allowed_tools:
                run.status = Status.DENIED
                run.events.append(("ACTION_DENIED", action))
                return run
            result = self.allowed_tools[action["name"]](action.get("args", {}))
            run.events.append(("TOOL_RESULT", result))
        run.status = Status.BUDGET_EXCEEDED
        run.events.append(("NO_FINAL", run.steps))
        return run

if __name__ == "__main__":
    engine = Engine({"search": lambda args: ["doc-001"]})
    good = engine.execute(Run("good"), [
        {"type": "tool", "name": "search", "args": {"q": "agent engine"}},
        {"type": "final", "text": "报告已完成"},
    ])
    assert good.status == Status.SUCCEEDED and good.steps == 2
    denied = engine.execute(Run("denied"), [
        {"type": "tool", "name": "publish", "args": {"path": "report.md"}}
    ])
    assert denied.status == Status.DENIED
    limited = engine.execute(Run("limited", max_steps=1), [
        {"type": "tool", "name": "search", "args": {}},
        {"type": "final", "text": "late"},
    ])
    assert limited.status == Status.BUDGET_EXCEEDED
    print("3 checks passed")
