# Sub2API Configuration File
# Sub2API 配置文件
#
# Copy this file to /etc/sub2api/config.yaml and modify as needed
# 复制此文件到 /etc/sub2api/config.yaml 并根据需要修改
#
# Documentation / 文档: https://github.com/Wei-Shaw/sub2api

# =============================================================================
# Server Configuration
# 服务器配置
# =============================================================================
server:
  # Bind address (0.0.0.0 for all interfaces)
  # 绑定地址（0.0.0.0 表示监听所有网络接口）
  host: "0.0.0.0"
  # Port to listen on
  # 监听端口
  port: 8080
  # Mode: "debug" for development, "release" for production
  # 运行模式："debug" 用于开发，"release" 用于生产环境
  mode: "release"
  # Frontend base URL used to generate external links in emails (e.g. password reset)
  # 用于生成邮件中的外部链接（例如：重置密码链接）的前端基础地址
  # Example: "https://example.com"
  frontend_url: ""
  # Trusted proxies for X-Forwarded-For parsing (CIDR/IP). Empty disables trusted proxies.
  # 信任的代理地址（CIDR/IP 格式），用于解析 X-Forwarded-For 头。留空则禁用代理信任。
  trusted_proxies: []
  # Global max request body size in bytes (default: 256MB)
  # 全局最大请求体大小（字节，默认 256MB）
  # Applies to all requests, especially important for h2c first request memory protection
  # 适用于所有请求，对 h2c 第一请求的内存保护尤为重要
  max_request_body_size: 268435456
  # HTTP/2 Cleartext (h2c) configuration
  # HTTP/2 Cleartext (h2c) 配置
  h2c:
    # Enable HTTP/2 Cleartext for client connections
    # 启用 HTTP/2 Cleartext 客户端连接
    enabled: true
    # Max concurrent streams per connection
    # 每个连接的最大并发流数量
    max_concurrent_streams: 50
    # Idle timeout for connections (seconds)
    # 连接空闲超时时间（秒）
    idle_timeout: 75
    # Max frame size in bytes (default: 1MB)
    # 最大帧大小（字节，默认 1MB）
    max_read_frame_size: 1048576
    # Max upload buffer per connection in bytes (default: 2MB)
    # 每个连接的最大上传缓冲区（字节，默认 2MB）
    max_upload_buffer_per_connection: 2097152
    # Max upload buffer per stream in bytes (default: 512KB)
    # 每个流的最大上传缓冲区（字节，默认 512KB）
    max_upload_buffer_per_stream: 524288

# =============================================================================
# Run Mode Configuration
# 运行模式配置
# =============================================================================
# Run mode: "standard" (default) or "simple" (for internal use)
# 运行模式："standard"（默认）或 "simple"（内部使用）
# - standard: Full SaaS features with billing/balance checks
# - standard: 完整 SaaS 功能，包含计费和余额校验
# - simple: Hides SaaS features and skips billing/balance checks
# - simple: 隐藏 SaaS 功能，跳过计费和余额校验
run_mode: "standard"

# =============================================================================
# CORS Configuration
# 跨域资源共享 (CORS) 配置
# =============================================================================
cors:
  # Allowed origins list. Leave empty to disable cross-origin requests.
  # 允许的来源列表。留空则禁用跨域请求。
  allowed_origins: []
  # Allow credentials (cookies/authorization headers). Cannot be used with "*".
  # 允许携带凭证（cookies/授权头）。不能与 "*" 通配符同时使用。
  allow_credentials: true

# =============================================================================
# Security Configuration
# 安全配置
# =============================================================================
security:
  url_allowlist:
    # Enable URL allowlist validation (disable to skip all URL checks)
    # 启用 URL 白名单验证（禁用则跳过所有 URL 检查）
    enabled: false
    # Allowed upstream hosts for API proxying
    # 允许代理的上游 API 主机列表
    upstream_hosts:
      - "api.openai.com"
      - "api.anthropic.com"
      - "api.kimi.com"
      - "open.bigmodel.cn"
      - "api.minimaxi.com"
      - "generativelanguage.googleapis.com"
      - "cloudcode-pa.googleapis.com"
      - "*.openai.azure.com"
    # Allowed hosts for pricing data download
    # 允许下载定价数据的主机列表
    pricing_hosts:
      - "raw.githubusercontent.com"
    # Allowed hosts for CRS sync (required when using CRS sync)
    # 允许 CRS 同步的主机列表（使用 CRS 同步功能时必须配置）
    crs_hosts: []
    # Allow localhost/private IPs for upstream/pricing/CRS (use only in trusted networks)
    # 允许本地/私有 IP 地址用于上游/定价/CRS（仅在可信网络中使用）
    allow_private_hosts: true
    # Allow http:// URLs when allowlist is disabled (default: false, require https)
    # 白名单禁用时是否允许 http:// URL（默认: false，要求 https）
    allow_insecure_http: true
  response_headers:
    # Enable configurable response header filtering (default: true)
    # 启用可配置的响应头过滤（默认启用，过滤上游敏感响应头）
    enabled: true
    # Extra allowed response headers from upstream
    # 额外允许的上游响应头
    additional_allowed: []
    # Force-remove response headers from upstream
    # 强制移除的上游响应头
    force_remove: []
  csp:
    # Enable Content-Security-Policy header
    # 启用内容安全策略 (CSP) 响应头
    enabled: true
    # Default CSP policy (override if you host assets on other domains)
    # 默认 CSP 策略（如果静态资源托管在其他域名，请自行覆盖）
    # Note: __CSP_NONCE__ will be replaced with 'nonce-xxx' at request time for inline script security
    # 注意：__CSP_NONCE__ 会在请求时被替换为 'nonce-xxx'，用于内联脚本安全
    policy: "default-src 'self'; script-src 'self' __CSP_NONCE__ https://challenges.cloudflare.com https://static.cloudflareinsights.com https://*.stripe.com https://static.airwallex.com https://checkout.airwallex.com https://static-demo.airwallex.com https://checkout-demo.airwallex.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://static.airwallex.com https://checkout.airwallex.com https://static-demo.airwallex.com https://checkout-demo.airwallex.com; img-src 'self' data: https:; font-src 'self' data: https://fonts.gstatic.com; connect-src 'self' https:; frame-src https://challenges.cloudflare.com https://*.stripe.com https://checkout.airwallex.com https://checkout-demo.airwallex.com; frame-ancestors 'none'; base-uri 'self'; form-action 'self'"
  proxy_probe:
    # Allow skipping TLS verification for proxy probe (debug only)
    # 允许代理探测时跳过 TLS 证书验证（仅用于调试）
    insecure_skip_verify: false
  proxy_fallback:
    # Allow auxiliary services (update check, pricing data) to fallback to direct
    # connection when proxy initialization fails. Does NOT affect AI gateway connections.
    # 辅助服务（更新检查、定价数据拉取）代理初始化失败时是否允许回退直连。
    # 不影响 AI 账号网关连接。默认 false：fail-fast 防止 IP 泄露。
    allow_direct_on_error: false

