refactor: 移除独立 hub/proxy/executor/gateway crate,统一为 gateway tunnel 架构

- 删除 aether-hub、aether-proxy 独立项目及其 Dockerfile/配置
- 删除 crates/aether-executor 和 crates/aether-gateway 全部模块
- 新增 apps/ 目录作为应用入口
- 将 hub 概念重构为 gateway tunnel transport
- 将 executor 重构为 execution runtime
- 新增 tunnel.rs 合约定义和 testkit tunnel/execution_runtime 模块
- 更新 Python 服务层和测试适配新架构命名
This commit is contained in:
fawney19
2026-04-03 14:59:58 +08:00
parent ddf18fed9a
commit 8f26e1a31f
983 changed files with 103098 additions and 105837 deletions

View File

@@ -0,0 +1,156 @@
use super::*;
pub(crate) fn models_api_format(request_context: &GatewayPublicRequestContext) -> Option<&str> {
request_context
.control_decision
.as_ref()
.and_then(|decision| decision.auth_endpoint_signature.as_deref())
.filter(|signature| matches!(*signature, "openai:chat" | "claude:chat" | "gemini:chat"))
}
pub(super) fn models_detail_id(request_path: &str) -> Option<String> {
let raw = if let Some(value) = request_path.strip_prefix("/v1/models/") {
value
} else if let Some(value) = request_path.strip_prefix("/v1beta/models/") {
value
} else {
return None;
};
let normalized = raw.trim().trim_start_matches("models/").trim();
if normalized.is_empty() {
None
} else {
Some(normalized.to_string())
}
}
fn auth_snapshot_allows_provider_for_models(
auth_snapshot: Option<&crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot>,
provider_id: &str,
provider_name: &str,
) -> bool {
let Some(allowed) = auth_snapshot.and_then(
crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot::effective_allowed_providers,
) else {
return true;
};
allowed.iter().any(|value| {
value.trim().eq_ignore_ascii_case(provider_id.trim())
|| value.trim().eq_ignore_ascii_case(provider_name.trim())
})
}
fn auth_snapshot_allows_model_for_models(
auth_snapshot: Option<&crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot>,
global_model_name: &str,
) -> bool {
let Some(allowed) = auth_snapshot.and_then(
crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot::effective_allowed_models,
) else {
return true;
};
allowed.iter().any(|value| value == global_model_name)
}
fn mapping_scope_matches_for_models(
mapping: &aether_data::repository::candidate_selection::StoredProviderModelMapping,
api_format: &str,
) -> bool {
let Some(api_formats) = mapping.api_formats.as_ref() else {
return true;
};
api_formats
.iter()
.any(|value| value.trim().eq_ignore_ascii_case(api_format))
}
fn candidate_model_names_for_models(
row: &StoredMinimalCandidateSelectionRow,
api_format: &str,
) -> std::collections::BTreeSet<String> {
let mut names = std::collections::BTreeSet::from([row.model_provider_model_name.clone()]);
if let Some(mappings) = row.model_provider_model_mappings.as_ref() {
for mapping in mappings {
if mapping_scope_matches_for_models(mapping, api_format) {
names.insert(mapping.name.clone());
}
}
}
names
}
pub(crate) fn matches_model_mapping_for_models(pattern: &str, model_name: &str) -> bool {
let Ok(compiled) = Regex::new(&format!("^(?:{pattern})$")) else {
return false;
};
compiled.is_match(model_name)
}
fn row_exposes_global_model_for_models(
row: &StoredMinimalCandidateSelectionRow,
api_format: &str,
) -> bool {
let Some(key_allowed_models) = row.key_allowed_models.as_ref() else {
return true;
};
if key_allowed_models.is_empty() {
return false;
}
if key_allowed_models
.iter()
.any(|value| value == &row.global_model_name)
{
return true;
}
let candidate_models = candidate_model_names_for_models(row, api_format);
for allowed_model in key_allowed_models {
if candidate_models.contains(allowed_model) {
return true;
}
}
let Some(global_model_mappings) = row.global_model_mappings.as_ref() else {
return false;
};
for allowed_model in key_allowed_models {
for pattern in global_model_mappings {
if matches_model_mapping_for_models(pattern, allowed_model) {
return true;
}
}
}
false
}
pub(super) fn filter_rows_for_models(
rows: Vec<StoredMinimalCandidateSelectionRow>,
auth_snapshot: Option<&crate::gateway::gateway_data::StoredGatewayAuthApiKeySnapshot>,
api_format: &str,
) -> Vec<StoredMinimalCandidateSelectionRow> {
let mut filtered = rows
.into_iter()
.filter(|row| {
auth_snapshot_allows_provider_for_models(
auth_snapshot,
&row.provider_id,
&row.provider_name,
)
})
.filter(|row| auth_snapshot_allows_model_for_models(auth_snapshot, &row.global_model_name))
.filter(|row| row_exposes_global_model_for_models(row, api_format))
.collect::<Vec<_>>();
filtered.sort_by(|left, right| left.global_model_name.cmp(&right.global_model_name));
let mut deduped = Vec::new();
let mut last_model_name: Option<String> = None;
for row in filtered {
if last_model_name.as_deref() == Some(row.global_model_name.as_str()) {
continue;
}
last_model_name = Some(row.global_model_name.clone());
deduped.push(row);
}
deduped
}