fix: normalise a bare tier string at the fourth door

`resolve_thinking` is exported, and its third argument turned from `bool`
into `Effort` this cycle — so the most natural downstream call now passes
the `"low"` it read out of JSON or config. Every gate inside compares by
identity, and `"none" is Effort.NONE` is always false: the tier was not
rejected, it was silently misjudged. Phase 2 read the on-form for a
request that wanted the off-form, Phase 4 was skipped entirely on a model
that cannot be disabled, and the only visible symptom arrived much later
as an AttributeError from `.value` — an exception that is neither
documented nor one of the four error classes.

Design 4.4 already lists this as the fourth entry a tier can come in
through; this makes the code agree with it.
This commit is contained in:
2026-09-05 06:49:34 -04:00
parent 32b92a8894
commit 4866e6b858
2 changed files with 57 additions and 2 deletions
+45
View File
@@ -443,6 +443,51 @@ class TestResolveThinking:
resolve_thinking(profile, cap, Effort.NONE, model="x-1")
assert "register_provider" not in str(exc.value), "形态已知,不该指向注册"
# —— 归一化: 本函数是档位进入库内的第四条入口(设计 §4.4) ——
def test_a_bare_string_tier_is_normalised_at_the_door(self):
"""`resolve_thinking` 在 `__all__` 里,下游直调时传的天然是裸串。
第三参数本次由 `bool` 换成 `Effort`,而下游最自然的写法是从 JSON/配置读出来
的 `"low"`。不在入口归一,`_inject` 撞 `.value` 抛的是 `AttributeError`——
一个未文档化、也不属错误四分类的异常(2026-09-05 独立验证查出)。
"""
got = resolve_thinking(
get_provider("zhipu"), get_capability("glm-5.3"), "low", model="glm-5.3"
)
assert got.payload == {"thinking": {"type": "enabled"}, "reasoning_effort": "low"}
assert got.applied_effort is Effort.LOW
def test_a_bare_none_string_still_means_the_off_tier(self):
"""裸 `"none"` 必须走到关闭形态,而不是被当成某个开启档。
身份比较 `"none" is Effort.NONE` 恒假,漏归一的后果是**静默判否**:
`_wire_unknown_for` 的 `effort is not Effort.NONE` 恒真,于是关闭请求会去看
`on_base`——正是设计 §2 处置表第 2 条点名要避免的误判方向。
"""
got = resolve_thinking(
get_provider("zhipu"), get_capability("glm-5.2"), "none", model="glm-5.2"
)
assert got.payload == {"thinking": {"type": "disabled"}}
assert got.applied_effort is Effort.NONE
def test_a_bare_none_string_reaches_phase4_on_a_model_that_cannot_disable(self):
"""漏归一时 Phase 4 整条被绕过: 关不掉的模型会被静默放行成"开启""""
with pytest.raises(ThinkingUnsupportedError, match="无法关闭推理") as exc:
resolve_thinking(
get_provider("zhipu"), get_capability("glm-5.3"), "none", model="glm-5.3"
)
assert "'low'" in str(exc.value), "Phase 4 的可执行替代不能丢"
def test_an_illegal_tier_string_names_this_function_as_the_origin(self):
"""非法档位报 `ValueError` 并指回**是哪一处**填错——档位有四条入口,不说清
就得让人自己去翻。"""
with pytest.raises(ValueError, match="resolve_thinking") as exc:
resolve_thinking(
get_provider("zhipu"), get_capability("glm-5.3"), "lowest", model="glm-5.3"
)
assert "非法推理档位" in str(exc.value)
class TestReconcileThinking:
"""声明 × 观测对账(设计 §4.3): 矛盾出文案,不表态出 None。