"""01 · Agent Definition & Boundaries v1.1 demo.

离线对照实验：AdaptivePolicy vs FixedPolicy，验证运行时决策权、
行动白名单与完成门禁。标准库 only；不是真实 LLM / 工具调用。
运行：python3 01-Agent-Definition-and-Boundaries-v1.1-demo.py
"""
from __future__ import annotations

from dataclasses import dataclass, field
from typing import Optional, Protocol


@dataclass
class State:
    facts: dict[str, str] = field(default_factory=dict)
    actions: list[str] = field(default_factory=list)
    report: Optional[str] = None


class Policy(Protocol):
    def decide(self, state: State) -> str: ...


class AdaptivePolicy:
    def decide(self, state: State) -> str:
        if "A" not in state.facts:
            return "read_A"
        if "B" not in state.facts:
            return "read_B"
        if state.report is None:
            return "write_report"
        return "finish"


class FixedPolicy:
    def __init__(self):
        self.plan = iter(["read_A", "read_B", "write_report", "finish"])

    def decide(self, state: State) -> str:
        return next(self.plan)


class Environment:
    def __init__(self, available: dict[str, str]):
        self.available = available

    def execute(self, action: str, state: State) -> None:
        if action.startswith("read_"):
            key = action.removeprefix("read_")
            if key not in self.available:
                raise LookupError(key)
            state.facts[key] = self.available[key]
        elif action == "write_report":
            if not {"A", "B"}.issubset(state.facts):
                raise ValueError("insufficient evidence")
            state.report = f"A: {state.facts['A']}; B: {state.facts['B']}"
        else:
            raise ValueError(f"unknown action: {action}")


ALLOWED = {"read_A", "read_B", "write_report"}


def run(policy: Policy, env: Environment, initial=None, max_steps=6):
    state = initial or State()
    for _ in range(max_steps):
        action = policy.decide(state)
        if action == "finish":
            assert state.report is not None, "premature completion"
            return state
        if action not in ALLOWED:
            raise PermissionError(action)
        env.execute(action, state)
        state.actions.append(action)
    raise TimeoutError("step budget exhausted")


if __name__ == "__main__":
    env = Environment({"A": "graph state", "B": "workflow history"})
    normal = run(AdaptivePolicy(), env)
    assert normal.actions == ["read_A", "read_B", "write_report"]

    # 在任务开始前已经有 A 的可信观察；动态策略跳过冗余读取。
    resumed = run(AdaptivePolicy(), env, State(facts={"A": "cached A"}))
    assert resumed.actions == ["read_B", "write_report"]

    fixed = run(FixedPolicy(), env, State(facts={"A": "cached A"}))
    assert fixed.actions == ["read_A", "read_B", "write_report"]

    class UnsafePolicy:
        def decide(self, state):
            return "delete_files"

    try:
        run(UnsafePolicy(), env)
    except PermissionError:
        pass
    else:
        raise AssertionError("unauthorized action was executed")
    print("4 boundary-mechanism checks passed")