# =============================================================================
# Gateway Configuration
# 网关配置
# =============================================================================
gateway:
  # Timeout for waiting upstream response headers (seconds)
  # 等待上游响应头超时时间（秒）
  response_header_timeout: 600
  # Max request body size in bytes (default: 256MB)
  # 请求体最大字节数（默认 256MB）
  max_body_size: 268435456
  # Max bytes to read for non-stream upstream responses (default: 8MB)
  # 非流式上游响应体读取上限（默认 8MB）
  upstream_response_read_max_bytes: 8388608
  # Max bytes to read for proxy probe responses (default: 1MB)
  # 代理探测响应体读取上限（默认 1MB）
  proxy_probe_response_read_max_bytes: 1048576
  # Enable Gemini upstream response header debug logs (default: false)
  # 是否开启 Gemini 上游响应头调试日志（默认 false）
  gemini_debug_response_headers: false
  # Sora max request body size in bytes (0=use max_body_size)
  # Sora 请求体最大字节数（0=使用 max_body_size）
  sora_max_body_size: 268435456
  # Sora stream timeout (seconds, 0=disable)
  # Sora 流式请求总超时（秒，0=禁用）
  sora_stream_timeout_seconds: 900
  # Sora non-stream timeout (seconds, 0=disable)
  # Sora 非流式请求超时（秒，0=禁用）
  sora_request_timeout_seconds: 180
  # Sora stream enforcement mode: force/error
  # Sora stream 强制策略：force/error
  sora_stream_mode: "force"
  # Sora model filters
  # Sora 模型过滤配置
  sora_model_filters:
    # Hide prompt-enhance models by default
    # 默认隐藏 prompt-enhance 模型
    hide_prompt_enhance: true
  # Require API key for /sora/media proxy (default: false)
  # /sora/media 是否强制要求 API Key（默认 true）
  sora_media_require_api_key: true
  # Sora media temporary signing key (empty disables signed URL)
  # Sora 媒体临时签名密钥（为空则禁用签名）
  sora_media_signing_key: ""
  # Signed URL TTL seconds (<=0 disables)
  # 临时签名 URL 有效期（秒，<=0 表示禁用）
  sora_media_signed_url_ttl_seconds: 900
  # Connection pool isolation strategy:
  # 连接池隔离策略：
  # - proxy: Isolate by proxy, same proxy shares connection pool (suitable for few proxies, many accounts)
  # - proxy: 按代理隔离，同一代理共享连接池（适合代理少、账户多）
  # - account: Isolate by account, same account shares connection pool (suitable for few accounts, strict isolation)
  # - account: 按账户隔离，同一账户共享连接池（适合账户少、需严格隔离）
  # - account_proxy: Isolate by account+proxy combination (default, finest granularity)
  # - account_proxy: 按账户+代理组合隔离（默认，最细粒度）
  connection_pool_isolation: "account_proxy"
  # Force Codex CLI mode: treat all /openai/v1/responses requests as Codex CLI.
  # 强制按 Codex CLI 处理 /openai/v1/responses 请求（用于网关未透传/改写 User-Agent 的兜底）。
  #
  # 注意：开启后会影响所有客户端的行为（不仅限于 VS Code / Codex CLI），请谨慎开启。
  force_codex_cli: false
  # Enable Codex image-generation bridge injection for /openai/v1/responses.
  # 是否为 Codex /responses 请求自动注入 image_generation 工具与桥接指令。
  #
  # Default false keeps text-only Codex requests text-only. Explicit client-provided
  # image_generation tools are still forwarded when the group allows image generation.
  # 默认 false：保持纯文本 Codex 请求不被改写；客户端显式提供 image_generation tool 时，
  # 仍会在分组允许图片生成的情况下正常转发。
  codex_image_generation_bridge_enabled: false
  # Optional: template file used to build the final top-level Codex `instructions`.
  # 可选：用于构建最终 Codex 顶层 `instructions` 的模板文件路径。
  #
  # This is applied on the `/v1/messages -> Responses/Codex` conversion path,
  # after Claude `system` has already been normalized into Codex `instructions`.
  # 该模板作用于 `/v1/messages -> Responses/Codex` 转换链路，且发生在 Claude `system`
  # 已经被归一化为 Codex `instructions` 之后。
  #
  # The template can reference:
  # 模板可引用：
  # - {{ .ExistingInstructions }} : converted client instructions/system
  # - {{ .OriginalModel }}        : original requested model
  # - {{ .NormalizedModel }}      : normalized routing model
  # - {{ .BillingModel }}         : billing model
  # - {{ .UpstreamModel }}        : final upstream model
  #
  # If you want to preserve client system prompts, keep {{ .ExistingInstructions }}
  # somewhere in the template. If omitted, the template output fully replaces it.
  # 如需保留客户端 system 提示词，请在模板中显式包含 {{ .ExistingInstructions }}。
  # 若省略，则模板输出会完全覆盖它。
  #
  # Docker users can mount a host file to /app/data/codex-instructions.md.tmpl
  # and point this field there.
  # Docker 用户可将宿主机文件挂载到 /app/data/codex-instructions.md.tmpl，
  # 然后把本字段指向该路径。
  forced_codex_instructions_template_file: ""
  # OpenAI 透传模式是否放行客户端超时头（如 x-stainless-timeout）
  # 默认 false：过滤超时头，降低上游提前断流风险。
  openai_passthrough_allow_timeout_headers: false
  # OpenAI Responses WebSocket 配置（默认开启，可按需回滚到 HTTP）
  openai_ws:
    # 新版 WS mode 路由（默认关闭）。关闭时保持当前 legacy 实现行为。
    mode_router_v2_enabled: false
    # ingress 默认模式：off|ctx_pool|passthrough（仅 mode_router_v2_enabled=true 生效）
    # 兼容旧值：shared/dedicated 会按 ctx_pool 处理。
    ingress_mode_default: ctx_pool
    # 全局总开关，默认 true；关闭时所有请求保持原有 HTTP/SSE 路由
    enabled: true
    # 按账号类型细分开关
    oauth_enabled: true
    apikey_enabled: true
    # 全局强制 HTTP（紧急回滚开关）
    force_http: false
    # 允许在 WSv2 下按策略恢复 store=true（默认 false）
    allow_store_recovery: false
    # ingress 模式收到 previous_response_not_found 时，自动去掉 previous_response_id 重试一次（默认 true）
    ingress_previous_response_recovery_enabled: true
    # store=false 且无可复用会话连接时的策略：
    # strict=强制新建连接（隔离优先），adaptive=仅在高风险失败后强制新建，off=尽量复用（性能优先）
    store_disabled_conn_mode: strict
    # store=false 且无可复用会话连接时，是否强制新建连接（默认 true，优先会话隔离）
    # 兼容旧配置：仅在 store_disabled_conn_mode 未配置时生效
    store_disabled_force_new_conn: true
    # 是否启用 WSv2 generate=false 预热（默认 false）
    prewarm_generate_enabled: false
    # 协议 feature 开关，v2 优先于 v1
    responses_websockets: false
    responses_websockets_v2: true
    # 连接池参数（按账号池化复用）
    max_conns_per_account: 128
    min_idle_per_account: 4
    max_idle_per_account: 12
    # 是否按账号并发动态计算连接池上限：
    # effective_max_conns = min(max_conns_per_account, ceil(account.concurrency * factor))
    dynamic_max_conns_by_account_concurrency_enabled: true
    # 按账号类型分别设置系数（OAuth / API Key）
    oauth_max_conns_factor: 1.0
    apikey_max_conns_factor: 1.0
    dial_timeout_seconds: 10
    read_timeout_seconds: 900
    write_timeout_seconds: 120
    pool_target_utilization: 0.7
    queue_limit_per_conn: 64
    # 流式写出批量 flush 参数
    event_flush_batch_size: 1
    event_flush_interval_ms: 10
    # 预热触发冷却（毫秒）
    prewarm_cooldown_ms: 300
    # WS 回退到 HTTP 后的冷却时间（秒），用于避免 WS/HTTP 来回抖动；0 表示关闭冷却
    fallback_cooldown_seconds: 30
    # WS 重试退避参数（毫秒）
    retry_backoff_initial_ms: 120
    retry_backoff_max_ms: 2000
    # 抖动比例（0-1）
    retry_jitter_ratio: 0.2
    # 单次请求 WS 重试总预算（毫秒）；建议设置为有限值，避免重试拉高 TTFT 长尾
    retry_total_budget_ms: 5000
    # payload_schema 日志采样率（0-1）；降低热路径日志放大
    payload_log_sample_rate: 0.2
    # 调度与粘连参数
    lb_top_k: 7
    sticky_session_ttl_seconds: 3600
    # 会话哈希迁移兼容开关：新 key 未命中时回退读取旧 SHA-256 key
    session_hash_read_old_fallback: true
    # 会话哈希迁移兼容开关：写入时双写旧 SHA-256 key（短 TTL）
    session_hash_dual_write_old: true
    # context 元数据迁移兼容开关：保留旧 ctxkey.* 读取/注入桥接
    metadata_bridge_enabled: true
    sticky_response_id_ttl_seconds: 3600
    # 兼容旧键：当 sticky_response_id_ttl_seconds 缺失时回退该值
    sticky_previous_response_ttl_seconds: 3600
    scheduler_score_weights:
      priority: 1.0
      load: 1.0
      queue: 0.7
      error_rate: 0.8
      ttft: 0.5
  # HTTP upstream connection pool settings (HTTP/2 + multi-proxy scenario defaults)
  # HTTP 上游连接池配置（HTTP/2 + 多代理场景默认值）
  # Max idle connections across all hosts
  # 所有主机的最大空闲连接数
  max_idle_conns: 2560
  # Max idle connections per host
  # 每个主机的最大空闲连接数
  max_idle_conns_per_host: 120
  # Max connections per host
  # 每个主机的最大连接数
  max_conns_per_host: 1024
  # Idle connection timeout (seconds)
  # 空闲连接超时时间（秒）
  idle_conn_timeout_seconds: 90
  # Upstream client cache settings
  # 上游连接池客户端缓存配置
  # max_upstream_clients: Max cached clients, evicts least recently used when exceeded
  # max_upstream_clients: 最大缓存客户端数量，超出后淘汰最久未使用的
  max_upstream_clients: 5000
  # client_idle_ttl_seconds: Client idle reclaim threshold (seconds), reclaimed when idle and no active requests
  # client_idle_ttl_seconds: 客户端空闲回收阈值（秒），超时且无活跃请求时回收
  client_idle_ttl_seconds: 900
  # Concurrency slot expiration time (minutes)
  # 并发槽位过期时间（分钟）
  concurrency_slot_ttl_minutes: 30
  # Stream data interval timeout (seconds), 0=disable
  # 流数据间隔超时（秒），0=禁用
  stream_data_interval_timeout: 180
  # Stream keepalive interval (seconds), 0=disable
  # 流式 keepalive 间隔（秒），0=禁用
  stream_keepalive_interval: 10
  # Image stream data interval timeout (seconds), 0=disable; independent from ordinary text streams
  # 图片流数据间隔超时（秒），0=禁用；独立于普通文本流式
  image_stream_data_interval_timeout: 900
  # Image stream keepalive interval (seconds), 0=disable; independent from ordinary text streams
  # 图片流式 keepalive 间隔（秒），0=禁用；独立于普通文本流式
  image_stream_keepalive_interval: 10
  # Image generation independent concurrency limiter (process-local, default disabled)
  # 图片生成独立并发限制（进程级，默认关闭；多实例总上限约为实例数×该值）
  image_concurrency:
    # Enable image-only concurrency protection; false keeps existing behavior unchanged
    # 是否启用图片独立并发保护；false 保持现有行为不变
    enabled: false
    # Max concurrent image generation requests in this process, 0=unlimited
    # 当前进程允许同时处理的图片生成请求数，0=不限制
    max_concurrent_requests: 0
    # Overflow mode when the image concurrency limit is full: reject/wait
    # 图片并发满时的处理方式：reject=立即拒绝，wait=等待槽位
    overflow_mode: "reject"
    # Wait timeout for overflow_mode=wait (seconds), 0=do not wait
    # wait 模式等待图片并发槽位的超时时间（秒），0=不等待
    wait_timeout_seconds: 30
    # Max image requests waiting in this process when overflow_mode=wait, 0=unlimited
    # wait 模式当前进程允许排队等待的图片请求数，0=不限制
    max_waiting_requests: 100
  # SSE max line size in bytes (default: 40MB)
  # SSE 单行最大字节数（默认 40MB）
  max_line_size: 41943040
  # Log upstream error response body summary (safe/truncated; does not log request content)
  # 记录上游错误响应体摘要（安全/截断；不记录请求内容）
  log_upstream_error_body: true
  # Max bytes to log from upstream error body
  # 记录上游错误响应体的最大字节数
  log_upstream_error_body_max_bytes: 2048
  # Auto inject anthropic-beta header for API-key accounts when needed (default: off)
  # 需要时自动为 API-key 账户注入 anthropic-beta 头（默认：关闭）
  inject_beta_for_apikey: false
  # Allow failover on selected 400 errors (default: off)
  # 允许在特定 400 错误时进行故障转移（默认：关闭）
  failover_on_400: false
  # Scheduling configuration
  # 调度配置
  scheduling:
    # Sticky session max waiting queue size
    # 粘性会话最大排队长度
    sticky_session_max_waiting: 3
    # Sticky session wait timeout (duration)
    # 粘性会话等待超时（时间段）
    sticky_session_wait_timeout: 120s
    # Fallback wait timeout (duration)
    # 兜底排队等待超时（时间段）
    fallback_wait_timeout: 30s
    # Fallback max waiting queue size
    # 兜底最大排队长度
    fallback_max_waiting: 100
    # Enable batch load calculation for scheduling
    # 启用调度批量负载计算
    load_batch_enabled: true
    # Slot cleanup interval (duration)
    # 并发槽位清理周期（时间段）
    slot_cleanup_interval: 30s
    # 是否允许受控回源到 DB（默认 true，保持现有行为）
    db_fallback_enabled: true
    # 受控回源超时（秒），0 表示不额外收紧超时
    db_fallback_timeout_seconds: 0
    # 受控回源限流（实例级 QPS），0 表示不限制
    db_fallback_max_qps: 0
    # outbox 轮询周期（秒）
    outbox_poll_interval_seconds: 1
    # outbox 滞后告警阈值（秒）
    outbox_lag_warn_seconds: 5
    # outbox 触发强制重建阈值（秒）
    outbox_lag_rebuild_seconds: 10
    # outbox 连续滞后触发次数
    outbox_lag_rebuild_failures: 3
    # outbox 积压触发重建阈值（行数）
    outbox_backlog_rebuild_rows: 10000
    # 全量重建周期（秒），0 表示禁用
    full_rebuild_interval_seconds: 300
  # TLS fingerprint simulation / TLS 指纹伪装
  # Default profile "claude_cli_v2" simulates Node.js 20.x
  # 默认模板 "claude_cli_v2" 模拟 Node.js 20.x 指纹
  tls_fingerprint:
    enabled: true
    # profiles:
    #   profile_1:
    #     name: "Custom Profile 1"
    #   profile_2:
    #     name: "Custom Profile 2"

