mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-01 17:00:21 +08:00
Remove ranked candidate data read wrappers
This commit is contained in:
@@ -1,9 +1,9 @@
|
|||||||
use aether_data::DataLayerError;
|
use aether_data::DataLayerError;
|
||||||
use aether_data_contracts::repository::candidate_selection::StoredMinimalCandidateSelectionRow;
|
use aether_data_contracts::repository::candidate_selection::StoredMinimalCandidateSelectionRow;
|
||||||
use aether_scheduler_core::{
|
use aether_scheduler_core::{
|
||||||
auth_constraints_allow_api_format, build_ranked_minimal_candidate_selection,
|
auth_constraints_allow_api_format, collect_global_model_names_for_required_capability,
|
||||||
collect_global_model_names_for_required_capability, enumerate_minimal_candidate_selection,
|
enumerate_minimal_candidate_selection, normalize_api_format,
|
||||||
normalize_api_format, resolve_requested_global_model_name, row_supports_requested_model,
|
resolve_requested_global_model_name, row_supports_requested_model,
|
||||||
BuildMinimalCandidateSelectionInput, SchedulerAuthConstraints,
|
BuildMinimalCandidateSelectionInput, SchedulerAuthConstraints,
|
||||||
SchedulerMinimalCandidateSelectionCandidate, SchedulerPriorityMode,
|
SchedulerMinimalCandidateSelectionCandidate, SchedulerPriorityMode,
|
||||||
};
|
};
|
||||||
@@ -51,129 +51,6 @@ pub(crate) async fn read_requested_model_rows(
|
|||||||
Ok(Some((resolved_global_model_name, rows)))
|
Ok(Some((resolved_global_model_name, rows)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn read_ranked_minimal_candidate_selection(
|
|
||||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
|
||||||
api_format: &str,
|
|
||||||
requested_model_name: &str,
|
|
||||||
require_streaming: bool,
|
|
||||||
auth_snapshot: Option<&GatewayAuthApiKeySnapshot>,
|
|
||||||
) -> Result<Vec<SchedulerMinimalCandidateSelectionCandidate>, DataLayerError> {
|
|
||||||
read_ranked_minimal_candidate_selection_with_priority_mode(
|
|
||||||
state,
|
|
||||||
api_format,
|
|
||||||
requested_model_name,
|
|
||||||
require_streaming,
|
|
||||||
auth_snapshot,
|
|
||||||
SchedulerPriorityMode::Provider,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn read_ranked_minimal_candidate_selection_with_priority_mode(
|
|
||||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
|
||||||
api_format: &str,
|
|
||||||
requested_model_name: &str,
|
|
||||||
require_streaming: bool,
|
|
||||||
auth_snapshot: Option<&GatewayAuthApiKeySnapshot>,
|
|
||||||
priority_mode: SchedulerPriorityMode,
|
|
||||||
) -> Result<Vec<SchedulerMinimalCandidateSelectionCandidate>, DataLayerError> {
|
|
||||||
read_ranked_minimal_candidate_selection_with_priority_mode_and_affinity_key(
|
|
||||||
state,
|
|
||||||
api_format,
|
|
||||||
requested_model_name,
|
|
||||||
require_streaming,
|
|
||||||
auth_snapshot,
|
|
||||||
priority_mode,
|
|
||||||
auth_snapshot_affinity_key(auth_snapshot),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn read_ranked_minimal_candidate_selection_with_priority_mode_and_required_capabilities(
|
|
||||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
|
||||||
api_format: &str,
|
|
||||||
requested_model_name: &str,
|
|
||||||
require_streaming: bool,
|
|
||||||
auth_snapshot: Option<&GatewayAuthApiKeySnapshot>,
|
|
||||||
priority_mode: SchedulerPriorityMode,
|
|
||||||
required_capabilities: Option<&serde_json::Value>,
|
|
||||||
) -> Result<Vec<SchedulerMinimalCandidateSelectionCandidate>, DataLayerError> {
|
|
||||||
read_ranked_minimal_candidate_selection_with_priority_mode_and_affinity_key_and_required_capabilities(
|
|
||||||
state,
|
|
||||||
api_format,
|
|
||||||
requested_model_name,
|
|
||||||
require_streaming,
|
|
||||||
auth_snapshot,
|
|
||||||
priority_mode,
|
|
||||||
auth_snapshot_affinity_key(auth_snapshot),
|
|
||||||
required_capabilities,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn read_ranked_minimal_candidate_selection_with_priority_mode_and_affinity_key(
|
|
||||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
|
||||||
api_format: &str,
|
|
||||||
requested_model_name: &str,
|
|
||||||
require_streaming: bool,
|
|
||||||
auth_snapshot: Option<&GatewayAuthApiKeySnapshot>,
|
|
||||||
priority_mode: SchedulerPriorityMode,
|
|
||||||
affinity_key: Option<&str>,
|
|
||||||
) -> Result<Vec<SchedulerMinimalCandidateSelectionCandidate>, DataLayerError> {
|
|
||||||
read_ranked_minimal_candidate_selection_with_priority_mode_and_affinity_key_and_required_capabilities(
|
|
||||||
state,
|
|
||||||
api_format,
|
|
||||||
requested_model_name,
|
|
||||||
require_streaming,
|
|
||||||
auth_snapshot,
|
|
||||||
priority_mode,
|
|
||||||
affinity_key,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn read_ranked_minimal_candidate_selection_with_priority_mode_and_affinity_key_and_required_capabilities(
|
|
||||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
|
||||||
api_format: &str,
|
|
||||||
requested_model_name: &str,
|
|
||||||
require_streaming: bool,
|
|
||||||
auth_snapshot: Option<&GatewayAuthApiKeySnapshot>,
|
|
||||||
priority_mode: SchedulerPriorityMode,
|
|
||||||
affinity_key: Option<&str>,
|
|
||||||
required_capabilities: Option<&serde_json::Value>,
|
|
||||||
) -> Result<Vec<SchedulerMinimalCandidateSelectionCandidate>, DataLayerError> {
|
|
||||||
let normalized_api_format = normalize_api_format(api_format);
|
|
||||||
if normalized_api_format.is_empty() {
|
|
||||||
return Ok(Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
if !auth_constraints_allow_api_format(
|
|
||||||
auth_snapshot.map(auth_snapshot_constraints).as_ref(),
|
|
||||||
&normalized_api_format,
|
|
||||||
) {
|
|
||||||
return Ok(Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
let Some((resolved_global_model_name, rows)) =
|
|
||||||
read_requested_model_rows(state, &normalized_api_format, requested_model_name).await?
|
|
||||||
else {
|
|
||||||
return Ok(Vec::new());
|
|
||||||
};
|
|
||||||
let auth_constraints = auth_snapshot.map(auth_snapshot_constraints);
|
|
||||||
build_ranked_minimal_candidate_selection(BuildMinimalCandidateSelectionInput {
|
|
||||||
rows,
|
|
||||||
normalized_api_format: &normalized_api_format,
|
|
||||||
requested_model_name,
|
|
||||||
resolved_global_model_name: resolved_global_model_name.as_str(),
|
|
||||||
require_streaming,
|
|
||||||
required_capabilities,
|
|
||||||
auth_constraints: auth_constraints.as_ref(),
|
|
||||||
affinity_key,
|
|
||||||
priority_mode,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) async fn enumerate_minimal_candidate_selection_with_required_capabilities(
|
pub(crate) async fn enumerate_minimal_candidate_selection_with_required_capabilities(
|
||||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
||||||
api_format: &str,
|
api_format: &str,
|
||||||
|
|||||||
@@ -9,12 +9,15 @@ use aether_data_contracts::repository::candidate_selection::StoredProviderModelM
|
|||||||
use aether_data_contracts::repository::candidates::{
|
use aether_data_contracts::repository::candidates::{
|
||||||
RequestCandidateStatus, StoredRequestCandidate,
|
RequestCandidateStatus, StoredRequestCandidate,
|
||||||
};
|
};
|
||||||
use aether_scheduler_core::SchedulerMinimalCandidateSelectionCandidate;
|
use aether_scheduler_core::{
|
||||||
|
build_ranked_minimal_candidate_selection, BuildMinimalCandidateSelectionInput,
|
||||||
|
SchedulerMinimalCandidateSelectionCandidate, SchedulerPriorityMode,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::cache::SchedulerAffinityTarget;
|
use crate::cache::SchedulerAffinityTarget;
|
||||||
use crate::data::auth::GatewayAuthApiKeySnapshot;
|
use crate::data::auth::GatewayAuthApiKeySnapshot;
|
||||||
use crate::data::candidate_selection::{
|
use crate::data::candidate_selection::{
|
||||||
read_ranked_minimal_candidate_selection, MinimalCandidateSelectionRowSource,
|
read_requested_model_rows, MinimalCandidateSelectionRowSource,
|
||||||
};
|
};
|
||||||
use crate::data::GatewayDataState;
|
use crate::data::GatewayDataState;
|
||||||
use crate::{AppState, GatewayError};
|
use crate::{AppState, GatewayError};
|
||||||
@@ -86,14 +89,22 @@ async fn same_priority_candidates_are_distributed_by_affinity_key() {
|
|||||||
let state = GatewayDataState::with_candidate_selection_and_quota_for_tests(candidates, quotas);
|
let state = GatewayDataState::with_candidate_selection_and_quota_for_tests(candidates, quotas);
|
||||||
let auth_snapshot = sample_auth_snapshot("affinity-key-1");
|
let auth_snapshot = sample_auth_snapshot("affinity-key-1");
|
||||||
|
|
||||||
let selection = read_ranked_minimal_candidate_selection(
|
let (_resolved_global_model_name, rows) =
|
||||||
&state,
|
read_requested_model_rows(&state, "openai:chat", "gpt-4.1")
|
||||||
"openai:chat",
|
|
||||||
"gpt-4.1",
|
|
||||||
false,
|
|
||||||
Some(&auth_snapshot),
|
|
||||||
)
|
|
||||||
.await
|
.await
|
||||||
|
.expect("selection rows should read")
|
||||||
|
.expect("selection rows should match requested model");
|
||||||
|
let selection = build_ranked_minimal_candidate_selection(BuildMinimalCandidateSelectionInput {
|
||||||
|
rows,
|
||||||
|
normalized_api_format: "openai:chat",
|
||||||
|
requested_model_name: "gpt-4.1",
|
||||||
|
resolved_global_model_name: "gpt-4.1",
|
||||||
|
require_streaming: false,
|
||||||
|
required_capabilities: None,
|
||||||
|
auth_constraints: None,
|
||||||
|
affinity_key: Some(auth_snapshot.api_key_id.as_str()),
|
||||||
|
priority_mode: SchedulerPriorityMode::Provider,
|
||||||
|
})
|
||||||
.expect("selection should succeed");
|
.expect("selection should succeed");
|
||||||
|
|
||||||
assert_eq!(selection.len(), 2);
|
assert_eq!(selection.len(), 2);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use aether_scheduler_core::{
|
|||||||
resolve_requested_global_model_name, SchedulerMinimalCandidateSelectionCandidate,
|
resolve_requested_global_model_name, SchedulerMinimalCandidateSelectionCandidate,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::data::candidate_selection::read_ranked_minimal_candidate_selection;
|
use crate::data::candidate_selection::enumerate_minimal_candidate_selection_with_required_capabilities;
|
||||||
use crate::data::GatewayDataState;
|
use crate::data::GatewayDataState;
|
||||||
|
|
||||||
use super::super::{
|
use super::super::{
|
||||||
@@ -119,7 +119,7 @@ fn scheduler_candidate_is_serializable() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn read_ranked_minimal_candidate_selection_resolves_provider_model_alias() {
|
async fn enumerate_minimal_candidate_selection_resolves_provider_model_alias() {
|
||||||
let mut row = sample_row();
|
let mut row = sample_row();
|
||||||
row.global_model_name = "gpt-5".to_string();
|
row.global_model_name = "gpt-5".to_string();
|
||||||
row.model_provider_model_name = "gpt-5.2".to_string();
|
row.model_provider_model_name = "gpt-5.2".to_string();
|
||||||
@@ -135,8 +135,14 @@ async fn read_ranked_minimal_candidate_selection_resolves_provider_model_alias()
|
|||||||
let quotas = Arc::new(InMemoryProviderQuotaRepository::seed(vec![]));
|
let quotas = Arc::new(InMemoryProviderQuotaRepository::seed(vec![]));
|
||||||
let state = GatewayDataState::with_candidate_selection_and_quota_for_tests(candidates, quotas);
|
let state = GatewayDataState::with_candidate_selection_and_quota_for_tests(candidates, quotas);
|
||||||
|
|
||||||
let selection =
|
let selection = enumerate_minimal_candidate_selection_with_required_capabilities(
|
||||||
read_ranked_minimal_candidate_selection(&state, "openai:chat", "gpt-5.2", false, None)
|
&state,
|
||||||
|
"openai:chat",
|
||||||
|
"gpt-5.2",
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.expect("selection should succeed");
|
.expect("selection should succeed");
|
||||||
|
|
||||||
@@ -146,7 +152,7 @@ async fn read_ranked_minimal_candidate_selection_resolves_provider_model_alias()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn read_ranked_minimal_candidate_selection_keeps_all_rows_supporting_requested_model() {
|
async fn enumerate_minimal_candidate_selection_keeps_all_rows_supporting_requested_model() {
|
||||||
let mut exact = sample_row();
|
let mut exact = sample_row();
|
||||||
exact.provider_id = "provider-exact".to_string();
|
exact.provider_id = "provider-exact".to_string();
|
||||||
exact.endpoint_id = "endpoint-exact".to_string();
|
exact.endpoint_id = "endpoint-exact".to_string();
|
||||||
@@ -178,8 +184,14 @@ async fn read_ranked_minimal_candidate_selection_keeps_all_rows_supporting_reque
|
|||||||
let quotas = Arc::new(InMemoryProviderQuotaRepository::seed(vec![]));
|
let quotas = Arc::new(InMemoryProviderQuotaRepository::seed(vec![]));
|
||||||
let state = GatewayDataState::with_candidate_selection_and_quota_for_tests(candidates, quotas);
|
let state = GatewayDataState::with_candidate_selection_and_quota_for_tests(candidates, quotas);
|
||||||
|
|
||||||
let selection =
|
let selection = enumerate_minimal_candidate_selection_with_required_capabilities(
|
||||||
read_ranked_minimal_candidate_selection(&state, "openai:chat", "gpt-5", false, None)
|
&state,
|
||||||
|
"openai:chat",
|
||||||
|
"gpt-5",
|
||||||
|
false,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
.expect("selection should succeed");
|
.expect("selection should succeed");
|
||||||
|
|
||||||
@@ -195,7 +207,7 @@ async fn read_ranked_minimal_candidate_selection_keeps_all_rows_supporting_reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn read_ranked_minimal_candidate_selection_allows_resolved_global_model_in_auth_snapshot() {
|
async fn enumerate_minimal_candidate_selection_allows_resolved_global_model_in_auth_snapshot() {
|
||||||
let mut row = sample_row();
|
let mut row = sample_row();
|
||||||
row.global_model_name = "gpt-5".to_string();
|
row.global_model_name = "gpt-5".to_string();
|
||||||
row.global_model_mappings = Some(vec!["gpt-5(?:\\.\\d+)?".to_string()]);
|
row.global_model_mappings = Some(vec!["gpt-5(?:\\.\\d+)?".to_string()]);
|
||||||
@@ -215,12 +227,13 @@ async fn read_ranked_minimal_candidate_selection_allows_resolved_global_model_in
|
|||||||
auth_snapshot.user_allowed_models = Some(vec!["gpt-5".to_string()]);
|
auth_snapshot.user_allowed_models = Some(vec!["gpt-5".to_string()]);
|
||||||
auth_snapshot.api_key_allowed_models = Some(vec!["gpt-5".to_string()]);
|
auth_snapshot.api_key_allowed_models = Some(vec!["gpt-5".to_string()]);
|
||||||
|
|
||||||
let selection = read_ranked_minimal_candidate_selection(
|
let selection = enumerate_minimal_candidate_selection_with_required_capabilities(
|
||||||
&state,
|
&state,
|
||||||
"openai:chat",
|
"openai:chat",
|
||||||
"gpt-5.2",
|
"gpt-5.2",
|
||||||
false,
|
false,
|
||||||
Some(&auth_snapshot),
|
Some(&auth_snapshot),
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("selection should succeed");
|
.expect("selection should succeed");
|
||||||
|
|||||||
@@ -558,9 +558,10 @@ fn scheduler_candidate_runtime_paths_depend_on_scheduler_core_and_state_trait()
|
|||||||
"data/candidate_selection.rs should host requested-model row lookup"
|
"data/candidate_selection.rs should host requested-model row lookup"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
candidate_selection
|
candidate_selection.contains(
|
||||||
.contains("pub(crate) async fn read_ranked_minimal_candidate_selection("),
|
"pub(crate) async fn enumerate_minimal_candidate_selection_with_required_capabilities(",
|
||||||
"data/candidate_selection.rs should host ranked minimal candidate selection builder"
|
),
|
||||||
|
"data/candidate_selection.rs should host minimal candidate enumeration builder"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
candidate_selection
|
candidate_selection
|
||||||
@@ -572,8 +573,12 @@ fn scheduler_candidate_runtime_paths_depend_on_scheduler_core_and_state_trait()
|
|||||||
"data/candidate_selection.rs should depend on core requested-model resolver"
|
"data/candidate_selection.rs should depend on core requested-model resolver"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
candidate_selection.contains("build_ranked_minimal_candidate_selection"),
|
!candidate_selection.contains("read_ranked_minimal_candidate_selection"),
|
||||||
"data/candidate_selection.rs should depend on core ranked minimal candidate builder"
|
"data/candidate_selection.rs should not host ranked candidate selection compatibility readers"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!candidate_selection.contains("build_ranked_minimal_candidate_selection"),
|
||||||
|
"data/candidate_selection.rs should not depend on core ranked minimal candidate builder"
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
candidate_selection.contains("collect_global_model_names_for_required_capability"),
|
candidate_selection.contains("collect_global_model_names_for_required_capability"),
|
||||||
|
|||||||
Reference in New Issue
Block a user