# BooMGateway 配置文件
# 兼容 litellm 的 proxy_server_config.yaml 格式
# model 字段使用 litellm 的 provider/model-id 前缀约定

# ──────────────────────────────────────────────
# 模型部署列表
# ──────────────────────────────────────────────
model_list:
  # OpenAI — 显式前缀
  - model_name: gpt-4
    litellm_params:
      model: openai/gpt-4-turbo
      api_key: os.environ/OPENAI_API_KEY
      rpm: 60                       # 部署级 RPM 限制
      timeout: 1200                 # 请求超时(秒),默认 1200

  # OpenAI — 自动检测 (gpt- 开头自动识别为 openai)
  - model_name: gpt-4o
    litellm_params:
      model: gpt-4o
      api_key: ${OPENAI_API_KEY}

  # 同名多部署 → 自动负载均衡(轮询)
  - model_name: gpt-4o
    litellm_params:
      model: openai/gpt-4o
      api_key: ${OPENAI_API_KEY_BACKUP}
      api_base: https://api.openai.com/v1

  # OpenAI 模型 — 计费通过 cost_template 引用(推荐方式,便于复用)
  - model_name: gpt-4o-billed
    model_info:
      id: node-a                    # 可选:部署标识
      cost_template: gpt-4o         # 引用下方 cost_templates 中的定价
      quota_count_ratio: 3          # 可选:配额消耗倍率,1 次请求消耗 3 个配额
    litellm_params:
      model: openai/gpt-4o
      api_key: os.environ/OPENAI_API_KEY
      temperature: 0.7             # 可选:温度覆盖
      max_tokens: 4096             # 可选:最大输出 token

  # OpenAI 模型 — 直接内联定价(适合一次性配置)
  - model_name: gpt-4o-inline
    model_info:
      input_cost_per_million_tokens: 2.5
      cached_input_cost_per_million_tokens: 1.25   # 可选:KV-cache 命中单价
      output_cost_per_million_tokens: 10.0
    litellm_params:
      model: openai/gpt-4o
      api_key: ${OPENAI_API_KEY}

  # 兜底部署:匹配不到任何 model_name 时路由到这里("*" 是真实 model_name)
  - model_name: "*"
    serve_not_match: true          # 同一部署同时注册为 "*" 兜底
    litellm_params:
      model: openai/gpt-4o
      api_key: ${OPENAI_API_KEY}

  # 带流控的部署 — 限制在途请求数和上下文总量
  # - model_name: gpt-4o
  #   model_info:
  #     id: gpt4o-node-1
  #   flow_control:
  #     model_queue_limit: 50            # 最大在途请求数(0 或不设 = 无限制)
  #     model_context_limit: 5000000     # 最大在途输入字符总量(0 或不设 = 无限制)
  #   litellm_params:
  #     model: openai/gpt-4o
  #     api_key: ${OPENAI_API_KEY}

# ──────────────────────────────────────────────
# 计费模板(可复用的定价表)
# ──────────────────────────────────────────────
# 所有价格均为「USD per 1M tokens」。网关内部会换算成 per-token。
# model_info.cost_template 引用这里的 name;同名时模板覆盖内联字段。
cost_templates:
  - name: gpt-4o
    input_cost_per_million_tokens: 2.5           # $2.5 / 1M 输入 token
    cached_input_cost_per_million_tokens: 1.25   # KV-cache 命中价(通常 1/2)
    output_cost_per_million_tokens: 10.0         # $10 / 1M 输出 token

  - name: gpt-4-turbo
    input_cost_per_million_tokens: 10.0
    cached_input_cost_per_million_tokens: 5.0
    output_cost_per_million_tokens: 30.0

# ──────────────────────────────────────────────
# 通用设置
# ──────────────────────────────────────────────
general_settings:
  # Master key — 不走 DB 也能鉴权
  master_key: os.environ/MASTER_KEY
  # PostgreSQL 连接串(litellm DB)
  database_url: os.environ/DATABASE_URL
  # DB 权威模式:true 时 DB 是模型/别名/套餐的数据源,YAML 仅首次 seed
  # store_model_in_db: false

