feat: let a source name its reasoning tier, and say so when it contradicts itself

This commit is contained in:
2026-09-05 01:56:24 -04:00
parent ed563b9ca0
commit 603a835f60
4 changed files with 178 additions and 0 deletions
+26
View File
@@ -22,6 +22,7 @@ from loguru import logger
from polygateway.types import (
BackpressurePolicy,
BreakerConfig,
Effort,
GlobalLimits,
RetryPolicy,
SourceConfig,
@@ -43,6 +44,10 @@ _SOURCE_FIELDS: dict[str, tuple[str, str]] = {
"TTFT_TIMEOUT_S": ("ttft_timeout_s", "float"),
"INTER_TOKEN_TIMEOUT_S": ("inter_token_timeout_s", "float"),
"ENABLE_THINKING": ("enable_thinking", "bool"),
# 档位两键(issue #20);值域校验分工: 档位在此(解析即校验,报错点得出 env 键名),
# fallback 交给 SourceConfig 构造期(那道同时覆盖构造函数注入与 dataclasses.replace)
"REASONING_EFFORT": ("reasoning_effort", "effort"),
"EFFORT_FALLBACK": ("effort_fallback", "str"),
"MISSING_DONE": ("missing_done", "str"),
"TRUST_ENV": ("trust_env", "bool"),
"EXTRA_BODY": ("extra_body", "json"),
@@ -93,6 +98,8 @@ def _cast(raw: str, kind: str, key: str) -> object:
if lowered in ("0", "false", "no", "off"):
return False
raise ValueError(f"非法布尔值: {raw!r}")
if kind == "effort":
return _to_effort(raw)
if kind == "json":
# JSONDecodeError 是 ValueError 子类,复用下方的统一包装
parsed = json.loads(raw)
@@ -104,6 +111,25 @@ def _cast(raw: str, kind: str, key: str) -> object:
raise ValueError(f"配置 {key} 解析失败: {exc}") from exc
def _to_effort(raw: str) -> Effort:
"""把 env 字符串解成 `Effort`;越界时报错并**列出全部八档**。
列全八档不是啰嗦: 档位词汇是封闭的,而下游会照着别处的习惯写
(`lowest`/`off`/`disabled` 都出现过),只说"非法值"等于让人去翻源码。
`strip().lower()` 与 `bool` 分支同一先例: `.env` 里的行尾空格与大写写法
是常态,而档位取值本身没有大小写语义(`Effort` 的值全小写)。
"""
try:
return Effort(raw.strip().lower())
except ValueError:
# 不 `from exc`: 枚举原生的 "'lowest' is not a valid Effort" 只是同一
# 件事的英文复述,链上去反而把可操作的那句挤到后面
raise ValueError(
f"非法推理档位 {raw!r};允许: {', '.join(e.value for e in Effort)}"
) from None
def _first(env: Mapping[str, str], *keys: str) -> tuple[str, str] | None:
for key in keys:
raw = env.get(key)