diff --git a/crates/brightstaff/src/handlers/routing_service.rs b/crates/brightstaff/src/handlers/routing_service.rs index cab18dbc..e5d50fcf 100644 --- a/crates/brightstaff/src/handlers/routing_service.rs +++ b/crates/brightstaff/src/handlers/routing_service.rs @@ -27,9 +27,8 @@ pub fn extract_routing_policy( let routing_preferences = json_body .as_object_mut() .and_then(|o| o.remove("routing_preferences")) - .and_then(|mut value| { - normalize_null_prefer_to_none(&mut value); - match serde_json::from_value::>(value) { + .and_then( + |value| match serde_json::from_value::>(value) { Ok(prefs) => { info!( num_routes = prefs.len(), @@ -41,43 +40,13 @@ pub fn extract_routing_policy( warn!(error = %err, "failed to parse routing_preferences"); None } - } - }); + }, + ); let bytes = Bytes::from(serde_json::to_vec(&json_body).unwrap()); Ok((bytes, routing_preferences)) } -fn normalize_null_prefer_to_none(routing_preferences: &mut serde_json::Value) { - let Some(preferences) = routing_preferences.as_array_mut() else { - return; - }; - - for preference in preferences { - let Some(preference_obj) = preference.as_object_mut() else { - continue; - }; - - let Some(selection_policy) = preference_obj.get_mut("selection_policy") else { - continue; - }; - - let Some(policy_obj) = selection_policy.as_object_mut() else { - continue; - }; - - if policy_obj - .get("prefer") - .is_some_and(serde_json::Value::is_null) - { - policy_obj.insert( - "prefer".to_string(), - serde_json::Value::String("none".to_string()), - ); - } - } -} - #[derive(serde::Serialize)] struct RoutingDecisionResponse { /// Ranked model list — use first, fall back to next on 429/5xx. diff --git a/crates/common/src/configuration.rs b/crates/common/src/configuration.rs index 653f4d8c..e46c06a5 100644 --- a/crates/common/src/configuration.rs +++ b/crates/common/src/configuration.rs @@ -1,5 +1,5 @@ use hermesllm::apis::openai::{ModelDetail, ModelObject, Models}; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize}; use std::collections::HashMap; use std::fmt::Display; @@ -116,9 +116,19 @@ pub enum SelectionPreference { #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct SelectionPolicy { + #[serde(default, deserialize_with = "deserialize_selection_preference")] pub prefer: SelectionPreference, } +fn deserialize_selection_preference<'de, D>( + deserializer: D, +) -> Result +where + D: Deserializer<'de>, +{ + Ok(Option::::deserialize(deserializer)?.unwrap_or_default()) +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TopLevelRoutingPreference { pub name: String,