fix: validate ownership of managed reasoning parameters
This commit is contained in:
@@ -441,6 +441,62 @@ def effective_effort(
|
||||
return Effort.AUTO if enable_thinking else Effort.NONE
|
||||
|
||||
|
||||
_RAW_THINKING_ROOTS = frozenset(
|
||||
{
|
||||
"reasoning_effort",
|
||||
"enable_thinking",
|
||||
"thinking",
|
||||
"thinking_budget",
|
||||
"reasoning",
|
||||
"thinkingConfig",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _has_output_effort(raw: Mapping[str, Any]) -> bool:
|
||||
"""标准嵌套强度只检查明确的路径,不猜私有方言。"""
|
||||
output = raw.get("output_config")
|
||||
return isinstance(output, Mapping) and "effort" in output
|
||||
|
||||
|
||||
def validate_thinking_wire(wire: ThinkingWire, *, model: str) -> None:
|
||||
"""拒绝开启片段代选强度,未知形态仍交由请求方向检查。"""
|
||||
base = wire.on_base
|
||||
if base is not None and (
|
||||
"reasoning_effort" in base
|
||||
or (wire.effort_key is not None and wire.effort_key in base)
|
||||
or _has_output_effort(base)
|
||||
):
|
||||
raise ThinkingUnsupportedError(
|
||||
f"模型 {model!r} 的 on_base 不得包含强度档位;请移除强度并显式传 reasoning_effort"
|
||||
)
|
||||
|
||||
|
||||
def validate_thinking_raw(
|
||||
raw: Mapping[str, Any],
|
||||
*,
|
||||
effort: Effort | None,
|
||||
wire: ThinkingWire | None,
|
||||
origin: str,
|
||||
) -> None:
|
||||
"""受管推理只有一个来源;同值或被遮蔽的 raw 控制也拒绝。"""
|
||||
if effort is None:
|
||||
return
|
||||
roots = set(_RAW_THINKING_ROOTS)
|
||||
if wire is not None:
|
||||
for fragment in (wire.on_base, wire.off):
|
||||
if fragment is not None:
|
||||
roots.update(fragment)
|
||||
if wire.effort_key is not None:
|
||||
roots.add(wire.effort_key)
|
||||
if roots.intersection(raw) or _has_output_effort(raw):
|
||||
# 不打印 raw 或自定义键名,防配置中夹带秘密。
|
||||
raise ThinkingUnsupportedError(
|
||||
f"{origin} 与受管 reasoning_effort={effort.value!r} 冲突;"
|
||||
"请删除 raw 推理控制,或移除源级/请求级推理表态后仅用 raw"
|
||||
)
|
||||
|
||||
|
||||
def resolve_thinking(
|
||||
profile: ProviderProfile,
|
||||
capability: ThinkingCapability | None,
|
||||
@@ -490,6 +546,7 @@ def resolve_thinking(
|
||||
而是**静默判否**: Phase 2 按开启方向取字段、Phase 4 整条被绕过,最后在拼错误
|
||||
文案时才以 `AttributeError` 现形(一个未文档化、也不属四分类的异常)。
|
||||
"""
|
||||
validate_thinking_wire(profile.thinking, model=model)
|
||||
# Phase 0: 归一 —— 判据全是身份比较,入口不归一则后面每一关都在拿裸串比枚举
|
||||
if effort is not None:
|
||||
effort = coerce_effort(effort, origin=f"resolve_thinking(model={model!r})")
|
||||
|
||||
Reference in New Issue
Block a user