mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-10 11:19:50 +08:00
refactor: 大规模模块拆分与代码精简,新增 ai-pipeline/data-contracts 独立 crate
- 新增 aether-ai-pipeline 和 aether-data-contracts crate,将 pipeline 逻辑与数据契约从 gateway 中解耦 - 重构 admin handlers:拆分单体模块为 auth/billing/endpoint/features/model/observability/provider/system 等独立子模块 - 合并 chat/cli 重复代码路径:精简 conversion、finalize、planner 中的 sync/chat/cli 分支 - 重构 scheduler/executor/data 层,引入 facade 模式降低模块间耦合 - 移除冗余的 intent 模块,将 plan_fallback/policy/stream_path/sync_path 迁移至 executor - 前端适配:调整 admin API 调用和 provider 模型测试对话框
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
use aether_data::DataLayerError;
|
||||
use aether_data_contracts::repository::candidate_selection::StoredMinimalCandidateSelectionRow;
|
||||
use aether_scheduler_core::{
|
||||
auth_constraints_allow_api_format, build_minimal_candidate_selection,
|
||||
collect_global_model_names_for_required_capability, normalize_api_format,
|
||||
resolve_requested_global_model_name, SchedulerAuthConstraints,
|
||||
SchedulerMinimalCandidateSelectionCandidate,
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::auth::GatewayAuthApiKeySnapshot;
|
||||
|
||||
#[async_trait]
|
||||
pub(crate) trait MinimalCandidateSelectionRowSource {
|
||||
async fn read_minimal_candidate_selection_rows_for_api_format_and_global_model(
|
||||
&self,
|
||||
api_format: &str,
|
||||
global_model_name: &str,
|
||||
) -> Result<Vec<StoredMinimalCandidateSelectionRow>, DataLayerError>;
|
||||
|
||||
async fn read_minimal_candidate_selection_rows_for_api_format(
|
||||
&self,
|
||||
api_format: &str,
|
||||
) -> Result<Vec<StoredMinimalCandidateSelectionRow>, DataLayerError>;
|
||||
}
|
||||
|
||||
pub(crate) async fn read_requested_model_rows(
|
||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
||||
api_format: &str,
|
||||
requested_model_name: &str,
|
||||
) -> Result<Option<(String, Vec<StoredMinimalCandidateSelectionRow>)>, DataLayerError> {
|
||||
let exact_rows = state
|
||||
.read_minimal_candidate_selection_rows_for_api_format_and_global_model(
|
||||
api_format,
|
||||
requested_model_name,
|
||||
)
|
||||
.await?;
|
||||
if !exact_rows.is_empty() {
|
||||
return Ok(Some((requested_model_name.to_string(), exact_rows)));
|
||||
}
|
||||
|
||||
let rows = state
|
||||
.read_minimal_candidate_selection_rows_for_api_format(api_format)
|
||||
.await?;
|
||||
let Some(resolved_global_model_name) =
|
||||
resolve_requested_global_model_name(&rows, requested_model_name, api_format)
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
Ok(Some((
|
||||
resolved_global_model_name.clone(),
|
||||
rows.into_iter()
|
||||
.filter(|row| row.global_model_name == resolved_global_model_name)
|
||||
.collect(),
|
||||
)))
|
||||
}
|
||||
|
||||
pub(crate) async fn read_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> {
|
||||
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);
|
||||
let affinity_key = auth_snapshot
|
||||
.map(|snapshot| snapshot.api_key_id.trim())
|
||||
.filter(|value| !value.is_empty());
|
||||
build_minimal_candidate_selection(
|
||||
rows,
|
||||
&normalized_api_format,
|
||||
requested_model_name,
|
||||
resolved_global_model_name.as_str(),
|
||||
require_streaming,
|
||||
auth_constraints.as_ref(),
|
||||
affinity_key,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) async fn read_global_model_names_for_required_capability(
|
||||
state: &(impl MinimalCandidateSelectionRowSource + Sync),
|
||||
api_format: &str,
|
||||
required_capability: &str,
|
||||
require_streaming: bool,
|
||||
auth_snapshot: Option<&GatewayAuthApiKeySnapshot>,
|
||||
) -> Result<Vec<String>, DataLayerError> {
|
||||
let normalized_api_format = normalize_api_format(api_format);
|
||||
let required_capability = required_capability.trim();
|
||||
if normalized_api_format.is_empty() || required_capability.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 rows = state
|
||||
.read_minimal_candidate_selection_rows_for_api_format(&normalized_api_format)
|
||||
.await?;
|
||||
let auth_constraints = auth_snapshot.map(auth_snapshot_constraints);
|
||||
Ok(collect_global_model_names_for_required_capability(
|
||||
rows,
|
||||
&normalized_api_format,
|
||||
required_capability,
|
||||
require_streaming,
|
||||
auth_constraints.as_ref(),
|
||||
))
|
||||
}
|
||||
|
||||
fn auth_snapshot_constraints(snapshot: &GatewayAuthApiKeySnapshot) -> SchedulerAuthConstraints {
|
||||
SchedulerAuthConstraints {
|
||||
allowed_providers: snapshot
|
||||
.effective_allowed_providers()
|
||||
.map(|items| items.to_vec()),
|
||||
allowed_api_formats: snapshot
|
||||
.effective_allowed_api_formats()
|
||||
.map(|items| items.to_vec()),
|
||||
allowed_models: snapshot
|
||||
.effective_allowed_models()
|
||||
.map(|items| items.to_vec()),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user