# =============================================================================
# Logging Configuration
# 日志配置
# =============================================================================
log:
  # Log level: debug/info/warn/error
  # 日志级别：debug/info/warn/error
  level: "info"
  # Log format: json/console
  # 日志格式：json/console
  format: "console"
  # Service name field written into each log line
  # 每条日志都会附带 service 字段
  service_name: "sub2api"
  # Environment field written into each log line
  # 每条日志都会附带 env 字段
  env: "production"
  # Include caller information
  # 是否输出调用方位置信息
  caller: true
  # Stacktrace threshold: none/error/fatal
  # 堆栈输出阈值：none/error/fatal
  stacktrace_level: "error"
  output:
    # Keep stdout/stderr output for container log collection
    # 保持标准输出用于容器日志采集
    to_stdout: true
    # Enable file output (default path auto-derived)
    # 启用文件输出（默认路径自动推导）
    to_file: true
    # Empty means:
    # - DATA_DIR set: {{DATA_DIR}}/logs/sub2api.log
    # - otherwise: /app/data/logs/sub2api.log
    # 留空时：
    # - 设置 DATA_DIR：{{DATA_DIR}}/logs/sub2api.log
    # - 否则：/app/data/logs/sub2api.log
    file_path: ""
  rotation:
    # Max file size before rotation (MB)
    # 单文件滚动阈值（MB）
    max_size_mb: 100
    # Number of rotated files to keep (0 means unlimited)
    # 保留历史文件数量（0 表示不限制）
    max_backups: 10
    # Number of days to keep old log files (0 means unlimited)
    # 历史日志保留天数（0 表示不限制）
    max_age_days: 7
    # Compress rotated files
    # 是否压缩历史日志
    compress: true
    # Use local time for timestamp in rotated filename
    # 滚动文件名时间戳使用本地时区
    local_time: true
  sampling:
    # Enable zap sampler (reduce high-frequency repetitive logs)
    # 启用 zap 采样（减少高频重复日志）
    enabled: false
    # Number of first entries per second to always log
    # 每秒无采样保留的前 N 条日志
    initial: 100
    # Thereafter keep 1 out of N entries per second
    # 之后每 N 条保留 1 条
    thereafter: 100

