fix(config): reasoning_effort accepts mixed case
`reasoning_effort = "High"` in config.toml failed the whole parse: the derived Deserialize matched lowercase variants only, while FromStr lowercased its input. Deserialize now routes through FromStr, so both paths share one vocabulary. Unknown tokens and non-strings still error. Ported from upstream (grok-build sampling-types/types.rs, 1.0.35).
This commit is contained in:
1 file changed
+29
-1
@@ -897,7 +897,7 @@ impl CompactionsRemaining {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Reasoning effort level. `None`/`Minimal` are omitted on the Anthropic Messages API.
|
/// Reasoning effort level. `None`/`Minimal` are omitted on the Anthropic Messages API.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, serde::Serialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
pub enum ReasoningEffort {
|
pub enum ReasoningEffort {
|
||||||
None,
|
None,
|
||||||
@@ -982,6 +982,16 @@ impl std::str::FromStr for ReasoningEffort {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'de> serde::Deserialize<'de> for ReasoningEffort {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let raw = String::deserialize(deserializer)?;
|
||||||
|
raw.parse().map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Canonical wire parse; remapped menu ids need a model catalog.
|
/// Canonical wire parse; remapped menu ids need a model catalog.
|
||||||
pub fn parse_canonical_effort_token(token: &str) -> Option<ReasoningEffort> {
|
pub fn parse_canonical_effort_token(token: &str) -> Option<ReasoningEffort> {
|
||||||
token.parse().ok()
|
token.parse().ok()
|
||||||
@@ -1849,6 +1859,24 @@ mod tests {
|
|||||||
assert!(serde_json::from_str::<ReasoningEffort>("\"BOGUS\"").is_err());
|
assert!(serde_json::from_str::<ReasoningEffort>("\"BOGUS\"").is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn reasoning_effort_deserializes_mixed_case() {
|
||||||
|
for (token, want) in [
|
||||||
|
("\"High\"", ReasoningEffort::High),
|
||||||
|
("\"XHIGH\"", ReasoningEffort::Xhigh),
|
||||||
|
("\"mAx\"", ReasoningEffort::Max),
|
||||||
|
] {
|
||||||
|
let got: ReasoningEffort = serde_json::from_str(token).unwrap();
|
||||||
|
assert_eq!(got, want, "deserialize {token}");
|
||||||
|
}
|
||||||
|
let err = serde_json::from_str::<ReasoningEffort>("\"Highest\"").unwrap_err();
|
||||||
|
assert!(
|
||||||
|
err.to_string().contains("invalid reasoning effort"),
|
||||||
|
"{err}"
|
||||||
|
);
|
||||||
|
assert!(serde_json::from_str::<ReasoningEffort>("7").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reasoning_effort_from_str_max_and_xhigh_are_distinct() {
|
fn reasoning_effort_from_str_max_and_xhigh_are_distinct() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|||||||
Reference in new issue
Block a user