Unify candidate ranking pipeline

This commit is contained in:
fawney19
2026-04-27 12:34:03 +08:00
parent 9b866a6d17
commit 3b542434a2
46 changed files with 3635 additions and 1914 deletions

View File

@@ -476,6 +476,23 @@ async fn gateway_executes_openai_chat_sync_via_local_cross_format_gemini_candida
}
}
fn sample_disabled_conversion_candidate_row() -> StoredMinimalCandidateSelectionRow {
let mut row = sample_candidate_row();
row.provider_id = "provider-openai-chat-gemini-local-disabled".to_string();
row.provider_priority = 20;
row.endpoint_id = "endpoint-openai-chat-gemini-local-disabled".to_string();
row.key_id = "key-openai-chat-gemini-local-disabled".to_string();
row.model_id = "model-openai-chat-gemini-local-disabled".to_string();
row.global_model_id = "global-model-openai-chat-gemini-local-disabled".to_string();
row.model_provider_model_name = "gemini-2.5-flash-upstream".to_string();
row.model_provider_model_mappings = Some(vec![StoredProviderModelMapping {
name: "gemini-2.5-flash-upstream".to_string(),
priority: 2,
api_formats: Some(vec!["gemini:chat".to_string()]),
}]);
row
}
fn sample_provider_catalog_provider() -> StoredProviderCatalogProvider {
StoredProviderCatalogProvider::new(
"provider-openai-chat-gemini-local-1".to_string(),
@@ -497,6 +514,27 @@ async fn gateway_executes_openai_chat_sync_via_local_cross_format_gemini_candida
)
}
fn sample_disabled_conversion_provider_catalog_provider() -> StoredProviderCatalogProvider {
StoredProviderCatalogProvider::new(
"provider-openai-chat-gemini-local-disabled".to_string(),
"gemini".to_string(),
Some("https://example.com".to_string()),
"custom".to_string(),
)
.expect("provider should build")
.with_transport_fields(
true,
false,
false,
None,
Some(2),
None,
Some(20.0),
None,
None,
)
}
fn sample_provider_catalog_endpoint() -> StoredProviderCatalogEndpoint {
StoredProviderCatalogEndpoint::new(
"endpoint-openai-chat-gemini-local-1".to_string(),
@@ -522,6 +560,29 @@ async fn gateway_executes_openai_chat_sync_via_local_cross_format_gemini_candida
.expect("endpoint transport should build")
}
fn sample_disabled_conversion_provider_catalog_endpoint() -> StoredProviderCatalogEndpoint {
StoredProviderCatalogEndpoint::new(
"endpoint-openai-chat-gemini-local-disabled".to_string(),
"provider-openai-chat-gemini-local-disabled".to_string(),
"gemini:chat".to_string(),
Some("gemini".to_string()),
Some("chat".to_string()),
true,
)
.expect("endpoint should build")
.with_transport_fields(
"https://generativelanguage.googleapis.com".to_string(),
None,
None,
Some(2),
Some("/custom/v1beta/models/gemini-2.5-flash-upstream:generateContent".to_string()),
None,
None,
None,
)
.expect("endpoint transport should build")
}
fn sample_provider_catalog_key() -> StoredProviderCatalogKey {
StoredProviderCatalogKey::new(
"key-openai-chat-gemini-local-1".to_string(),
@@ -550,6 +611,34 @@ async fn gateway_executes_openai_chat_sync_via_local_cross_format_gemini_candida
.expect("key transport should build")
}
fn sample_disabled_conversion_provider_catalog_key() -> StoredProviderCatalogKey {
StoredProviderCatalogKey::new(
"key-openai-chat-gemini-local-disabled".to_string(),
"provider-openai-chat-gemini-local-disabled".to_string(),
"prod".to_string(),
"api_key".to_string(),
None,
true,
)
.expect("key should build")
.with_transport_fields(
Some(serde_json::json!(["gemini:chat"])),
encrypt_python_fernet_plaintext(
DEVELOPMENT_ENCRYPTION_KEY,
"sk-upstream-openai-chat-gemini-disabled",
)
.expect("api key should encrypt"),
None,
None,
Some(serde_json::json!({"gemini:chat": 2})),
None,
None,
None,
None,
)
.expect("key transport should build")
}
let seen_execution_runtime = Arc::new(Mutex::new(None::<SeenExecutionRuntimeSyncRequest>));
let seen_execution_runtime_clone = Arc::clone(&seen_execution_runtime);
let seen_report = Arc::new(Mutex::new(false));
@@ -730,11 +819,21 @@ async fn gateway_executes_openai_chat_sync_via_local_cross_format_gemini_candida
let candidate_selection_repository =
Arc::new(InMemoryMinimalCandidateSelectionReadRepository::seed(vec![
sample_candidate_row(),
sample_disabled_conversion_candidate_row(),
]));
let provider_catalog_repository = Arc::new(InMemoryProviderCatalogReadRepository::seed(
vec![sample_provider_catalog_provider()],
vec![sample_provider_catalog_endpoint()],
vec![sample_provider_catalog_key()],
vec![
sample_provider_catalog_provider(),
sample_disabled_conversion_provider_catalog_provider(),
],
vec![
sample_provider_catalog_endpoint(),
sample_disabled_conversion_provider_catalog_endpoint(),
],
vec![
sample_provider_catalog_key(),
sample_disabled_conversion_provider_catalog_key(),
],
));
let (upstream_url, upstream_handle) = start_server(upstream).await;
@@ -833,8 +932,31 @@ async fn gateway_executes_openai_chat_sync_via_local_cross_format_gemini_candida
.list_by_request_id("trace-openai-chat-gemini-local-123")
.await
.expect("request candidate trace should read");
assert_eq!(stored_candidates.len(), 1);
assert_eq!(stored_candidates[0].status, RequestCandidateStatus::Success);
assert_eq!(stored_candidates.len(), 2);
assert_eq!(
stored_candidates
.iter()
.filter(|candidate| candidate.status == RequestCandidateStatus::Success)
.count(),
1
);
let skipped_candidate = stored_candidates
.iter()
.find(|candidate| candidate.status == RequestCandidateStatus::Skipped)
.expect("disabled conversion candidate should be persisted as skipped");
assert_eq!(
skipped_candidate.skip_reason.as_deref(),
Some("format_conversion_disabled")
);
let extra_data = skipped_candidate
.extra_data
.as_ref()
.expect("skipped cross-format candidate extra_data should exist");
assert_eq!(extra_data["execution_strategy"], "local_cross_format");
assert_eq!(
extra_data["transport_diagnostics"]["request_pair"]["conversion_enabled"],
false
);
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
assert!(