# =============================================================================
# Sora Direct Client Configuration
# Sora 直连配置
# =============================================================================
sora:
  client:
    # Sora backend base URL
    # Sora 上游 Base URL
    base_url: "https://sora.chatgpt.com/backend"
    # Request timeout (seconds)
    # 请求超时（秒）
    timeout_seconds: 120
    # Max retries for upstream requests
    # 上游请求最大重试次数
    max_retries: 3
    # Account+proxy cooldown window after Cloudflare challenge (seconds, 0 to disable)
    # Cloudflare challenge 后按账号+代理冷却窗口（秒，0 表示关闭）
    cloudflare_challenge_cooldown_seconds: 900
    # Poll interval (seconds)
    # 轮询间隔（秒）
    poll_interval_seconds: 2
    # Max poll attempts
    # 最大轮询次数
    max_poll_attempts: 600
    # Recent task query limit (image)
    # 最近任务查询数量（图片轮询）
    recent_task_limit: 50
    # Recent task query max limit (fallback)
    # 最近任务查询最大数量（回退）
    recent_task_limit_max: 200
    # Enable debug logs for Sora upstream requests
    # 启用 Sora 直连调试日志
    # 调试日志会输出上游请求尝试、重试、响应摘要；Authorization/openai-sentinel-token 等敏感头会自动脱敏
    debug: false
    # Allow Sora client to fetch token via OpenAI token provider
    # 是否允许 Sora 客户端通过 OpenAI token provider 取 token（默认 false，避免误走 OpenAI 刷新链路）
    use_openai_token_provider: false
    # Optional custom headers (key-value)
    # 额外请求头（键值对）
    headers: {}
    # Default User-Agent for Sora requests
    # Sora 默认 User-Agent
    user_agent: "Sora/1.2026.007 (Android 15; 24122RKC7C; build 2600700)"
    # Disable TLS fingerprint for Sora upstream
    # 关闭 Sora 上游 TLS 指纹伪装
    disable_tls_fingerprint: false
    # curl_cffi sidecar for Sora only (required)
    # 仅 Sora 链路使用的 curl_cffi sidecar（必需）
    curl_cffi_sidecar:
      # Sora 强制通过 sidecar 请求，必须启用
      # Sora is forced to use sidecar only; keep enabled=true
      enabled: true
      # Sidecar base URL (default endpoint: /request)
      # sidecar 基础地址（默认请求端点：/request）
      base_url: "http://sora-curl-cffi-sidecar:8080"
      # curl_cffi impersonate profile, e.g. chrome131/chrome124/safari18_0
      # curl_cffi 指纹伪装 profile，例如 chrome131/chrome124/safari18_0
      impersonate: "chrome131"
      # Sidecar request timeout (seconds)
      # sidecar 请求超时（秒）
      timeout_seconds: 60
      # Reuse session key per account+proxy to let sidecar persist cookies/session
      # 按账号+代理复用 session key，让 sidecar 持久化 cookies/session
      session_reuse_enabled: true
      # Session TTL in sidecar (seconds)
      # sidecar 会话 TTL（秒）
      session_ttl_seconds: 3600
  storage:
    # Storage type (local only for now)
    # 存储类型（首发仅支持 local）
    type: "local"
    # Local base path; empty uses /app/data/sora
    # 本地存储基础路径；为空使用 /app/data/sora
    local_path: ""
    # Fallback to upstream URL when download fails
    # 下载失败时回退到上游 URL
    fallback_to_upstream: true
    # Max concurrent downloads
    # 并发下载上限
    max_concurrent_downloads: 4
    # Download timeout (seconds)
    # 下载超时（秒）
    download_timeout_seconds: 120
    # Max download bytes
    # 最大下载字节数
    max_download_bytes: 209715200
    # Enable debug logs for media storage
    # 启用媒体存储调试日志
    debug: false
    cleanup:
      # Enable cleanup task
      # 启用清理任务
      enabled: true
      # Retention days
      # 保留天数
      retention_days: 7
      # Cron schedule
      # Cron 调度表达式
      schedule: "0 3 * * *"

