#!/usr/bin/env python3
"""stop_reason_router.py — 按 stop_reason 分派的响应处理骨架（无需 API key，本地可跑）

演示生产代码必须做的分支处理。stop_reason 枚举截至 2026-08-30：
end_turn / max_tokens / stop_sequence / tool_use / pause_turn / refusal /
model_context_window_exceeded

来源: https://platform.claude.com/docs/en/api/messages（访问于 2026-08-30）
运行: python3 stop_reason_router.py
"""

from dataclasses import dataclass


@dataclass
class HandleResult:
    action: str          # deliver | retry | tools | continue | degrade | abort
    detail: str


def handle_response(resp: dict) -> HandleResult:
    """resp 模拟 Messages API 的响应对象。"""
    reason = resp.get("stop_reason")
    usage = resp.get("usage", {})

    if reason == "end_turn":
        return HandleResult("deliver", "自然结束，正常交付给用户")

    if reason == "max_tokens":
        # 语义可能被截断：不能盲目交付
        return HandleResult(
            "retry",
            "输出被截断：检查内容完整性；调大 max_tokens 或分段生成；"
            "长输出建议 streaming 防 10 分钟超时",
        )

    if reason == "stop_sequence":
        return HandleResult("deliver", f"命中自定义停止串 {resp.get('stop_sequence')!r}，按业务边界交付")

    if reason == "tool_use":
        return HandleResult("tools", "提取 tool_use 块 -> 执行 -> 回传 tool_result（模块 4）")

    if reason == "pause_turn":
        return HandleResult("continue", "长任务暂停：把本次响应原样回传即可继续")

    if reason == "refusal":
        return HandleResult("degrade", "安全分类器介入：记录 request-id、走降级话术，不要自动重试")

    if reason == "model_context_window_exceeded":
        return HandleResult(
            "abort",
            "超上下文窗口：压缩历史/检索裁剪/换 1M 窗口模型后重试",
        )

    # 版本化策略：API 可能新增 stop_reason，未知值要优雅处理
    return HandleResult("degrade", f"未知 stop_reason {reason!r}：按版本兼容策略降级")


if __name__ == "__main__":
    cases = [
        {"stop_reason": "end_turn", "usage": {"input_tokens": 120, "output_tokens": 45}},
        {"stop_reason": "max_tokens", "usage": {"input_tokens": 120, "output_tokens": 1024}},
        {"stop_reason": "stop_sequence", "stop_sequence": "\n\nHuman:"},
        {"stop_reason": "tool_use"},
        {"stop_reason": "pause_turn"},
        {"stop_reason": "refusal"},
        {"stop_reason": "model_context_window_exceeded"},
        {"stop_reason": "some_future_reason_2027"},   # 未来新增值的优雅处理
    ]
    for c in cases:
        r = handle_response(c)
        print(f"{c['stop_reason']:36s} -> {r.action:8s} | {r.detail}")

    # usage 三件套认知检查：input_tokens 只是"最后一个缓存断点之后"的输入
    usage = {"input_tokens": 50, "cache_read_input_tokens": 200_000, "cache_creation_input_tokens": 0}
    total = usage["input_tokens"] + usage["cache_read_input_tokens"] + usage["cache_creation_input_tokens"]
    assert total == 200_050
    print("\nusage 校验: input_tokens(50) + cache_read(200000) + cache_creation(0) =", total,
          "（不要把 input_tokens 当总输入！）")