# ──────────────────────────────────────────────
# 部署健康检查(自动离线/恢复)
# ──────────────────────────────────────────────
deployment_health_check:
  auto_offline_enabled: false          # 在线节点探活失败后是否自动离线
  auto_recovery_enabled: false         # 自动离线节点恢复后是否自动上线
  path: /metric                        # 探活路径:GET {api_base}{path}
  failure_threshold: 3                 # 连续探活失败次数达到阈值后自动离线
  recovery_threshold: 2                # 连续探活成功次数达到阈值后自动恢复
  offline_check_interval_secs: 30      # 在线节点探活间隔
  recovery_check_interval_secs: 60     # 自动离线节点探活间隔
  request_failure_auto_offline_enabled: false  # 请求失败自动离线(仅计数确定性失败:ProviderError / 401/403)
  request_failure_threshold: 3                # 连续请求失败次数达到阈值后自动离线

# ──────────────────────────────────────────────
# 路由设置
# ──────────────────────────────────────────────
router_settings:
  # 路由策略:round_robin(默认)或 key_affinity(会话亲和)
  routing_strategy: round_robin

  # 模型别名:客户端用别名请求,实际路由到目标模型
  model_group_alias:
    # 简单别名
    "gpt-4": "gpt-4o"

    # 扩展格式(可设置 hidden: true 使其不在 /v1/models 中展示)
    "GPT-4o":
      model: "gpt-4o"
      hidden: true

  # key_affinity 策略参数(仅 routing_strategy: key_affinity 时生效)
  # key_affinity_context_threshold: 0     # 上下文字符数阈值,低于此值优先最低负载
  # key_affinity_rebalance_threshold: 10  # 再均衡阈值(请求数差异超过此值时重新分配)

  # 内容路由:根据请求内容自动选择模型(可选)
  # hybrid_router:
  #   model_name: "auto"                  # 虚拟模型名,客户端请求此名触发分类
  #   strategy: "tier_classifier"         # 分类策略(默认 tier_classifier)
  #   default_tier: "medium"              # 分类不确定时使用的默认 tier
  #   tiers:
  #     small:
  #       target_model: "gpt-4o-mini"     # 简单请求 → 轻量模型
  #     medium:
  #       target_model: "gpt-4o"          # 中等请求 → 标准模型
  #     large:
  #       target_model: "gpt-4o"          # 复杂请求 → 强力模型

  # 剥离 Claude Code 注入的 x-anthropic-billing-header 块(仅 /v1/messages)。
  # Claude Code 会在 system prompt 开头注入一个独立 text block:
  #   x-anthropic-billing-header: cc_version=...; cch=<每请求变化>; ...
  # 该 block 会让 KV-cache prefix matching 每次都 miss。开启后会整块丢弃,
  # 恢复 cache 命中(与 vLLM PR #36829 行为一致)。
  # 默认 false:仅在转发到非 Anthropic backend(vLLM / Bedrock / OpenAI 兼容)
  # 时才建议开启;若上游是 Anthropic 官方,剥离可能触发反盗版风控。
  # /v1/chat/completions 不受影响(Claude Code 不会在该协议下注入)。
  strip_claude_code_attribution: false

# ──────────────────────────────────────────────
# 服务器设置
# ──────────────────────────────────────────────
server:
  host: 0.0.0.0
  port: 4000
  workers: 4

# ──────────────────────────────────────────────
# 全局限流设置(无套餐的 key 兜底)
# ──────────────────────────────────────────────
rate_limit:
  enabled: true
  default_rpm: 60                   # 无套餐的 key 的默认 RPM
  # 自定义时间窗口: [次数, 秒数]
  window_limits:
    - [100, 18000]                  # 100 次请求 / 5 小时