# Token refresh behavior
# token 刷新行为控制
token_refresh:
  # Whether OpenAI refresh flow is allowed to sync linked Sora accounts
  # 是否允许 OpenAI 刷新流程同步覆盖 linked_openai_account_id 关联的 Sora 账号 token
  sync_linked_sora_accounts: false

# =============================================================================
# API Key Auth Cache Configuration
# API Key 认证缓存配置
# =============================================================================
api_key_auth_cache:
  # L1 cache size (entries), in-process LRU/TTL cache
  # L1 缓存容量（条目数），进程内 LRU/TTL 缓存
  l1_size: 65535
  # L1 cache TTL (seconds)
  # L1 缓存 TTL（秒）
  l1_ttl_seconds: 15
  # L2 cache TTL (seconds), stored in Redis
  # L2 缓存 TTL（秒），Redis 中存储
  l2_ttl_seconds: 300
  # Negative cache TTL (seconds)
  # 负缓存 TTL（秒）
  negative_ttl_seconds: 30
  # TTL jitter percent (0-100)
  # TTL 抖动百分比（0-100）
  jitter_percent: 10
  # Enable singleflight for cache misses
  # 缓存未命中时启用 singleflight 合并回源
  singleflight: true

# =============================================================================
# Dashboard Cache Configuration
# 仪表盘缓存配置
# =============================================================================
dashboard_cache:
  # Enable dashboard cache
  # 启用仪表盘缓存
  enabled: true
  # Redis key prefix for multi-environment isolation
  # Redis key 前缀，用于多环境隔离
  key_prefix: "sub2api:"
  # Fresh TTL (seconds); within this window cached stats are considered fresh
  # 新鲜阈值（秒）；命中后处于该窗口视为新鲜数据
  stats_fresh_ttl_seconds: 15
  # Cache TTL (seconds) stored in Redis
  # Redis 缓存 TTL（秒）
  stats_ttl_seconds: 30
  # Async refresh timeout (seconds)
  # 异步刷新超时（秒）
  stats_refresh_timeout_seconds: 30

