mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 02:47:45 +08:00
feat(routing): consolidate scheduling strategy configuration
This commit is contained in:
@@ -8,7 +8,9 @@ use crate::actions::{
|
||||
RoutingAction, RoutingRulePhase, RoutingSchedulingMode, RoutingSetPriorityMode,
|
||||
};
|
||||
use crate::conditions::RoutingConditionContext;
|
||||
use crate::model::{RoutingGroupConfig, RoutingModelPolicy, RoutingPoolPolicyOverride};
|
||||
use crate::model::{
|
||||
RoutingExecutionPolicy, RoutingGroupConfig, RoutingModelPolicy, RoutingPoolPolicyOverride,
|
||||
};
|
||||
use crate::mutations::{validate_header_patch, validate_json_patch_operations, MutationPlan};
|
||||
use crate::ranking::RankingOverlay;
|
||||
use crate::validation::validate_routing_group_config;
|
||||
@@ -17,7 +19,7 @@ use crate::validation::validate_routing_group_config;
|
||||
pub enum RoutingPolicyError {
|
||||
#[error("routing group config is invalid: {0}")]
|
||||
InvalidConfig(String),
|
||||
#[error("model is not allowed by routing group: {0}")]
|
||||
#[error("model is not allowed by routing rule: {0}")]
|
||||
ModelNotAllowed(String),
|
||||
#[error("mutation action is invalid: {0}")]
|
||||
InvalidMutation(String),
|
||||
@@ -60,6 +62,8 @@ pub struct ResolvedRoutingPolicy {
|
||||
/// See `RoutingDefaultPolicy::sticky_key_attempts`.
|
||||
#[serde(default = "default_sticky_key_attempts")]
|
||||
pub sticky_key_attempts: u32,
|
||||
#[serde(flatten)]
|
||||
pub execution_policy: RoutingExecutionPolicy,
|
||||
pub ranking_overlay: RankingOverlay,
|
||||
pub mutation_plan: MutationPlan,
|
||||
#[serde(default)]
|
||||
@@ -75,14 +79,6 @@ pub fn resolve_routing_policy(
|
||||
validate_routing_group_config(config)
|
||||
.map_err(|error| RoutingPolicyError::InvalidConfig(error.to_string()))?;
|
||||
|
||||
if !model_allowed(&config.allowed_models, input.requested_model)
|
||||
&& !model_allowed(&config.allowed_models, input.resolved_model)
|
||||
{
|
||||
return Err(RoutingPolicyError::ModelNotAllowed(
|
||||
input.requested_model.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut policy = ResolvedRoutingPolicy {
|
||||
group_id: input.group_id.map(str::to_string),
|
||||
group_version: input.group_version,
|
||||
@@ -93,6 +89,7 @@ pub fn resolve_routing_policy(
|
||||
scheduling_mode: config.default_policy.scheduling_mode,
|
||||
keep_priority_on_conversion: config.default_policy.keep_priority_on_conversion,
|
||||
sticky_key_attempts: config.default_policy.sticky_key_attempts,
|
||||
execution_policy: config.default_policy.execution_policy,
|
||||
ranking_overlay: RankingOverlay::default(),
|
||||
mutation_plan: MutationPlan::default(),
|
||||
pool_policy_overrides: BTreeMap::new(),
|
||||
@@ -322,7 +319,6 @@ mod tests {
|
||||
#[test]
|
||||
fn resolves_model_policy_and_matching_rule() {
|
||||
let config = RoutingGroupConfig {
|
||||
allowed_models: vec!["gpt-*".to_string()],
|
||||
default_policy: RoutingDefaultPolicy::default(),
|
||||
model_policies: vec![RoutingModelPolicy {
|
||||
model: "gpt-5".to_string(),
|
||||
@@ -389,14 +385,14 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_allowlist_keeps_default_policy_for_models_without_an_override() {
|
||||
fn default_policy_applies_to_models_without_an_override() {
|
||||
let config = RoutingGroupConfig {
|
||||
allowed_models: vec![],
|
||||
default_policy: RoutingDefaultPolicy {
|
||||
priority_mode: RoutingSetPriorityMode::GlobalKey,
|
||||
scheduling_mode: RoutingSchedulingMode::LoadBalance,
|
||||
keep_priority_on_conversion: true,
|
||||
sticky_key_attempts: 3,
|
||||
execution_policy: Default::default(),
|
||||
},
|
||||
model_policies: vec![RoutingModelPolicy {
|
||||
model: "special-model".to_string(),
|
||||
@@ -471,6 +467,38 @@ mod tests {
|
||||
.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_group_model_allowlist_is_ignored() {
|
||||
let config: RoutingGroupConfig = serde_json::from_value(json!({
|
||||
"allowed_models": ["gpt-5"],
|
||||
"default_policy": {
|
||||
"priority_mode": "provider",
|
||||
"scheduling_mode": "cache_affinity"
|
||||
},
|
||||
"model_policies": [],
|
||||
"rules": []
|
||||
}))
|
||||
.expect("legacy routing config should remain readable");
|
||||
|
||||
resolve_routing_policy(
|
||||
&config,
|
||||
RoutingPolicyInput {
|
||||
group_id: Some("group-1"),
|
||||
group_version: Some(1),
|
||||
selection_source: "system_default",
|
||||
requested_model: "claude-sonnet",
|
||||
resolved_model: "claude-sonnet",
|
||||
api_format: "openai:chat",
|
||||
user_id: None,
|
||||
api_key_id: None,
|
||||
headers: &json!({}),
|
||||
body: &json!({}),
|
||||
phase: RoutingRulePhase::ClientRequest,
|
||||
},
|
||||
)
|
||||
.expect("the legacy allowlist must not reject another model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sticky_key_attempts_defaults_to_two_and_can_be_overridden_by_rule() {
|
||||
let default_config = RoutingGroupConfig::default();
|
||||
@@ -541,41 +569,9 @@ mod tests {
|
||||
assert_eq!(policy.sticky_key_attempts, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_disallowed_model() {
|
||||
let config = RoutingGroupConfig {
|
||||
allowed_models: vec!["gpt-5".to_string()],
|
||||
..RoutingGroupConfig::default()
|
||||
};
|
||||
|
||||
let err = resolve_routing_policy(
|
||||
&config,
|
||||
RoutingPolicyInput {
|
||||
group_id: None,
|
||||
group_version: None,
|
||||
selection_source: "test",
|
||||
requested_model: "claude",
|
||||
resolved_model: "claude",
|
||||
api_format: "openai:chat",
|
||||
user_id: None,
|
||||
api_key_id: None,
|
||||
headers: &json!({}),
|
||||
body: &json!({}),
|
||||
phase: RoutingRulePhase::ClientRequest,
|
||||
},
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
err,
|
||||
RoutingPolicyError::ModelNotAllowed("claude".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn restrict_model_action_rejects_matching_request() {
|
||||
let config = RoutingGroupConfig {
|
||||
allowed_models: vec!["*".to_string()],
|
||||
rules: vec![RoutingRule {
|
||||
id: "restrict".to_string(),
|
||||
priority: 1,
|
||||
|
||||
Reference in New Issue
Block a user