mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 02:17:46 +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:
@@ -3,13 +3,13 @@ use futures_util::future::BoxFuture;
|
||||
use sqlx::{PgPool, Row};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::types::{
|
||||
use super::{
|
||||
PublicHealthStatusCount, PublicHealthTimelineBucket, RequestCandidateReadRepository,
|
||||
RequestCandidateStatus, RequestCandidateWriteRepository, StoredRequestCandidate,
|
||||
UpsertRequestCandidateRecord,
|
||||
};
|
||||
use crate::postgres::PostgresTransactionRunner;
|
||||
use crate::DataLayerError;
|
||||
use crate::{error::SqlxResultExt, DataLayerError};
|
||||
|
||||
const LIST_BY_REQUEST_ID_SQL: &str = r#"
|
||||
SELECT
|
||||
@@ -309,7 +309,8 @@ impl SqlxRequestCandidateReadRepository {
|
||||
let rows = sqlx::query(LIST_BY_REQUEST_ID_SQL)
|
||||
.bind(request_id)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
rows.iter().map(map_request_candidate_row).collect()
|
||||
}
|
||||
|
||||
@@ -328,7 +329,8 @@ impl SqlxRequestCandidateReadRepository {
|
||||
))
|
||||
})?)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
rows.iter().map(map_request_candidate_row).collect()
|
||||
}
|
||||
|
||||
@@ -351,7 +353,8 @@ impl SqlxRequestCandidateReadRepository {
|
||||
.bind(provider_id)
|
||||
.bind(limit_value)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
rows.iter().map(map_request_candidate_row).collect()
|
||||
}
|
||||
|
||||
@@ -374,7 +377,8 @@ impl SqlxRequestCandidateReadRepository {
|
||||
))
|
||||
})?)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
rows.iter().map(map_request_candidate_row).collect()
|
||||
}
|
||||
|
||||
@@ -391,17 +395,18 @@ impl SqlxRequestCandidateReadRepository {
|
||||
.bind(endpoint_ids)
|
||||
.bind(since_unix_secs as f64)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
|
||||
rows.iter()
|
||||
.map(|row| {
|
||||
let status = RequestCandidateStatus::from_database(
|
||||
row.try_get::<String, _>("status")?.as_str(),
|
||||
row_get::<String>(row, "status")?.as_str(),
|
||||
)?;
|
||||
Ok(PublicHealthStatusCount {
|
||||
endpoint_id: row.try_get("endpoint_id")?,
|
||||
endpoint_id: row_get(row, "endpoint_id")?,
|
||||
status,
|
||||
count: u64::try_from(row.try_get::<i64, _>("count")?).map_err(|_| {
|
||||
count: u64::try_from(row_get::<i64>(row, "count")?).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(
|
||||
"public health status count out of range".to_string(),
|
||||
)
|
||||
@@ -435,11 +440,12 @@ impl SqlxRequestCandidateReadRepository {
|
||||
.bind(until_unix_secs as f64)
|
||||
.bind(segment_seconds)
|
||||
.fetch_all(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
|
||||
rows.iter()
|
||||
.map(|row| {
|
||||
let raw_segment_idx = row.try_get::<i64, _>("segment_idx")?;
|
||||
let raw_segment_idx = row_get::<i64>(row, "segment_idx")?;
|
||||
let segment_idx = if raw_segment_idx < 0 {
|
||||
0
|
||||
} else {
|
||||
@@ -452,49 +458,53 @@ impl SqlxRequestCandidateReadRepository {
|
||||
.min(segments.saturating_sub(1));
|
||||
|
||||
Ok(PublicHealthTimelineBucket {
|
||||
endpoint_id: row.try_get("endpoint_id")?,
|
||||
endpoint_id: row_get(row, "endpoint_id")?,
|
||||
segment_idx,
|
||||
total_count: u64::try_from(row.try_get::<i64, _>("total_count")?).map_err(
|
||||
total_count: u64::try_from(row_get::<i64>(row, "total_count")?).map_err(
|
||||
|_| {
|
||||
DataLayerError::UnexpectedValue(
|
||||
"public health total_count out of range".to_string(),
|
||||
)
|
||||
},
|
||||
)?,
|
||||
success_count: u64::try_from(row.try_get::<i64, _>("success_count")?).map_err(
|
||||
success_count: u64::try_from(row_get::<i64>(row, "success_count")?).map_err(
|
||||
|_| {
|
||||
DataLayerError::UnexpectedValue(
|
||||
"public health success_count out of range".to_string(),
|
||||
)
|
||||
},
|
||||
)?,
|
||||
failed_count: u64::try_from(row.try_get::<i64, _>("failed_count")?).map_err(
|
||||
failed_count: u64::try_from(row_get::<i64>(row, "failed_count")?).map_err(
|
||||
|_| {
|
||||
DataLayerError::UnexpectedValue(
|
||||
"public health failed_count out of range".to_string(),
|
||||
)
|
||||
},
|
||||
)?,
|
||||
min_created_at_unix_secs: row
|
||||
.try_get::<Option<i64>, _>("min_created_at_unix_secs")?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health min_created_at_unix_secs out of range: {value}"
|
||||
))
|
||||
})
|
||||
min_created_at_unix_secs: row_get::<Option<i64>>(
|
||||
row,
|
||||
"min_created_at_unix_secs",
|
||||
)?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health min_created_at_unix_secs out of range: {value}"
|
||||
))
|
||||
})
|
||||
.transpose()?,
|
||||
max_created_at_unix_secs: row
|
||||
.try_get::<Option<i64>, _>("max_created_at_unix_secs")?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health max_created_at_unix_secs out of range: {value}"
|
||||
))
|
||||
})
|
||||
})
|
||||
.transpose()?,
|
||||
max_created_at_unix_secs: row_get::<Option<i64>>(
|
||||
row,
|
||||
"max_created_at_unix_secs",
|
||||
)?
|
||||
.map(|value| {
|
||||
u64::try_from(value).map_err(|_| {
|
||||
DataLayerError::UnexpectedValue(format!(
|
||||
"public health max_created_at_unix_secs out of range: {value}"
|
||||
))
|
||||
})
|
||||
.transpose()?,
|
||||
})
|
||||
.transpose()?,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -538,7 +548,8 @@ impl SqlxRequestCandidateReadRepository {
|
||||
.bind(candidate.started_at_unix_secs.map(|value| value as f64))
|
||||
.bind(candidate.finished_at_unix_secs.map(|value| value as f64))
|
||||
.fetch_one(&mut **tx)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
map_request_candidate_row(&row)
|
||||
}) as BoxFuture<'_, Result<StoredRequestCandidate, DataLayerError>>
|
||||
})
|
||||
@@ -562,7 +573,8 @@ impl SqlxRequestCandidateReadRepository {
|
||||
))
|
||||
})?)
|
||||
.execute(&self.pool)
|
||||
.await?;
|
||||
.await
|
||||
.map_postgres_err()?;
|
||||
Ok(result.rows_affected() as usize)
|
||||
}
|
||||
}
|
||||
@@ -648,36 +660,42 @@ impl RequestCandidateWriteRepository for SqlxRequestCandidateReadRepository {
|
||||
fn map_request_candidate_row(
|
||||
row: &sqlx::postgres::PgRow,
|
||||
) -> Result<StoredRequestCandidate, DataLayerError> {
|
||||
let status =
|
||||
RequestCandidateStatus::from_database(row.try_get::<String, _>("status")?.as_str())?;
|
||||
let status = RequestCandidateStatus::from_database(row_get::<String>(row, "status")?.as_str())?;
|
||||
StoredRequestCandidate::new(
|
||||
row.try_get("id")?,
|
||||
row.try_get("request_id")?,
|
||||
row.try_get("user_id")?,
|
||||
row.try_get("api_key_id")?,
|
||||
row.try_get("username")?,
|
||||
row.try_get("api_key_name")?,
|
||||
row.try_get("candidate_index")?,
|
||||
row.try_get("retry_index")?,
|
||||
row.try_get("provider_id")?,
|
||||
row.try_get("endpoint_id")?,
|
||||
row.try_get("key_id")?,
|
||||
row_get(row, "id")?,
|
||||
row_get(row, "request_id")?,
|
||||
row_get(row, "user_id")?,
|
||||
row_get(row, "api_key_id")?,
|
||||
row_get(row, "username")?,
|
||||
row_get(row, "api_key_name")?,
|
||||
row_get(row, "candidate_index")?,
|
||||
row_get(row, "retry_index")?,
|
||||
row_get(row, "provider_id")?,
|
||||
row_get(row, "endpoint_id")?,
|
||||
row_get(row, "key_id")?,
|
||||
status,
|
||||
row.try_get("skip_reason")?,
|
||||
row.try_get("is_cached")?,
|
||||
row.try_get("status_code")?,
|
||||
row.try_get("error_type")?,
|
||||
row.try_get("error_message")?,
|
||||
row.try_get("latency_ms")?,
|
||||
row.try_get("concurrent_requests")?,
|
||||
row.try_get("extra_data")?,
|
||||
row.try_get("required_capabilities")?,
|
||||
row.try_get("created_at_unix_secs")?,
|
||||
row.try_get("started_at_unix_secs")?,
|
||||
row.try_get("finished_at_unix_secs")?,
|
||||
row_get(row, "skip_reason")?,
|
||||
row_get(row, "is_cached")?,
|
||||
row_get(row, "status_code")?,
|
||||
row_get(row, "error_type")?,
|
||||
row_get(row, "error_message")?,
|
||||
row_get(row, "latency_ms")?,
|
||||
row_get(row, "concurrent_requests")?,
|
||||
row_get(row, "extra_data")?,
|
||||
row_get(row, "required_capabilities")?,
|
||||
row_get(row, "created_at_unix_secs")?,
|
||||
row_get(row, "started_at_unix_secs")?,
|
||||
row_get(row, "finished_at_unix_secs")?,
|
||||
)
|
||||
}
|
||||
|
||||
fn row_get<T>(row: &sqlx::postgres::PgRow, column: &str) -> Result<T, DataLayerError>
|
||||
where
|
||||
for<'r> T: sqlx::Decode<'r, sqlx::Postgres> + sqlx::Type<sqlx::Postgres>,
|
||||
{
|
||||
row.try_get(column).map_postgres_err()
|
||||
}
|
||||
|
||||
fn status_to_database(status: RequestCandidateStatus) -> &'static str {
|
||||
match status {
|
||||
RequestCandidateStatus::Available => "available",
|
||||
|
||||
Reference in New Issue
Block a user