# =============================================================================
# Dashboard Aggregation Configuration
# 仪表盘预聚合配置（重启生效）
# =============================================================================
dashboard_aggregation:
  # Enable aggregation job
  # 启用聚合作业
  enabled: true
  # Refresh interval (seconds)
  # 刷新间隔（秒）
  interval_seconds: 60
  # Lookback window (seconds) for late-arriving data
  # 回看窗口（秒），处理迟到数据
  lookback_seconds: 120
  # Allow manual backfill
  # 允许手动回填
  backfill_enabled: false
  # Backfill max range (days)
  # 回填最大跨度（天）
  backfill_max_days: 31
  # Recompute recent N days on startup
  # 启动时重算最近 N 天
  recompute_days: 2
  # Retention windows (days)
  # 保留窗口（天）
  retention:
    # Raw usage_logs retention
    # 原始 usage_logs 保留天数
    usage_logs_days: 90
    # Hourly aggregation retention
    # 小时聚合保留天数
    hourly_days: 180
    # Daily aggregation retention
    # 日聚合保留天数
    daily_days: 730

# =============================================================================
# Usage Cleanup Task Configuration
# 使用记录清理任务配置（重启生效）
# =============================================================================
usage_cleanup:
  # Enable cleanup task worker
  # 启用清理任务执行器
  enabled: true
  # Max date range (days) per task
  # 单次任务最大时间跨度（天）
  max_range_days: 31
  # Batch delete size
  # 单批删除数量
  batch_size: 5000
  # Worker interval (seconds)
  # 执行器轮询间隔（秒）
  worker_interval_seconds: 10
  # Task execution timeout (seconds)
  # 单次任务最大执行时长（秒）
  task_timeout_seconds: 1800

# =============================================================================
# HTTP 写接口幂等配置
# Idempotency Configuration
# =============================================================================
idempotency:
  # Observe-only 模式：
  # true: 观察期，不带 Idempotency-Key 仍放行（但会记录）
  # false: 强制期，不带 Idempotency-Key 直接拒绝（仅对接入幂等保护的接口生效）
  observe_only: true
  # 关键写接口幂等记录 TTL（秒）
  default_ttl_seconds: 86400
  # 系统操作接口（update/rollback/restart）幂等记录 TTL（秒）
  system_operation_ttl_seconds: 3600
  # processing 锁超时（秒）
  processing_timeout_seconds: 30
  # 可重试失败退避窗口（秒）
  failed_retry_backoff_seconds: 5
  # 持久化响应体最大长度（字节）
  max_stored_response_len: 65536
  # 过期幂等记录清理周期（秒）
  cleanup_interval_seconds: 60
  # 每轮清理最大删除条数
  cleanup_batch_size: 500

# =============================================================================
# Concurrency Wait Configuration
# 并发等待配置
# =============================================================================
concurrency:
  # SSE ping interval during concurrency wait (seconds)
  # 并发等待期间的 SSE ping 间隔（秒）
  ping_interval: 10

# =============================================================================
# Database Configuration (PostgreSQL)
# 数据库配置 (PostgreSQL)
# =============================================================================
database:
  # Database host address
  # 数据库主机地址
  host: "localhost"
  # Database port
  # 数据库端口
  port: 5432
  # Database username
  # 数据库用户名
  user: "postgres"
  # Database password
  # 数据库密码
  password: "your_secure_password_here"
  # Database name
  # 数据库名称
  dbname: "sub2api"
  # SSL mode: disable, prefer, require, verify-ca, verify-full
  # SSL 模式：disable（禁用）, prefer（优先加密，默认）, require（要求）, verify-ca（验证CA）, verify-full（完全验证）
  # 默认值为 "prefer"，数据库支持 SSL 时自动使用加密连接，不支持时回退明文
  sslmode: "prefer"
  # Max open connections (高并发场景建议 256+，需配合 PostgreSQL max_connections 调整)
  # 最大打开连接数
  max_open_conns: 256
  # Max idle connections (建议为 max_open_conns 的 50%，减少频繁建连开销)
  # 最大空闲连接数
  max_idle_conns: 128
  # Connection max lifetime (minutes)
  # 连接最大存活时间（分钟）
  conn_max_lifetime_minutes: 30
  # Connection max idle time (minutes)
  # 空闲连接最大存活时间（分钟）
  conn_max_idle_time_minutes: 5

# =============================================================================
# Redis Configuration
# Redis 配置
# =============================================================================
redis:
  # Redis host address
  # Redis 主机地址
  host: "localhost"
  # Redis port
  # Redis 端口
  port: 6379
  # Redis password (leave empty if no password is set)
  # Redis 密码（如果未设置密码则留空）
  password: ""
  # Database number (0-15)
  # 数据库编号（0-15）
  db: 0
  # Connection pool size (max concurrent connections)
  # 连接池大小（最大并发连接数）
  pool_size: 1024
  # Minimum number of idle connections (高并发场景建议 128+，保持足够热连接)
  # 最小空闲连接数
  min_idle_conns: 128
  # Enable TLS/SSL connection
  # 是否启用 TLS/SSL 连接
  enable_tls: false

