-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathschema.py
More file actions
354 lines (318 loc) · 13.2 KB
/
Copy pathschema.py
File metadata and controls
354 lines (318 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
"""Pydantic 配置模型 — 聚合层(re-export 所有子模块符号).
本文件为向后兼容的聚合入口点,所有配置模型已正交拆分至以下子模块:
- :mod:`.server` – ServerConfig / DatabaseConfig / LoggingConfig
- :mod:`.vendors` – AnthropicConfig / CopilotConfig / AntigravityConfig / ZhipuConfig
- :mod:`.resiliency` – CircuitBreakerConfig / RetryConfig / FailoverConfig / QuotaGuardConfig
- :mod:`.routing` – VendorType / VendorConfig / ModelMappingRule / ModelPricingEntry
- :mod:`.auth_schema` – AuthConfig
:py:class:`ProxyConfig` 及其旧格式迁移逻辑保留在此文件中。
"""
from __future__ import annotations
import logging
from pathlib import Path
from typing import Any
from pydantic import BaseModel, Field, model_validator
from ..native_api.config import NativeApiConfig # noqa: F401
from .auth_schema import AuthConfig # noqa: F401
from .resiliency import ( # noqa: F401
CircuitBreakerConfig,
FailoverConfig,
QuotaGuardConfig,
RetryConfig,
)
from .routing import ( # noqa: F401
_ANTIGRAVITY_FIELDS,
_BACKEND_EXCLUSIVE_FIELDS, # 向后兼容别名
_COPILOT_FIELDS,
_NATIVE_ANTHROPIC_FIELDS,
_VENDOR_EXCLUSIVE_FIELDS,
_ZHIPU_FIELDS,
BackendType, # 向后兼容别名
ModelMappingRule,
ModelPricingEntry,
TierConfig, # 向后兼容别名
VendorConfig,
VendorType,
)
# ── 子模块 re-export ────────────────────────────────────────────
from .server import DatabaseConfig, LoggingConfig, ServerConfig # noqa: F401
from .session_policy import SessionPoliciesConfig, TitleVendorBinding # noqa: F401
from .vendors import ( # noqa: F401
AlibabaConfig,
AnthropicConfig,
AntigravityConfig,
CopilotConfig,
DoubaoConfig,
KimiConfig,
MinimaxConfig,
XiaomiConfig,
ZhipuConcurrencyConfig,
ZhipuConfig,
)
logger = logging.getLogger(__name__)
class ProxyConfig(BaseModel):
"""顶层配置模型.
.. note::
以下字段为 **旧 flat 格式**(已废弃,保留仅用于向后兼容迁移):
``primary``, ``copilot``, ``antigravity``, ``fallback``,
``circuit_breaker``, ``copilot_circuit_breaker``, ``antigravity_circuit_breaker``,
``quota_guard``, ``copilot_quota_guard``, ``antigravity_quota_guard``
新配置应使用 ``vendors`` 列表格式(参见 config.default.yaml)。
旧格式会在 ``_migrate_legacy_fields`` 中自动转换为 vendors。
"""
server: ServerConfig = ServerConfig()
# ── Legacy 字段(旧 flat 格式,由 _migrate_legacy_fields 自动迁移至 vendors) ──
primary: AnthropicConfig = Field(
default=AnthropicConfig(),
description="[legacy] Anthropic 主供应商配置;新格式请使用 vendors[].vendor=anthropic",
)
copilot: CopilotConfig = Field(
default=CopilotConfig(),
description="[legacy] Copilot 供应商配置;新格式请使用 vendors[].vendor=copilot",
)
antigravity: AntigravityConfig = Field(
default=AntigravityConfig(),
description="[legacy] Antigravity 供应商配置;新格式请使用 vendors[].vendor=antigravity",
)
fallback: ZhipuConfig = Field(
default=ZhipuConfig(),
description="[legacy] 智谱兜底供应商配置;新格式请使用 vendors[].vendor=zhipu",
)
circuit_breaker: CircuitBreakerConfig = Field(
default=CircuitBreakerConfig(),
description="[legacy] 全局熔断器配置;新格式请使用 vendors[].circuit_breaker",
)
copilot_circuit_breaker: CircuitBreakerConfig = Field(
default=CircuitBreakerConfig(),
description="[legacy] Copilot 熔断器配置;新格式请使用 vendors[vendor=copilot].circuit_breaker",
)
antigravity_circuit_breaker: CircuitBreakerConfig = Field(
default=CircuitBreakerConfig(),
description="[legacy] Antigravity 熔断器配置;新格式请使用 vendors[vendor=antigravity].circuit_breaker",
)
failover: FailoverConfig = FailoverConfig()
model_mapping: list[ModelMappingRule] = Field(
default=[
ModelMappingRule(
pattern="claude-sonnet-.*", target="glm-5.1", is_regex=True
),
ModelMappingRule(pattern="claude-opus-.*", target="glm-5.1", is_regex=True),
ModelMappingRule(
pattern="claude-haiku-.*", target="glm-4.5-air", is_regex=True
),
ModelMappingRule(pattern="claude-.*", target="glm-5.1", is_regex=True),
],
)
quota_guard: QuotaGuardConfig = Field(
default=QuotaGuardConfig(),
description="[legacy] 全局配额守卫;新格式请使用 vendors[].quota_guard",
)
copilot_quota_guard: QuotaGuardConfig = Field(
default=QuotaGuardConfig(),
description="[legacy] Copilot 配额守卫;新格式请使用 vendors[vendor=copilot].quota_guard",
)
antigravity_quota_guard: QuotaGuardConfig = Field(
default=QuotaGuardConfig(),
description="[legacy] Antigravity 配额守卫;新格式请使用 vendors[vendor=antigravity].quota_guard",
)
auth: AuthConfig = AuthConfig()
database: DatabaseConfig = DatabaseConfig()
logging: LoggingConfig = LoggingConfig()
# 模型定价(USD / 1M tokens),按 (vendor, model) 匹配
pricing: list[ModelPricingEntry] = Field(default_factory=list)
# 新格式:vendors 列表(供应商定义)
vendors: list[VendorConfig] = Field(default_factory=list)
# 降级链路优先级(可选);None 时回退到 vendors 列表顺序
tiers: list[VendorType] | None = Field(
default=None,
description=(
"显式指定降级链路的优先级顺序(索引越小优先级越高)。"
"引用的 vendor 必须在 vendors 中存在且 enabled=True。"
"未配置时回退到 vendors 列表原始顺序。"
),
)
# 原生 LLM API 透传通道 — 与 /v1/messages(Claude Code)链路正交
native_api: NativeApiConfig = Field(
default_factory=NativeApiConfig,
description=(
"OpenAI / Gemini / Anthropic 原生 API 透传配置。"
"三个 provider 默认 enabled=False,显式启用才暴露 /api/{provider}/* 端点。"
),
)
# Session 级别路由策略
session_policies: SessionPoliciesConfig = Field(
default_factory=SessionPoliciesConfig,
description=(
"Session 级别的路由策略配置。"
"可为特定 Session 或客户端类别定制 vendor 优先级顺序。"
),
)
@model_validator(mode="before")
@classmethod
def _migrate_legacy_fields(cls, data: Any) -> Any:
"""向后兼容迁移(legacy flat 格式 → vendors 列表格式)+ session_policies 规范化.
迁移规则:
1. ``anthropic`` / ``zhipu`` 字段名自动映射为 ``primary`` / ``fallback``
2. 若配置中未显式指定 ``vendors``,则从旧 flat 格式字段自动生成
"""
if not isinstance(data, dict):
return data
# session_policies 规范化:YAML 中 session_policies: [] 解析为 list,
# 需转为 dict 包装以匹配 SessionPoliciesConfig 模型
sp = data.get("session_policies")
if isinstance(sp, list):
data["session_policies"] = {"policies": sp}
# 1. 字段别名迁移
if "anthropic" in data and "primary" not in data:
data["primary"] = data.pop("anthropic")
if "zhipu" in data and "fallback" not in data:
data["fallback"] = data.pop("zhipu")
# 2. 若已有 vendors 配置则直接使用,跳过自动迁移
# 同时支持旧的 tiers 字段名(向后兼容 YAML)
# 使用 key 存在性检测(而非真值检测),以正确处理 vendors: [] 等显式空配置
if "vendors" in data or "tiers" in data:
# 如果用户使用了旧的 tiers 字段名但实际是 vendor 定义列表,重映射
if (
"tiers" in data
and "vendors" not in data
and isinstance(data["tiers"], list)
):
# 检测是否为新格式的 vendor 定义列表(每项有 vendor 字段,兼容旧 backend 字段)
first_item = data["tiers"][0] if data["tiers"] else {}
if isinstance(first_item, dict) and (
"vendor" in first_item or "backend" in first_item
):
data["vendors"] = data.pop("tiers")
return data
# 3. 从旧 flat 格式自动构建 vendors(触发时记录废弃日志)
vendors: list[dict[str, Any]] = []
_legacy_keys = {
"primary",
"copilot",
"antigravity",
"fallback",
"circuit_breaker",
"copilot_circuit_breaker",
"antigravity_circuit_breaker",
"quota_guard",
"copilot_quota_guard",
"antigravity_quota_guard",
}
if any(k in data for k in _legacy_keys):
logger.info(
"检测到旧 flat 格式配置字段,已自动迁移至 vendors 列表格式。"
"建议迁移至 config.default.yaml 中的 vendors 新格式。",
)
primary = data.get("primary") or {}
if primary.get("enabled", True):
vendor_cfg: dict[str, Any] = {"vendor": "anthropic", **primary}
cb = data.get("circuit_breaker")
if cb:
vendor_cfg["circuit_breaker"] = cb
qg = data.get("quota_guard")
if qg:
vendor_cfg["quota_guard"] = qg
vendors.append(vendor_cfg)
copilot = data.get("copilot") or {}
if copilot.get("enabled", False):
vendor_cfg = {"vendor": "copilot", **copilot}
cb = data.get("copilot_circuit_breaker")
if cb:
vendor_cfg["circuit_breaker"] = cb
qg = data.get("copilot_quota_guard")
if qg:
vendor_cfg["quota_guard"] = qg
vendors.append(vendor_cfg)
antigravity = data.get("antigravity") or {}
if antigravity.get("enabled", False):
vendor_cfg = {"vendor": "antigravity", **antigravity}
cb = data.get("antigravity_circuit_breaker")
if cb:
vendor_cfg["circuit_breaker"] = cb
qg = data.get("antigravity_quota_guard")
if qg:
vendor_cfg["quota_guard"] = qg
vendors.append(vendor_cfg)
fallback = data.get("fallback") or {}
if fallback.get("enabled", True):
# 终端层:不设置 circuit_breaker
vendors.append({"vendor": "zhipu", **fallback})
data["vendors"] = vendors
return data
@model_validator(mode="after")
def _validate_tiers(self) -> ProxyConfig:
"""校验 tiers 引用的 vendor 必须在 enabled vendors 中存在."""
if self.tiers is None:
return self # 未配置,跳过校验
# 构建 enabled vendor 的 name 集合
enabled_vendors = {v.vendor for v in self.vendors if v.enabled}
# 检查重复
seen: set[str] = set()
for name in self.tiers:
if name in seen:
raise ValueError(f"tiers 包含重复的 vendor 名称: {name!r}")
seen.add(name)
# 检查引用是否存在
all_vendors = {v.vendor for v in self.vendors}
if name not in all_vendors:
raise ValueError(
f"tiers 引用了不存在的 vendor: {name!r}。"
f"可用的 vendor: {sorted(all_vendors)}"
)
# 存在但 disabled → warning
if name not in enabled_vendors:
logger.warning(
"tiers 引用了 disabled 的 vendor: %s,该层级将在运行时被跳过",
name,
)
return self
@property
def db_path(self) -> Path:
return Path(self.database.path).expanduser()
@property
def compat_state_path(self) -> Path:
return Path(self.database.compat_state_path).expanduser()
__all__ = [
"ProxyConfig",
# server
"ServerConfig",
"DatabaseConfig",
"LoggingConfig",
# vendors
"AnthropicConfig",
"CopilotConfig",
"AntigravityConfig",
"ZhipuConfig",
"ZhipuConcurrencyConfig",
# resiliency
"CircuitBreakerConfig",
"RetryConfig",
"FailoverConfig",
"QuotaGuardConfig",
# routing
"VendorType",
"VendorConfig",
"ModelMappingRule",
"ModelPricingEntry",
"TierConfig", # 向后兼容别名
"BackendType", # 向后兼容别名
"_COPILOT_FIELDS",
"_ANTIGRAVITY_FIELDS",
"_ZHIPU_FIELDS",
"_NATIVE_ANTHROPIC_FIELDS",
"_VENDOR_EXCLUSIVE_FIELDS",
"_BACKEND_EXCLUSIVE_FIELDS",
# auth
"AuthConfig",
# new native anthropic vendor configs
"MinimaxConfig",
"KimiConfig",
"DoubaoConfig",
"XiaomiConfig",
"AlibabaConfig",
# native api passthrough
"NativeApiConfig",
# session policy
"SessionPoliciesConfig",
"TitleVendorBinding",
]