fix: read a tier the way every config path actually spells it

Both public assembly paths took the tier on trust: a bare "none" from
JSON or a hand-built SourceConfig stayed a str, and `is Effort.NONE`
then read it as a contradiction and crashed on `.value` while wording
the error -- the caller got an AttributeError where a ValueError was
promised, and on the request side that unclassified exception walked
straight through the transport's ThinkingUnsupportedError catch and the
retry classifier.

Normalize at the two entrances instead, matching what the .env path has
always done, and let EFFORT_FALLBACK be spelled with the same freedom as
its neighbour.
This commit is contained in:
2026-09-05 04:07:06 -04:00
parent 701a8a6841
commit 1a35d515d9
6 changed files with 173 additions and 26 deletions
+14
View File
@@ -162,6 +162,20 @@ class TestReasoningEffortParsing:
s = GatewaySettings.from_env("LLM", env=env)
assert s.sources[0].effort_fallback == "nearest"
def test_effort_key_tolerates_case_and_whitespace(self):
"""`.env` 里的行尾空格与大写写法是常态,档位取值本身没有大小写语义。"""
env = _env(**{"LLM__QWEN__1__REASONING_EFFORT": " LOW "})
assert GatewaySettings.from_env("LLM", env=env).sources[0].reasoning_effort is Effort.LOW
def test_effort_fallback_tolerates_case_and_whitespace(self):
"""与相邻的 REASONING_EFFORT 同口径: 同一份 .env 里两个键脾气不同即是坑。
`EFFORT_FALLBACK=Nearest` 此前会原样落到 `SourceConfig`,被值域校验拒掉
——而人看着 .env 里明明写了 nearest(2026-09-05 独立验证查出)。
"""
env = _env(**{"LLM__QWEN__1__EFFORT_FALLBACK": " Nearest "})
assert GatewaySettings.from_env("LLM", env=env).sources[0].effort_fallback == "nearest"
def test_invalid_effort_fallback_rejected(self):
"""`resolve_thinking` 对未知 fallback 值是 fail-closed,不会替配置兜错。"""
env = _env(**{"LLM__QWEN__1__EFFORT_FALLBACK": "closest"})