feat: provider api_formats 可空继承、OpenAI 图片 edit/variation 与用量配额多项补强

- 鉴权: provider_api_keys.api_formats 改为可空,OAuth 托管 key 自动继承 provider endpoints 激活格式,相关 handler/测试同步更新
- 图片 planner: OpenAI 图片路由新增 edit/variation 操作并完善参数校验、响应合并与流式处理
- 用量: user me usage 返回区分 client_requested_stream/upstream_is_stream,前端 usage 列表筛选与展示增强
- 统计: stats_daily_model 新增 cache_creation_ephemeral_5m/1h tokens 字段与回填链路
- 配额/observability: quota repository 新增内存与 SQL 扩展,admin observability usage 字段扩充
- 其它: OAuth 导入/轮询收敛、provider 汇总与 pool admin 读写链路小修、新增 system_config 缓存与 provider template handler

Closes #318

Co-authored-by: Entropy.Xu <[email protected]>
This commit is contained in:
fawney19
2026-04-23 14:42:51 +08:00
co-authored by Entropy.Xu
parent f55f22d2e8
commit fa328e18a1
128 changed files with 5583 additions and 690 deletions
+144 -3
View File
@@ -1,4 +1,8 @@
use aether_data_contracts::repository::provider_catalog::StoredProviderCatalogKey;
use aether_data_contracts::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey,
};
use aether_provider_transport::provider_types::provider_type_is_fixed;
use std::collections::BTreeSet;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ProviderKeyCredentialKind {
@@ -146,12 +150,68 @@ pub(crate) fn provider_key_is_oauth_managed(
provider_key_auth_semantics(key, provider_type).oauth_managed()
}
pub(crate) fn provider_key_configured_api_formats(key: &StoredProviderCatalogKey) -> Vec<String> {
key.api_formats
.as_ref()
.and_then(serde_json::Value::as_array)
.map(|items| {
items
.iter()
.filter_map(serde_json::Value::as_str)
.map(str::trim)
.filter(|value| !value.is_empty())
.map(ToOwned::to_owned)
.collect::<Vec<_>>()
})
.unwrap_or_default()
}
pub(crate) fn provider_active_api_formats(
endpoints: &[StoredProviderCatalogEndpoint],
) -> Vec<String> {
let mut formats = Vec::new();
let mut seen = BTreeSet::new();
for endpoint in endpoints.iter().filter(|endpoint| endpoint.is_active) {
let api_format = endpoint.api_format.trim();
if api_format.is_empty() || !seen.insert(api_format.to_string()) {
continue;
}
formats.push(api_format.to_string());
}
formats
}
pub(crate) fn provider_key_inherits_provider_api_formats(
key: &StoredProviderCatalogKey,
provider_type: &str,
) -> bool {
provider_type_is_fixed(provider_type) && provider_key_is_oauth_managed(key, provider_type)
}
pub(crate) fn provider_key_effective_api_formats(
key: &StoredProviderCatalogKey,
provider_type: &str,
endpoints: &[StoredProviderCatalogEndpoint],
) -> Vec<String> {
if provider_key_inherits_provider_api_formats(key, provider_type) {
provider_active_api_formats(endpoints)
} else {
provider_key_configured_api_formats(key)
}
}
#[cfg(test)]
mod tests {
use super::{
provider_key_auth_semantics, ProviderKeyCredentialKind, ProviderKeyRuntimeAuthKind,
provider_active_api_formats, provider_key_auth_semantics,
provider_key_configured_api_formats, provider_key_effective_api_formats,
provider_key_inherits_provider_api_formats, ProviderKeyCredentialKind,
ProviderKeyRuntimeAuthKind,
};
use aether_data_contracts::repository::provider_catalog::StoredProviderCatalogKey;
use aether_data_contracts::repository::provider_catalog::{
StoredProviderCatalogEndpoint, StoredProviderCatalogKey,
};
use serde_json::json;
fn sample_key(auth_type: &str) -> StoredProviderCatalogKey {
StoredProviderCatalogKey::new(
@@ -165,6 +225,21 @@ mod tests {
.expect("key should build")
}
fn sample_endpoint(api_format: &str, is_active: bool) -> StoredProviderCatalogEndpoint {
let mut endpoint = StoredProviderCatalogEndpoint::new(
format!("endpoint-{api_format}"),
"provider-1".to_string(),
api_format.to_string(),
None,
None,
true,
)
.expect("endpoint should build");
endpoint.is_active = is_active;
endpoint.base_url = "https://example.invalid".to_string();
endpoint
}
#[test]
fn recognizes_oauth_managed_key() {
let semantics = provider_key_auth_semantics(&sample_key("oauth"), "codex");
@@ -227,4 +302,70 @@ mod tests {
ProviderKeyRuntimeAuthKind::ServiceAccount
);
}
#[test]
fn deduplicates_active_provider_api_formats() {
let endpoints = vec![
sample_endpoint("openai:cli", true),
sample_endpoint("openai:image", true),
sample_endpoint("openai:cli", true),
sample_endpoint("openai:compact", false),
];
assert_eq!(
provider_active_api_formats(&endpoints),
vec!["openai:cli".to_string(), "openai:image".to_string()]
);
}
#[test]
fn fixed_oauth_key_with_null_formats_inherits_provider_formats() {
let key = sample_key("oauth");
let endpoints = vec![
sample_endpoint("openai:cli", true),
sample_endpoint("openai:image", true),
];
assert!(provider_key_inherits_provider_api_formats(&key, "codex"));
assert_eq!(
provider_key_effective_api_formats(&key, "codex", &endpoints),
vec!["openai:cli".to_string(), "openai:image".to_string()]
);
}
#[test]
fn fixed_oauth_key_with_legacy_explicit_formats_still_inherits_provider_formats() {
let mut key = sample_key("oauth");
key.api_formats = Some(json!(["openai:compact"]));
let endpoints = vec![
sample_endpoint("openai:cli", true),
sample_endpoint("openai:image", true),
];
assert!(provider_key_inherits_provider_api_formats(&key, "codex"));
assert_eq!(
provider_key_effective_api_formats(&key, "codex", &endpoints),
vec!["openai:cli".to_string(), "openai:image".to_string()]
);
}
#[test]
fn explicit_formats_do_not_inherit_for_non_fixed_key() {
let mut key = sample_key("oauth");
key.api_formats = Some(json!(["openai:compact"]));
let endpoints = vec![
sample_endpoint("openai:cli", true),
sample_endpoint("openai:image", true),
];
assert!(!provider_key_inherits_provider_api_formats(&key, "openai"));
assert_eq!(
provider_key_configured_api_formats(&key),
vec!["openai:compact".to_string()]
);
assert_eq!(
provider_key_effective_api_formats(&key, "openai", &endpoints),
vec!["openai:compact".to_string()]
);
}
}