mirror of
https://github.com/katanemo/plano.git
synced 2026-05-18 13:45:15 +02:00
Handle null prefer in inline routing policy
This commit is contained in:
parent
f019f05738
commit
9e066c86d4
1 changed files with 54 additions and 4 deletions
|
|
@ -27,8 +27,9 @@ pub fn extract_routing_policy(
|
||||||
let routing_preferences = json_body
|
let routing_preferences = json_body
|
||||||
.as_object_mut()
|
.as_object_mut()
|
||||||
.and_then(|o| o.remove("routing_preferences"))
|
.and_then(|o| o.remove("routing_preferences"))
|
||||||
.and_then(
|
.and_then(|mut value| {
|
||||||
|value| match serde_json::from_value::<Vec<TopLevelRoutingPreference>>(value) {
|
normalize_null_prefer_to_none(&mut value);
|
||||||
|
match serde_json::from_value::<Vec<TopLevelRoutingPreference>>(value) {
|
||||||
Ok(prefs) => {
|
Ok(prefs) => {
|
||||||
info!(
|
info!(
|
||||||
num_routes = prefs.len(),
|
num_routes = prefs.len(),
|
||||||
|
|
@ -40,13 +41,43 @@ pub fn extract_routing_policy(
|
||||||
warn!(error = %err, "failed to parse routing_preferences");
|
warn!(error = %err, "failed to parse routing_preferences");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
let bytes = Bytes::from(serde_json::to_vec(&json_body).unwrap());
|
let bytes = Bytes::from(serde_json::to_vec(&json_body).unwrap());
|
||||||
Ok((bytes, routing_preferences))
|
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)]
|
#[derive(serde::Serialize)]
|
||||||
struct RoutingDecisionResponse {
|
struct RoutingDecisionResponse {
|
||||||
/// Ranked model list — use first, fall back to next on 429/5xx.
|
/// Ranked model list — use first, fall back to next on 429/5xx.
|
||||||
|
|
@ -197,6 +228,7 @@ async fn routing_decision_inner(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use common::configuration::SelectionPreference;
|
||||||
|
|
||||||
fn make_chat_body(extra_fields: &str) -> Vec<u8> {
|
fn make_chat_body(extra_fields: &str) -> Vec<u8> {
|
||||||
let extra = if extra_fields.is_empty() {
|
let extra = if extra_fields.is_empty() {
|
||||||
|
|
@ -264,6 +296,24 @@ mod tests {
|
||||||
assert!(cleaned_json.get("routing_preferences").is_none());
|
assert!(cleaned_json.get("routing_preferences").is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extract_routing_policy_prefer_null_defaults_to_none() {
|
||||||
|
let policy = r#""routing_preferences": [
|
||||||
|
{
|
||||||
|
"name": "coding",
|
||||||
|
"description": "code generation, writing functions, debugging",
|
||||||
|
"models": ["openai/gpt-4o", "openai/gpt-4o-mini"],
|
||||||
|
"selection_policy": {"prefer": null}
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
let body = make_chat_body(policy);
|
||||||
|
let (_cleaned, prefs) = extract_routing_policy(&body).unwrap();
|
||||||
|
|
||||||
|
let prefs = prefs.expect("should parse routing_preferences when prefer is null");
|
||||||
|
assert_eq!(prefs.len(), 1);
|
||||||
|
assert_eq!(prefs[0].selection_policy.prefer, SelectionPreference::None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn routing_decision_response_serialization() {
|
fn routing_decision_response_serialization() {
|
||||||
let response = RoutingDecisionResponse {
|
let response = RoutingDecisionResponse {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue