mirror of
https://github.com/katanemo/plano.git
synced 2026-07-05 15:52:12 +02:00
Handle null prefer in inline routing policy (#856)
* Handle null prefer in inline routing policy * Use serde defaulting for null selection preference * Add tests for default selection policy behavior in routing preferences
This commit is contained in:
parent
3dbda9741e
commit
f68c21f8df
2 changed files with 68 additions and 1 deletions
|
|
@ -197,6 +197,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 +265,61 @@ 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]
|
||||||
|
fn extract_routing_policy_selection_policy_missing_defaults_to_none() {
|
||||||
|
let policy = r#""routing_preferences": [
|
||||||
|
{
|
||||||
|
"name": "coding",
|
||||||
|
"description": "code generation, writing functions, debugging",
|
||||||
|
"models": ["openai/gpt-4o", "openai/gpt-4o-mini"]
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
let body = make_chat_body(policy);
|
||||||
|
let (_cleaned, prefs) = extract_routing_policy(&body).unwrap();
|
||||||
|
|
||||||
|
let prefs =
|
||||||
|
prefs.expect("should parse routing_preferences when selection_policy is missing");
|
||||||
|
assert_eq!(prefs.len(), 1);
|
||||||
|
assert_eq!(prefs[0].selection_policy.prefer, SelectionPreference::None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extract_routing_policy_prefer_empty_string_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": ""}
|
||||||
|
}
|
||||||
|
]"#;
|
||||||
|
let body = make_chat_body(policy);
|
||||||
|
let (_cleaned, prefs) = extract_routing_policy(&body).unwrap();
|
||||||
|
|
||||||
|
let prefs =
|
||||||
|
prefs.expect("should parse routing_preferences when selection_policy.prefer is empty");
|
||||||
|
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 {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use hermesllm::apis::openai::{ModelDetail, ModelObject, Models};
|
use hermesllm::apis::openai::{ModelDetail, ModelObject, Models};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
|
@ -111,14 +111,25 @@ pub enum SelectionPreference {
|
||||||
Fastest,
|
Fastest,
|
||||||
/// Return models in the same order they were defined — no reordering.
|
/// Return models in the same order they were defined — no reordering.
|
||||||
#[default]
|
#[default]
|
||||||
|
#[serde(alias = "")]
|
||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct SelectionPolicy {
|
pub struct SelectionPolicy {
|
||||||
|
#[serde(default, deserialize_with = "deserialize_selection_preference")]
|
||||||
pub prefer: SelectionPreference,
|
pub prefer: SelectionPreference,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_selection_preference<'de, D>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<SelectionPreference, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
Ok(Option::<SelectionPreference>::deserialize(deserializer)?.unwrap_or_default())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct TopLevelRoutingPreference {
|
pub struct TopLevelRoutingPreference {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue