fix(model-fetch): 提取获取计划请求,并使网关运行时与共享构建器保持一致

- 将 build_execution_plan 的散参数收敛为 ModelFetchExecutionPlanRequest,消除 clippy too_many_arguments
- 在 aether-gateway 的 model_fetch runtime 中显式依赖 build_models_fetch_execution_plan
- 补充共享 models fetch plan builder 的运行时测试覆盖
This commit is contained in:
AAEE86
2026-04-12 11:57:06 +08:00
parent 3fcb2b1514
commit c24a29fa65
2 changed files with 103 additions and 54 deletions

View File

@@ -365,7 +365,9 @@ mod tests {
use aether_data_contracts::repository::provider_catalog::{ use aether_data_contracts::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider, StoredProviderCatalogEndpoint, StoredProviderCatalogKey, StoredProviderCatalogProvider,
}; };
use aether_model_fetch::{ModelFetchAssociationStore, ModelFetchTransportRuntime}; use aether_model_fetch::{
build_models_fetch_execution_plan, ModelFetchAssociationStore, ModelFetchTransportRuntime,
};
use async_trait::async_trait; use async_trait::async_trait;
use serde_json::{json, Value}; use serde_json::{json, Value};
use std::collections::{HashMap, VecDeque}; use std::collections::{HashMap, VecDeque};
@@ -746,6 +748,30 @@ mod tests {
} }
} }
#[tokio::test]
async fn gateway_runtime_state_supports_shared_models_fetch_plan_builder() {
let state = TestState::default();
let transport = sample_transport(
"openai",
"provider-openai",
"endpoint-openai-chat",
"key-openai-chat",
"openai:chat",
"api_key",
None,
);
let plan = build_models_fetch_execution_plan(&state, &transport)
.await
.expect("shared models fetch plan should build");
assert_eq!(plan.method, "GET");
assert_eq!(plan.provider_id, "provider-openai");
assert_eq!(plan.endpoint_id, "endpoint-openai-chat");
assert_eq!(plan.key_id, "key-openai-chat");
assert_eq!(plan.model_name.as_deref(), Some("models"));
}
#[tokio::test] #[tokio::test]
async fn model_fetch_uses_preset_models_without_endpoint() { async fn model_fetch_uses_preset_models_without_endpoint() {
let provider = sample_provider("provider-codex", "codex"); let provider = sample_provider("provider-codex", "codex");

View File

@@ -67,6 +67,17 @@ pub async fn build_models_fetch_execution_plan(
build_standard_models_fetch_execution_plan(runtime, transport, None).await build_standard_models_fetch_execution_plan(runtime, transport, None).await
} }
struct ModelFetchExecutionPlanRequest {
method: String,
url: String,
headers: BTreeMap<String, String>,
content_type: Option<String>,
body: RequestBody,
client_api_format: String,
provider_api_format: String,
model_name: Option<String>,
}
pub async fn build_standard_models_fetch_execution_plan( pub async fn build_standard_models_fetch_execution_plan(
runtime: &(impl ModelFetchTransportRuntime + ?Sized), runtime: &(impl ModelFetchTransportRuntime + ?Sized),
transport: &GatewayProviderTransportSnapshot, transport: &GatewayProviderTransportSnapshot,
@@ -96,18 +107,20 @@ pub async fn build_standard_models_fetch_execution_plan(
build_execution_plan( build_execution_plan(
runtime, runtime,
transport, transport,
"GET", ModelFetchExecutionPlanRequest {
upstream_url, method: "GET".to_string(),
headers, url: upstream_url,
None, headers,
RequestBody { content_type: None,
json_body: None, body: RequestBody {
body_bytes_b64: None, json_body: None,
body_ref: None, body_bytes_b64: None,
body_ref: None,
},
client_api_format: provider_api_format.clone(),
provider_api_format,
model_name: Some("models".to_string()),
}, },
provider_api_format.clone(),
provider_api_format,
Some("models".to_string()),
) )
.await .await
} }
@@ -148,14 +161,16 @@ pub async fn build_antigravity_fetch_available_models_plan(
build_execution_plan( build_execution_plan(
runtime, runtime,
transport, transport,
"POST", ModelFetchExecutionPlanRequest {
url, method: "POST".to_string(),
headers, url,
Some("application/json".to_string()), headers,
RequestBody::from_json(json!({ "project": project_id })), content_type: Some("application/json".to_string()),
"gemini:chat".to_string(), body: RequestBody::from_json(json!({ "project": project_id })),
ANTIGRAVITY_FETCH_PROVIDER_API_FORMAT.to_string(), client_api_format: "gemini:chat".to_string(),
Some("fetchAvailableModels".to_string()), provider_api_format: ANTIGRAVITY_FETCH_PROVIDER_API_FORMAT.to_string(),
model_name: Some("fetchAvailableModels".to_string()),
},
) )
.await .await
} }
@@ -180,20 +195,22 @@ pub async fn build_gemini_cli_load_code_assist_plan(
build_execution_plan( build_execution_plan(
runtime, runtime,
transport, transport,
"POST", ModelFetchExecutionPlanRequest {
"https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist".to_string(), method: "POST".to_string(),
headers, url: "https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist".to_string(),
Some("application/json".to_string()), headers,
RequestBody::from_json(json!({ content_type: Some("application/json".to_string()),
"metadata": { body: RequestBody::from_json(json!({
"ideType": "ANTIGRAVITY", "metadata": {
"platform": "PLATFORM_UNSPECIFIED", "ideType": "ANTIGRAVITY",
"pluginType": "GEMINI", "platform": "PLATFORM_UNSPECIFIED",
} "pluginType": "GEMINI",
})), }
"gemini:cli".to_string(), })),
GEMINI_CLI_LOAD_CODE_ASSIST_PROVIDER_API_FORMAT.to_string(), client_api_format: "gemini:cli".to_string(),
Some("loadCodeAssist".to_string()), provider_api_format: GEMINI_CLI_LOAD_CODE_ASSIST_PROVIDER_API_FORMAT.to_string(),
model_name: Some("loadCodeAssist".to_string()),
},
) )
.await .await
} }
@@ -219,18 +236,20 @@ pub async fn build_vertex_models_fetch_execution_plan(
build_execution_plan( build_execution_plan(
runtime, runtime,
transport, transport,
"GET", ModelFetchExecutionPlanRequest {
url.trim().to_string(), method: "GET".to_string(),
headers, url: url.trim().to_string(),
None, headers,
RequestBody { content_type: None,
json_body: None, body: RequestBody {
body_bytes_b64: None, json_body: None,
body_ref: None, body_bytes_b64: None,
body_ref: None,
},
client_api_format: api_format.to_string(),
provider_api_format: api_format.to_string(),
model_name: Some("models".to_string()),
}, },
api_format.to_string(),
api_format.to_string(),
Some("models".to_string()),
) )
.await .await
} }
@@ -238,15 +257,19 @@ pub async fn build_vertex_models_fetch_execution_plan(
async fn build_execution_plan( async fn build_execution_plan(
runtime: &(impl ModelFetchTransportRuntime + ?Sized), runtime: &(impl ModelFetchTransportRuntime + ?Sized),
transport: &GatewayProviderTransportSnapshot, transport: &GatewayProviderTransportSnapshot,
method: &str, request: ModelFetchExecutionPlanRequest,
url: String,
headers: BTreeMap<String, String>,
content_type: Option<String>,
body: RequestBody,
client_api_format: String,
provider_api_format: String,
model_name: Option<String>,
) -> Result<ExecutionPlan, String> { ) -> Result<ExecutionPlan, String> {
let ModelFetchExecutionPlanRequest {
method,
url,
headers,
content_type,
body,
client_api_format,
provider_api_format,
model_name,
} = request;
Ok(ExecutionPlan { Ok(ExecutionPlan {
request_id: format!( request_id: format!(
"req-model-fetch-{}-{}", "req-model-fetch-{}-{}",
@@ -258,7 +281,7 @@ async fn build_execution_plan(
provider_id: transport.provider.id.clone(), provider_id: transport.provider.id.clone(),
endpoint_id: transport.endpoint.id.clone(), endpoint_id: transport.endpoint.id.clone(),
key_id: transport.key.id.clone(), key_id: transport.key.id.clone(),
method: method.to_string(), method,
url, url,
headers, headers,
content_type, content_type,