# =============================================================================
# Ops Monitoring (Optional)
# 运维监控 (可选)
# =============================================================================
ops:
  # Enable ops monitoring features (background jobs and APIs)
  # 是否启用运维监控功能（后台任务和接口）
  # Set to false to hide ops menu in sidebar and disable all ops features
  # 设置为 false 可在左侧栏隐藏运维监控菜单并禁用所有运维监控功能
  # Other detailed settings (cleanup, aggregation, etc.) are configured in ops settings dialog
  # 其他详细设置（数据清理、预聚合等）在运维监控设置对话框中配置
  enabled: true

# =============================================================================
# JWT Configuration
# JWT 配置
# =============================================================================
jwt:
  # IMPORTANT: Change this to a random string in production!
  # 重要：生产环境中请更改为随机字符串！
  # Generate with / 生成命令: openssl rand -hex 32
  secret: "change-this-to-a-secure-random-string"
  # Token expiration time in hours (max 168)
  # 令牌过期时间（小时，最大 168）
  expire_hour: 24
  # Access Token 过期时间（分钟）
  # 优先级说明：
  # - >0: 按分钟生效（优先于 expire_hour）
  # - =0: 回退使用 expire_hour
  access_token_expire_minutes: 0

# =============================================================================
# TOTP (2FA) Configuration
# TOTP 双因素认证配置
# =============================================================================
totp:
  # IMPORTANT: Set a fixed encryption key for TOTP secrets.
  # 重要：设置固定的 TOTP 加密密钥。
  # If left empty, a random key will be generated on each startup, causing all
  # existing TOTP configurations to become invalid (users won't be able to
  # login with 2FA).
  # 如果留空，每次启动将生成随机密钥，导致现有的 TOTP 配置失效（用户无法使用
  # 双因素认证登录）。
  # Generate with / 生成命令: openssl rand -hex 32
  encryption_key: ""

# =============================================================================
# LinuxDo Connect OAuth Login (SSO)
# LinuxDo Connect OAuth 登录（用于 Sub2API 用户登录）
# =============================================================================
linuxdo_connect:
  enabled: false
  client_id: ""
  client_secret: ""
  authorize_url: "https://connect.linux.do/oauth2/authorize"
  token_url: "https://connect.linux.do/oauth2/token"
  userinfo_url: "https://connect.linux.do/api/user"
  scopes: "user"
  # 示例: "https://your-domain.com/api/v1/auth/oauth/linuxdo/callback"
  redirect_url: ""
  # 安全提示：
  # - 建议使用同源相对路径（以 / 开头），避免把 token 重定向到意外的第三方域名
  # - 该地址不应包含 #fragment（本实现使用 URL fragment 传递 access_token）
  frontend_redirect_url: "/auth/linuxdo/callback"
  token_auth_method: "client_secret_post" # client_secret_post | client_secret_basic | none
  # 注意：当 token_auth_method=none（public client）时，必须启用 PKCE
  use_pkce: true
  userinfo_email_path: ""
  userinfo_id_path: ""
  userinfo_username_path: ""

# =============================================================================
# Generic OIDC OAuth Login (SSO)
# 通用 OIDC OAuth 登录（用于 Sub2API 用户登录）
# =============================================================================
oidc_connect:
  enabled: false
  provider_name: "OIDC"
  client_id: ""
  client_secret: ""
  # 例如: "https://keycloak.example.com/realms/myrealm"
  issuer_url: ""
  # 可选: OIDC Discovery URL。为空时可手动填写 authorize/token/userinfo/jwks
  discovery_url: ""
  authorize_url: ""
  token_url: ""
  # 可选（仅补充 email/username，不用于 sub 可信绑定）
  userinfo_url: ""
  # validate_id_token=true 时必填
  jwks_url: ""
  scopes: "openid email profile"
  # 示例: "https://your-domain.com/api/v1/auth/oauth/oidc/callback"
  redirect_url: ""
  # 安全提示：
  # - 建议使用同源相对路径（以 / 开头），避免把 token 重定向到意外的第三方域名
  # - 该地址不应包含 #fragment（本实现使用 URL fragment 传递 access_token）
  frontend_redirect_url: "/auth/oidc/callback"
  token_auth_method: "client_secret_post" # client_secret_post | client_secret_basic | none
  # 注意：当 token_auth_method=none（public client）时，必须启用 PKCE
  use_pkce: false
  # 开启后强制校验 id_token 的签名和 claims（推荐）
  validate_id_token: true
  allowed_signing_algs: "RS256,ES256,PS256"
  # 允许的时钟偏移（秒）
  clock_skew_seconds: 120
  # 若 Provider 返回 email_verified=false，是否拒绝登录
  require_email_verified: false
  userinfo_email_path: ""
  userinfo_id_path: ""
  userinfo_username_path: ""

# =============================================================================
# Default Settings
# 默认设置
# =============================================================================
default:
  # Initial admin account (created on first run)
  # 初始管理员账户（首次运行时创建）
  admin_email: "admin@example.com"
  admin_password: "admin123"

  # Default settings for new users
  # 新用户默认设置
  # Max concurrent requests per user
  # 每用户最大并发请求数
  user_concurrency: 5
  # Initial balance for new users
  # 新用户初始余额
  user_balance: 0

  # API key settings
  # API 密钥设置
  # Prefix for generated API keys
  # 生成的 API 密钥前缀
  api_key_prefix: "sk-"

  # Rate multiplier (affects billing calculation)
  # 费率倍数（影响计费计算）
  rate_multiplier: 1.0

