mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-06 01:17:46 +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:
@@ -0,0 +1,273 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
mod constants;
|
||||
pub(crate) mod ndjson;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod remote_compat;
|
||||
mod server;
|
||||
pub(crate) mod stream;
|
||||
mod stream_pump;
|
||||
pub(crate) mod submission;
|
||||
pub(crate) mod sync;
|
||||
pub(crate) mod transport;
|
||||
|
||||
pub(crate) use self::constants::{
|
||||
MAX_ERROR_BODY_BYTES, MAX_STREAM_PREFETCH_BYTES, MAX_STREAM_PREFETCH_FRAMES,
|
||||
};
|
||||
pub use server::{
|
||||
build_execution_runtime_router, build_execution_runtime_router_with_request_concurrency_limit,
|
||||
build_execution_runtime_router_with_request_gates, serve_execution_runtime_tcp,
|
||||
serve_execution_runtime_unix,
|
||||
};
|
||||
pub(crate) use stream::{
|
||||
execute_execution_runtime_stream, maybe_execute_via_execution_runtime_stream,
|
||||
};
|
||||
pub(crate) use stream_pump::build_direct_execution_frame_stream;
|
||||
pub(crate) use sync::{
|
||||
execute_execution_runtime_sync, maybe_build_local_sync_finalize_response,
|
||||
maybe_build_local_video_error_response, maybe_build_local_video_success_outcome,
|
||||
maybe_execute_via_execution_runtime_sync, resolve_local_sync_error_background_report_kind,
|
||||
resolve_local_sync_success_background_report_kind, LocalVideoSyncSuccessOutcome,
|
||||
};
|
||||
pub(crate) use transport::{
|
||||
execute_sync_plan as execute_execution_runtime_sync_plan, DirectSyncExecutionRuntime,
|
||||
DirectUpstreamStreamExecution, ExecutionRuntimeTransportError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum ExecutionStrategy {
|
||||
GatewayAffinityForward,
|
||||
RawPublicProxy,
|
||||
LocalSameFormat,
|
||||
LocalCrossFormat,
|
||||
}
|
||||
|
||||
impl ExecutionStrategy {
|
||||
pub(crate) const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::GatewayAffinityForward => "gateway_affinity_forward",
|
||||
Self::RawPublicProxy => "raw_public_proxy",
|
||||
Self::LocalSameFormat => "local_same_format",
|
||||
Self::LocalCrossFormat => "local_cross_format",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum ConversionMode {
|
||||
None,
|
||||
RequestOnly,
|
||||
ResponseOnly,
|
||||
Bidirectional,
|
||||
}
|
||||
|
||||
impl ConversionMode {
|
||||
pub(crate) const fn as_str(self) -> &'static str {
|
||||
match self {
|
||||
Self::None => "none",
|
||||
Self::RequestOnly => "request_only",
|
||||
Self::ResponseOnly => "response_only",
|
||||
Self::Bidirectional => "bidirectional",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct ClientIntent {
|
||||
pub(crate) client_contract: String,
|
||||
pub(crate) method: String,
|
||||
pub(crate) request_path: String,
|
||||
pub(crate) is_stream: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) requested_model: Option<String>,
|
||||
#[serde(default)]
|
||||
pub(crate) original_request_headers: BTreeMap<String, String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) original_request_body: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct CompiledProviderRequest {
|
||||
pub(crate) execution_strategy: ExecutionStrategy,
|
||||
pub(crate) provider_contract: String,
|
||||
pub(crate) conversion_mode: ConversionMode,
|
||||
pub(crate) request_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) candidate_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) endpoint_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) key_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) mapped_model: Option<String>,
|
||||
#[serde(default)]
|
||||
pub(crate) provider_request_headers: BTreeMap<String, String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_request_body: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_request_body_base64: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) upstream_url: Option<String>,
|
||||
#[serde(default)]
|
||||
pub(crate) upstream_is_stream: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct ExecutionTerminalResult {
|
||||
pub(crate) status_code: u16,
|
||||
#[serde(default)]
|
||||
pub(crate) provider_headers: BTreeMap<String, String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_body: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_body_base64: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) telemetry: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_usage: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct FinalizedExecutionOutcome {
|
||||
pub(crate) report_kind: String,
|
||||
pub(crate) status_code: u16,
|
||||
pub(crate) terminal_state: FinalizedExecutionState,
|
||||
pub(crate) client_contract: String,
|
||||
pub(crate) provider_contract: String,
|
||||
pub(crate) execution_strategy: ExecutionStrategy,
|
||||
pub(crate) conversion_mode: ConversionMode,
|
||||
pub(crate) request_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) candidate_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) user_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) api_key_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) username: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) api_key_name: Option<String>,
|
||||
pub(crate) provider_name: String,
|
||||
pub(crate) model: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) target_model: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_endpoint_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_api_key_id: Option<String>,
|
||||
pub(crate) request_type: String,
|
||||
pub(crate) is_stream: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) response_time_ms: Option<u64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) first_byte_time_ms: Option<u64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) request_headers: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) request_body: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_request_headers: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_request: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_response_headers: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) provider_response: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) client_response_headers: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) client_response: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) standardized_usage: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) request_metadata: Option<Value>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub(crate) audit_payload: Option<Value>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub(crate) enum FinalizedExecutionState {
|
||||
Completed,
|
||||
Failed,
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
pub(crate) fn append_execution_contract_fields(
|
||||
object: &mut Map<String, Value>,
|
||||
execution_strategy: ExecutionStrategy,
|
||||
conversion_mode: ConversionMode,
|
||||
client_contract: &str,
|
||||
provider_contract: &str,
|
||||
) {
|
||||
object.insert(
|
||||
"execution_strategy".to_string(),
|
||||
Value::String(execution_strategy.as_str().to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"conversion_mode".to_string(),
|
||||
Value::String(conversion_mode.as_str().to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"client_contract".to_string(),
|
||||
Value::String(client_contract.to_string()),
|
||||
);
|
||||
object.insert(
|
||||
"provider_contract".to_string(),
|
||||
Value::String(provider_contract.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn append_execution_contract_fields_to_value(
|
||||
value: Value,
|
||||
execution_strategy: ExecutionStrategy,
|
||||
conversion_mode: ConversionMode,
|
||||
client_contract: &str,
|
||||
provider_contract: &str,
|
||||
) -> Value {
|
||||
match value {
|
||||
Value::Object(mut object) => {
|
||||
append_execution_contract_fields(
|
||||
&mut object,
|
||||
execution_strategy,
|
||||
conversion_mode,
|
||||
client_contract,
|
||||
provider_contract,
|
||||
);
|
||||
Value::Object(object)
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn execution_contract_helper_appends_unified_fields() {
|
||||
let value = append_execution_contract_fields_to_value(
|
||||
json!({"provider_api_format": "gemini:chat"}),
|
||||
ExecutionStrategy::LocalCrossFormat,
|
||||
ConversionMode::Bidirectional,
|
||||
"openai:chat",
|
||||
"gemini:chat",
|
||||
);
|
||||
|
||||
assert_eq!(value["execution_strategy"], "local_cross_format");
|
||||
assert_eq!(value["conversion_mode"], "bidirectional");
|
||||
assert_eq!(value["client_contract"], "openai:chat");
|
||||
assert_eq!(value["provider_contract"], "gemini:chat");
|
||||
assert_eq!(value["provider_api_format"], "gemini:chat");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user