fix(build): 修复网关构建失败并收口候选选择与 finalize 回归

- 补齐 DecisionTraceCandidate 新增字段,修复审计测试构造
- 修正 usage 内存仓库的 created_at_unix_ms 字段引用与秒/毫秒换算
- 将 build_minimal_candidate_selection 重构为输入对象,消除 clippy 参数过多问题
- 修复 admin global model created_at 旧字段残留引用
- 修复 openai:cli 与 openai:compact 同家族 finalize 在 needs_conversion=true 时的成功回落逻辑
- 清理 aether-gateway 中的 derive/default 与 needless borrow 等 clippy 问题
This commit is contained in:
AAEE86
2026-04-10 17:23:40 +08:00
parent 677b8f5acb
commit 82c3c33610
12 changed files with 198 additions and 79 deletions

View File

@@ -192,7 +192,7 @@ async fn resolve_tunnel_owner_affinity_from_transport(
state: PlannerAppState<'_>,
transport: &GatewayProviderTransportSnapshot,
) -> TunnelOwnerAffinityBucket {
let Some(proxy) = resolve_transport_proxy_snapshot(&transport) else {
let Some(proxy) = resolve_transport_proxy_snapshot(transport) else {
return TunnelOwnerAffinityBucket::Neutral;
};
if proxy.enabled == Some(false) {

View File

@@ -52,8 +52,7 @@ pub(super) async fn build_cross_format_local_openai_chat_decision_payload_for_ca
else {
return None;
};
if !request_pair_allowed_for_transport(&transport, "openai:chat", provider_api_format.as_str())
{
if !request_pair_allowed_for_transport(transport, "openai:chat", provider_api_format.as_str()) {
let skip_reason =
if request_conversion_requires_enable_flag("openai:chat", provider_api_format.as_str())
&& !transport.provider.enable_format_conversion

View File

@@ -3,8 +3,8 @@ use aether_data_contracts::repository::candidate_selection::StoredMinimalCandida
use aether_scheduler_core::{
auth_constraints_allow_api_format, build_minimal_candidate_selection,
collect_global_model_names_for_required_capability, normalize_api_format,
resolve_requested_global_model_name, SchedulerAuthConstraints,
SchedulerMinimalCandidateSelectionCandidate, SchedulerPriorityMode,
resolve_requested_global_model_name, BuildMinimalCandidateSelectionInput,
SchedulerAuthConstraints, SchedulerMinimalCandidateSelectionCandidate, SchedulerPriorityMode,
};
use async_trait::async_trait;
use std::collections::BTreeSet;
@@ -167,17 +167,17 @@ pub(crate) async fn read_minimal_candidate_selection_with_priority_mode_and_affi
return Ok(Vec::new());
};
let auth_constraints = auth_snapshot.map(auth_snapshot_constraints);
build_minimal_candidate_selection(
build_minimal_candidate_selection(BuildMinimalCandidateSelectionInput {
rows,
&normalized_api_format,
normalized_api_format: &normalized_api_format,
requested_model_name,
resolved_global_model_name.as_str(),
resolved_global_model_name: resolved_global_model_name.as_str(),
require_streaming,
required_capabilities,
auth_constraints.as_ref(),
auth_constraints: auth_constraints.as_ref(),
affinity_key,
priority_mode,
)
})
}
pub(crate) async fn read_global_model_names_for_required_capability(

View File

@@ -29,7 +29,8 @@ use aether_data_contracts::repository::video_tasks::{
UpsertVideoTask, VideoTaskLookupKey, VideoTaskStatus, VideoTaskWriteRepository,
};
use aether_scheduler_core::{
build_minimal_candidate_selection, SchedulerAuthConstraints, SchedulerPriorityMode,
build_minimal_candidate_selection, BuildMinimalCandidateSelectionInput,
SchedulerAuthConstraints, SchedulerPriorityMode,
};
use async_trait::async_trait;
use serde_json::json;
@@ -664,17 +665,17 @@ async fn data_state_reads_minimal_candidate_selection_with_auth_filters() {
.map(|items| items.to_vec()),
};
let selection = build_minimal_candidate_selection(
let selection = build_minimal_candidate_selection(BuildMinimalCandidateSelectionInput {
rows,
"openai:chat",
"gpt-4.1",
"gpt-4.1",
false,
None,
Some(&auth_constraints),
Some(auth_snapshot.api_key_id.as_str()),
SchedulerPriorityMode::Provider,
)
normalized_api_format: "openai:chat",
requested_model_name: "gpt-4.1",
resolved_global_model_name: "gpt-4.1",
require_streaming: false,
required_capabilities: None,
auth_constraints: Some(&auth_constraints),
affinity_key: Some(auth_snapshot.api_key_id.as_str()),
priority_mode: SchedulerPriorityMode::Provider,
})
.expect("selection should read");
assert_eq!(selection.len(), 2);

View File

@@ -790,7 +790,6 @@ async fn execute_stream_from_frame_stream(
let request_id_for_report = request_id.to_string();
let request_id_for_report_log = short_request_id(request_id);
let candidate_id_for_report = candidate_id.map(ToOwned::to_owned);
let mut buffered_frames = buffered_frames;
tokio::spawn(async move {
let mut provider_buffered_body = provider_prefetched_body_for_report;
let mut buffered_body = prefetched_body_for_report;

View File

@@ -23,7 +23,10 @@ pub(crate) fn build_admin_global_model_response(
"provider_count": global_model.provider_count,
"active_provider_count": global_model.active_provider_count,
"usage_count": global_model.usage_count,
"created_at": timestamp_or_now(global_model.created_at_unix_secs, now_unix_secs),
"created_at": timestamp_or_now(
global_model.created_at_unix_ms.map(|value| value / 1000),
now_unix_secs,
),
"updated_at": timestamp_or_now(global_model.updated_at_unix_secs, now_unix_secs),
})
}

View File

@@ -2,19 +2,14 @@ use aether_scheduler_core::SchedulerPriorityMode;
use crate::{AppState, GatewayError};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub(crate) enum SchedulerSchedulingMode {
FixedOrder,
#[default]
CacheAffinity,
LoadBalance,
}
impl Default for SchedulerSchedulingMode {
fn default() -> Self {
Self::CacheAffinity
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct SchedulerOrderingConfig {
pub(crate) priority_mode: SchedulerPriorityMode,