# =============================================================================
# Rate Limiting
# 速率限制
# =============================================================================
rate_limit:
  # Cooldown time (in minutes) when upstream returns 529 (overloaded)
  # 上游返回 529（过载）时的冷却时间（分钟）
  overload_cooldown_minutes: 10

# =============================================================================
# Pricing Data Source (Optional)
# 定价数据源（可选）
# =============================================================================
pricing:
  # URL to fetch model pricing data (default: pinned model-price-repo commit)
  # 获取模型定价数据的 URL（默认：固定 commit 的 model-price-repo）
  remote_url: "https://raw.githubusercontent.com/Wei-Shaw/model-price-repo/refs/heads/main//model_prices_and_context_window.json"
  # Hash verification URL (optional)
  # 哈希校验 URL（可选）
  hash_url: "https://raw.githubusercontent.com/Wei-Shaw/model-price-repo/refs/heads/main//model_prices_and_context_window.sha256"
  # Local data directory for caching
  # 本地数据缓存目录
  data_dir: "./data"
  # Fallback pricing file
  # 备用定价文件
  fallback_file: "./resources/model-pricing/model_prices_and_context_window.json"
  # Update interval in hours
  # 更新间隔（小时）
  update_interval_hours: 24
  # Hash check interval in minutes
  # 哈希检查间隔（分钟）
  hash_check_interval_minutes: 10

# =============================================================================
# Billing Configuration
# 计费配置
# =============================================================================
billing:
  circuit_breaker:
    # Enable circuit breaker for billing service
    # 启用计费服务熔断器
    enabled: true
    # Number of failures before opening circuit
    # 触发熔断的失败次数阈值
    failure_threshold: 5
    # Time to wait before attempting reset (seconds)
    # 熔断后重试等待时间（秒）
    reset_timeout_seconds: 30
    # Number of requests to allow in half-open state
    # 半开状态允许通过的请求数
    half_open_requests: 3

# =============================================================================
# Turnstile Configuration
# Turnstile 人机验证配置
# =============================================================================
turnstile:
  # Require Turnstile in release mode (when enabled, login/register will fail if not configured)
  # 在 release 模式下要求 Turnstile 验证（启用后，若未配置则登录/注册会失败）
  required: false

# =============================================================================
# Gemini OAuth (Required for Gemini accounts)
# Gemini OAuth 配置（Gemini 账户必需）
# =============================================================================
# Sub2API supports TWO Gemini OAuth modes:
# Sub2API 支持两种 Gemini OAuth 模式：
#
# 1. Code Assist OAuth (requires GCP project_id)
# 1. Code Assist OAuth（需要 GCP project_id）
#    - Uses: cloudcode-pa.googleapis.com (Code Assist API)
#    - 使用：cloudcode-pa.googleapis.com（Code Assist API）
#
# 2. AI Studio OAuth (no project_id needed)
# 2. AI Studio OAuth（不需要 project_id）
#    - Uses: generativelanguage.googleapis.com (AI Studio API)
#    - 使用：generativelanguage.googleapis.com（AI Studio API）
#
# Default: Uses Gemini CLI's public OAuth credentials (same as Google's official CLI tool)
# 默认：使用 Gemini CLI 的公开 OAuth 凭证（与 Google 官方 CLI 工具相同）
gemini:
  oauth:
    # OAuth 客户端配置说明：
    # 1) 留空 client_id/client_secret：使用 Gemini CLI 内置 OAuth Client（其 client_secret 需通过环境变量注入）
    #    - GEMINI_CLI_OAUTH_CLIENT_SECRET
    # 2) 同时设置 client_id/client_secret：使用你自建的 OAuth Client（推荐，权限更完整）
    #
    # 注意：client_id 与 client_secret 必须同时为空或同时非空。
    client_id: ""
    client_secret: ""
    # Optional scopes (space-separated). Leave empty to auto-select based on oauth_type.
    # 可选的权限范围（空格分隔）。留空则根据 oauth_type 自动选择。
    scopes: ""
  quota:
    # Optional: local quota simulation for Gemini Code Assist (local billing).
    # 可选：Gemini Code Assist 本地配额模拟（本地计费）。
    # These values are used for UI progress + precheck scheduling, not official Google quotas.
    # 这些值用于 UI 进度显示和预检调度，并非 Google 官方配额。
    tiers:
      LEGACY:
        # Pro model requests per day
        # Pro 模型每日请求数
        pro_rpd: 50
        # Flash model requests per day
        # Flash 模型每日请求数
        flash_rpd: 1500
        # Cooldown time (minutes) after hitting quota
        # 达到配额后的冷却时间（分钟）
        cooldown_minutes: 30
      PRO:
        # Pro model requests per day
        # Pro 模型每日请求数
        pro_rpd: 1500
        # Flash model requests per day
        # Flash 模型每日请求数
        flash_rpd: 4000
        # Cooldown time (minutes) after hitting quota
        # 达到配额后的冷却时间（分钟）
        cooldown_minutes: 5
      ULTRA:
        # Pro model requests per day
        # Pro 模型每日请求数
        pro_rpd: 2000
        # Flash model requests per day (0 = unlimited)
        # Flash 模型每日请求数（0 = 无限制）
        flash_rpd: 0
        # Cooldown time (minutes) after hitting quota
        # 达到配额后的冷却时间（分钟）
        cooldown_minutes: 5

# =============================================================================
# Update Configuration (在线更新配置)
# =============================================================================
update:
  # Proxy URL for accessing GitHub (used for online updates and pricing data)
  # 用于访问 GitHub 的代理地址（用于在线更新和定价数据获取）
  # Supports: http, https, socks5, socks5h
  # Examples:
  #   - HTTP proxy: "http://127.0.0.1:7890"
  #   - SOCKS5 proxy: "socks5://127.0.0.1:1080"
  #   - With authentication: "http://user:pass@proxy.example.com:8080"
  # Leave empty for direct connection (recommended for overseas servers)
  # 留空表示直连（适用于海外服务器）
  proxy_url: ""
