#!/usr/bin/env python3
"""结构化输出 + strict tool use 完整示例（需要 ANTHROPIC_API_KEY，静态校验通过）。

演示官方 Structured outputs 的两个互补特性（截至 2026-08-30）：
  1. JSON outputs  —— output_config.format: {type: "json_schema", schema: ...}
  2. Strict tool use —— 工具定义上加 strict: true

先设置环境变量 ANTHROPIC_API_KEY，再运行: python3 structured_output_api.py
来源: https://platform.claude.com/docs/en/build-with-claude/structured-outputs（访问于 2026-08-30）

注意: 本文件未在本机实际调用 API（无 key 环境），已做静态校验；
     依赖 anthropic SDK（pip install anthropic）。
"""

from __future__ import annotations

import json
import os
import sys

try:
    import anthropic
except ImportError:
    print("需要安装 SDK: pip install anthropic", file=sys.stderr)
    sys.exit(1)

MODEL = "claude-sonnet-4-6"  # 模型名截至 2026-08-30，按需替换

# 工单抽取 schema：注意枚举大小写坑（官方已知行为），下游做不敏感归一
TICKET_SCHEMA = {
    "type": "object",
    "properties": {
        "topic": {"type": "string"},
        "severity": {"enum": ["low", "medium", "high", "urgent"]},
        "product_line": {"type": "string"},
    },
    "required": ["topic", "severity", "product_line"],  # 能 required 就不 optional
    "additionalProperties": False,  # 对象必须显式 false
}

SEARCH_FLIGHTS_TOOL = {
    "name": "search_flights",
    "strict": True,  # strict tool use：工具名与入参保证过 schema
    "input_schema": {
        "type": "object",
        "properties": {
            "destination": {"type": "string"},
            "date": {"type": "string", "format": "date"},
        },
        "required": ["destination", "date"],
        "additionalProperties": False,
    },
}


def extract_ticket(email_text: str) -> dict:
    client = anthropic.Anthropic()  # 密钥只从环境变量读取
    response = client.messages.create(
        model=MODEL,
        max_tokens=1024,
        messages=[
            {
                "role": "user",
                "content": (
                    "<instructions>从邮件中抽取工单字段。"
                    "severity 只能取 low/medium/high/urgent。</instructions>"
                    f"<email>{email_text}</email>"
                ),
            }
        ],
        output_config={"format": {"type": "json_schema", "schema": TICKET_SCHEMA}},
    )
    raw = next(b.text for b in response.content if b.type == "text")
    ticket = json.loads(raw)
    # 官方已知行为：enum 值可能大小写不完全匹配且不报错 -> 归一化
    ticket["severity"] = ticket["severity"].lower()
    return ticket


def plan_trip_with_strict_tools(question: str):
    client = anthropic.Anthropic()
    return client.messages.create(
        model=MODEL,
        max_tokens=1024,
        messages=[{"role": "user", "content": question}],
        # JSON outputs 与 strict tool use 可同请求组合
        output_config={
            "format": {
                "type": "json_schema",
                "schema": {
                    "type": "object",
                    "properties": {
                        "summary": {"type": "string"},
                        "next_steps": {"type": "array", "items": {"type": "string"}},
                    },
                    "required": ["summary", "next_steps"],
                    "additionalProperties": False,
                },
            }
        },
        tools=[SEARCH_FLIGHTS_TOOL],
    )


if __name__ == "__main__":
    if not os.environ.get("ANTHROPIC_API_KEY"):
        print("请先设置环境变量 ANTHROPIC_API_KEY", file=sys.stderr)
        sys.exit(1)
    print(json.dumps(extract_ticket(
        "Hi, our prod dashboard is down since 9am, we're on the Analytics line. "
        "This is urgent — losing data every minute."
    ), ensure_ascii=False, indent=2))
