"""`AgentSpec` 模型（Prompt 外置方案A · 步1）。

从 `specs.py` 原样抽出的 frozen Pydantic 声明，字段不变（`system_prompt` 仍是
`str`，import 期由 `load_prompt` 填入；不改 Callable——缓存断点前块需确定字符串）。
内置 Agent 与用户 Skill 同构：一份只读声明，由编排器加载、经网关按 `tier` 执行。

- 不变量 #2：agent 只声明 `tier`，**不**写具体 model。
- 不变量 #3：四审 `writes=[]`（只读），任何 AI 产出入库必经验收事务。
"""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict
from ww_llm_gateway.types import Tier


class AgentSpec(BaseModel):
    """单一 Agent / Skill 的声明（ARCH §5.1）。"""

    model_config = ConfigDict(frozen=True, arbitrary_types_allowed=True)

    name: str
    tier: Tier  # 能力档位（网关解析 provider+model）；不含具体 model
    system_prompt: str
    # 入/出参契约（Pydantic 模型类型）；writer 纯文本 → output_schema 可为 None
    input_schema: type[BaseModel] | None = None
    output_schema: type[BaseModel] | None = None
    # 不可变序列：frozen 只防整字段重绑，不防 list 原地变异；tuple 无 append/clear，
    # 守住不变量 #3（四审 writes==() 不可被 .append 旁路）。Pydantic v2 coerce list→tuple。
    reads: tuple[str, ...] = ()  # 声明式表读权限
    writes: tuple[str, ...] = ()  # 声明式表写权限（经验收才生效）
    genre: str | None = None  # 题材适用（Skill 用）
    scope: str = "builtin"  # builtin / custom / community
