feat: let one call ask for a different tier than its source defaults to
The three-layer priority (call > source > enable_thinking sugar > silence) now lives in one pure function, thinking.effective_effort(). The assembly guard and the request hot path used to each carry their own inline copy of the sugar conversion; two copies of the same judgement drift into the worst shape there is - passes at assembly, raises at runtime. The guard now also honours effort_fallback, so a source that opted into nearest is no longer sentenced at assembly for a tier it could have mapped.
This commit is contained in:
@@ -308,6 +308,39 @@ class ThinkingResolution:
|
||||
applied_effort: Effort | None
|
||||
|
||||
|
||||
def effective_effort(
|
||||
*,
|
||||
request_effort: Effort | None,
|
||||
source_effort: Effort | None,
|
||||
enable_thinking: bool | None,
|
||||
) -> Effort | None:
|
||||
"""求本次生效的档位: 请求级 > 源级 > `enable_thinking` 语法糖 > 不表态(设计 §4.2)。
|
||||
|
||||
**收口成一个纯函数**是本函数存在的全部理由: 装配守卫(`client._guard_thinking`)
|
||||
与请求热路径(`openai_compat._build_payload`)必须给出**同一个**判定,两处各写
|
||||
一份就地转换迟早会分叉,而分叉的形态是"装配期放行、运行期报错"——最难查的那种。
|
||||
|
||||
**一律用 `is None` 判有没有表态,不靠真值性**: `Effort.NONE`(要求不推理)与
|
||||
`enable_thinking=False` 都是**表态**而非缺省,`x or y` 式的回落会把后者当成没配
|
||||
从而跳到下一层——那正是本次要消灭的静默失效。
|
||||
|
||||
语法糖排在最末且 `True → AUTO`(开启但不指定强度,不依赖能力表),不是旧版那个
|
||||
硬编码的 `medium`: 那是库替下游做的档位判断,而 `medium` 在 GLM/kimi/deepseek 的
|
||||
档位表里根本不存在(设计 §4.2 声明过的有意变更)。
|
||||
|
||||
同源同时配 `enable_thinking` 与 `reasoning_effort` 且语义矛盾,已由
|
||||
`SourceConfig.__post_init__` 在构造期报错,故这里不再判——两个字段说同一件事时,
|
||||
矛盾是配置错误,不是优先级问题。
|
||||
"""
|
||||
if request_effort is not None:
|
||||
return request_effort
|
||||
if source_effort is not None:
|
||||
return source_effort
|
||||
if enable_thinking is None:
|
||||
return None
|
||||
return Effort.AUTO if enable_thinking else Effort.NONE
|
||||
|
||||
|
||||
def resolve_thinking(
|
||||
profile: ProviderProfile,
|
||||
capability: ThinkingCapability | None,
|
||||
|
||||
Reference in New Issue
Block a user