# ──────────────────────────────────────────────
# 套餐设置
# ──────────────────────────────────────────────
# 套餐是「通用模板」——同一组限流字段对 key 和 team 都适用。
# type=key 的套餐分配给单个 key(按 key 维度独立计数);
# type=team 的套餐分配给整个 team(team 下所有 key 请求聚合计数)。
# team 套餐可设 member_plan,让 team 下每个 key 再单独套用一个 key 套餐
# 做「team 总额 + key 单独限流」的双层防护。
#
# WindowLimit 项格式:[counts, tokens, costs, window_secs],null 表示不限该维度
#   - [100, 18000, null, 60]      60s 内:100 请求 / 18K token
#   - [null, 1000000, null, 3600] 1h 内:1M token
#   - [null, null, 50.0, 86400]   24h 内:$50
plan_settings:
  default_plan: "basic"             # 未显式分配套餐的 key 使用的默认套餐
  default_team_plan: "team_basic"   # 未显式分配套餐的 team 使用的默认套餐

  plans:
    # ── key 套餐示例:单 key 4 并发、60 RPM、100K TPM ──
    basic:
      type: key                     # 套餐适用对象:key 或 team
      concurrency_limit: 4          # 最大并发请求数(RAII guard,Drop 释放)
      rpm_limit: 60                 # 每分钟请求数上限(60s counts 维度简写)
      tpm_limit: 100000             # 每分钟 token 数上限(60s tokens 维度简写)
      window_limits:                # 多维滑动窗口列表,每项可同时卡 counts/tokens/costs
        - [100, 18000, null, 60]    # 60s 内:100 请求 / 18K token
        - [null, 1000000, null, 3600] # 1h 内:1M token
        - [null, null, 50.0, 86400] # 24h 内:$50
      total_token_limit: 10000000   # 累计 token 总量上限(无时间窗,跨整个生命周期,达到需手动 reset)
      total_cost_limit: 500.0       # 累计费用上限(USD,无时间窗,达到需手动 reset)

    # ── key 套餐示例:白天高配,夜间降级 ──
    pro:
      type: key                     # 套餐适用对象
      concurrency_limit: 8          # 最大并发请求数
      rpm_limit: 120                # 每分钟请求数上限
      tpm_limit: 200000             # 每分钟 token 数上限
      window_limits:                # 多维滑动窗口列表
        - [200, 50000, 100.0, 60]   # 60s 内:200 请求 / 50K token / $100
      total_token_limit: 50000000   # 累计 token 总量上限
      total_cost_limit: 2000.0      # 累计费用上限
      schedule:                     # 时段覆盖,命中时段时 slot 字段覆盖套餐基线
        - hours: "9:00-21:00"       # 北京时间(UTC+8),支持跨午夜
          concurrency_limit: 8      # 时段内并发上限(未设则回退到套餐基线)
          rpm_limit: 120            # 时段内 RPM 上限
        - hours: "21:00-9:00"       # 跨午夜时段
          concurrency_limit: 2      # 夜间降级:并发 2
          rpm_limit: 30             # 夜间降级:RPM 30

    # ── team 套餐示例:team 维度聚合限流 ──
    # team 下每个 key 再套用 basic 套餐做 key 维度限流(双层防护)
    team_basic:
      type: team                    # team 套餐,team 下所有 key 请求聚合计数
      member_plan: basic            # team 下每个 key 单独套用的 key 套餐名
      concurrency_limit: 40         # team 总并发上限
      rpm_limit: 600                # team 总 RPM 上限
      window_limits:                # team 维度多维滑动窗口
        - [1000, 10000000, 150.0, 3600] # 1h 内:1000 请求 / 10M token / $150
      total_token_limit: 1000000000 # team 累计 token 总量上限
      total_cost_limit: 10000.0     # team 累计费用上限

    # ── 企业版 team 套餐:高额累计上限 ──
    enterprise:
      type: team                    # team 套餐
      member_plan: pro              # team 下每个 key 套用 pro 套餐
      concurrency_limit: 100        # team 总并发上限
      rpm_limit: 3000               # team 总 RPM 上限
      total_token_limit: 100000000000 # team 累计 token 总量上限(100B)
      total_cost_limit: 50000.0     # team 累计费用上限($50K)

# ──────────────────────────────────────────────
# Prompt 日志(完整请求/响应落盘,调试用)
# ──────────────────────────────────────────────
# 默认关闭。开启后每个请求的输入/输出会按天分目录写入 dir。
# 可在 Dashboard 按套餐/team/key 维度动态开关,也可在这里做全局默认。
prompt_log:
  enabled: false                    # 全局开关,默认关闭
  dir: "/data/prompt_logs"          # 日志根目录,按天分子目录
  max_file_size_mb: 50              # 单文件大小上限(MB),超过自动滚动
  capture_raw_upstream: false       # 同时记录上游原始响应(仅格式转换路径如 /v1/messages)
  excluded_keys: []                 # 跳过这些 key(key_hash),不记录
  excluded_teams: []                # 跳过这些 team(team_id),不记录