mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
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:
14
apps/aether-gateway/src/api/ai/claude.rs
Normal file
14
apps/aether-gateway/src/api/ai/claude.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
|
||||
match api_format {
|
||||
"claude:chat" => Some("claude:chat"),
|
||||
"claude:cli" => Some("claude:cli"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
|
||||
match api_format {
|
||||
"claude" | "claude:chat" | "claude:cli" => Some("/v1/messages"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
16
apps/aether-gateway/src/api/ai/gemini.rs
Normal file
16
apps/aether-gateway/src/api/ai/gemini.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
|
||||
match api_format {
|
||||
"gemini:chat" => Some("gemini:chat"),
|
||||
"gemini:cli" => Some("gemini:cli"),
|
||||
"gemini:video" => Some("gemini:video"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
|
||||
match api_format {
|
||||
"gemini" | "gemini:chat" | "gemini:cli" => Some("/v1beta/models/{model}:{action}"),
|
||||
"gemini:video" => Some("/v1beta/models/{model}:predictLongRunning"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
9
apps/aether-gateway/src/api/ai/mod.rs
Normal file
9
apps/aether-gateway/src/api/ai/mod.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
mod claude;
|
||||
mod gemini;
|
||||
mod openai;
|
||||
mod registry;
|
||||
|
||||
pub(crate) use registry::{
|
||||
admin_default_body_rules_for_signature, admin_endpoint_signature_parts, mount_ai_routes,
|
||||
normalize_admin_endpoint_signature, public_api_format_local_path,
|
||||
};
|
||||
19
apps/aether-gateway/src/api/ai/openai.rs
Normal file
19
apps/aether-gateway/src/api/ai/openai.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
pub(crate) fn normalized_signature(api_format: &str) -> Option<&'static str> {
|
||||
match api_format {
|
||||
"openai:chat" => Some("openai:chat"),
|
||||
"openai:cli" => Some("openai:cli"),
|
||||
"openai:compact" => Some("openai:compact"),
|
||||
"openai:video" => Some("openai:video"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn local_path(api_format: &str) -> Option<&'static str> {
|
||||
match api_format {
|
||||
"openai" | "openai:chat" => Some("/v1/chat/completions"),
|
||||
"openai:cli" => Some("/v1/responses"),
|
||||
"openai:compact" => Some("/v1/responses/compact"),
|
||||
"openai:video" => Some("/v1/videos"),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
93
apps/aether-gateway/src/api/ai/registry.rs
Normal file
93
apps/aether-gateway/src/api/ai/registry.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use axum::routing::{any, post};
|
||||
use axum::Router;
|
||||
use serde_json::json;
|
||||
|
||||
use super::{claude, gemini, openai};
|
||||
use crate::gateway::{proxy_request, AppState};
|
||||
|
||||
// Router registration patterns live here so AI public ingress has a single mount registry.
|
||||
// They intentionally stay separate from manifest-facing route inventories in constants.rs,
|
||||
// which describe operational compatibility surfaces rather than the concrete axum mount list.
|
||||
const AI_POST_ROUTE_PATTERNS: &[&str] = &[
|
||||
"/v1/chat/completions",
|
||||
"/v1/messages",
|
||||
"/v1/messages/count_tokens",
|
||||
"/v1/responses",
|
||||
"/v1/responses/compact",
|
||||
];
|
||||
|
||||
const AI_ANY_ROUTE_PATTERNS: &[&str] = &[
|
||||
"/v1/models/{*gemini_path}",
|
||||
"/v1beta/models/{*gemini_path}",
|
||||
"/v1beta/operations",
|
||||
"/v1beta/operations/{*operation_path}",
|
||||
"/v1/videos",
|
||||
"/v1/videos/{*video_path}",
|
||||
"/upload/v1beta/files",
|
||||
"/v1beta/files",
|
||||
"/v1beta/files/{*file_path}",
|
||||
];
|
||||
|
||||
pub(crate) fn mount_ai_routes(mut router: Router<AppState>) -> Router<AppState> {
|
||||
for path in AI_POST_ROUTE_PATTERNS {
|
||||
router = router.route(path, post(proxy_request));
|
||||
}
|
||||
for path in AI_ANY_ROUTE_PATTERNS {
|
||||
router = router.route(path, any(proxy_request));
|
||||
}
|
||||
router
|
||||
}
|
||||
|
||||
pub(crate) fn public_api_format_local_path(api_format: &str) -> &'static str {
|
||||
let normalized = api_format.trim().to_ascii_lowercase();
|
||||
openai::local_path(&normalized)
|
||||
.or_else(|| claude::local_path(&normalized))
|
||||
.or_else(|| gemini::local_path(&normalized))
|
||||
.unwrap_or("/")
|
||||
}
|
||||
|
||||
pub(crate) fn normalize_admin_endpoint_signature(api_format: &str) -> Option<&'static str> {
|
||||
let normalized = api_format.trim().to_ascii_lowercase();
|
||||
openai::normalized_signature(&normalized)
|
||||
.or_else(|| claude::normalized_signature(&normalized))
|
||||
.or_else(|| gemini::normalized_signature(&normalized))
|
||||
}
|
||||
|
||||
pub(crate) fn admin_endpoint_signature_parts(
|
||||
api_format: &str,
|
||||
) -> Option<(&'static str, &'static str, &'static str)> {
|
||||
let normalized = normalize_admin_endpoint_signature(api_format)?;
|
||||
let (api_family, endpoint_kind) = normalized.split_once(':')?;
|
||||
Some((normalized, api_family, endpoint_kind))
|
||||
}
|
||||
|
||||
fn codex_default_body_rules() -> Vec<serde_json::Value> {
|
||||
vec![
|
||||
json!({"action": "drop", "path": "max_output_tokens"}),
|
||||
json!({"action": "drop", "path": "temperature"}),
|
||||
json!({"action": "drop", "path": "top_p"}),
|
||||
json!({"action": "set", "path": "store", "value": false}),
|
||||
json!({
|
||||
"action": "set",
|
||||
"path": "instructions",
|
||||
"value": "You are GPT-5.",
|
||||
"condition": {"path": "instructions", "op": "not_exists"},
|
||||
}),
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn admin_default_body_rules_for_signature(
|
||||
api_format: &str,
|
||||
provider_type: Option<&str>,
|
||||
) -> Option<(String, Vec<serde_json::Value>)> {
|
||||
let normalized_api_format = normalize_admin_endpoint_signature(api_format)?.to_string();
|
||||
let provider_type = provider_type.map(|value| value.trim().to_ascii_lowercase());
|
||||
let body_rules = if normalized_api_format == "openai:compact"
|
||||
|| (normalized_api_format == "openai:cli" && provider_type.as_deref() == Some("codex"))
|
||||
{
|
||||
codex_default_body_rules()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
Some((normalized_api_format, body_rules))
|
||||
}
|
||||
Reference in New Issue
Block a user