mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-09-24 23:10:56 +08:00
release: v1.10.0
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
//! **Validates: Requirements 9.1**
|
||||
|
||||
use crate::database::dao::api_key_provider::{
|
||||
ApiKeyEntry, ApiKeyProvider, ApiProviderType, ProviderWithKeys,
|
||||
ApiKeyEntry, ApiKeyProvider, ApiProviderPromptCacheMode, ApiProviderType, ProviderWithKeys,
|
||||
};
|
||||
use crate::database::system_providers::get_system_providers;
|
||||
use crate::database::DbConnection;
|
||||
@@ -35,6 +35,7 @@ pub struct AddCustomProviderRequest {
|
||||
pub project: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub region: Option<String>,
|
||||
pub prompt_cache_mode: Option<String>,
|
||||
}
|
||||
|
||||
/// 更新 Provider 请求
|
||||
@@ -51,6 +52,7 @@ pub struct UpdateProviderRequest {
|
||||
pub project: Option<String>,
|
||||
pub location: Option<String>,
|
||||
pub region: Option<String>,
|
||||
pub prompt_cache_mode: Option<String>,
|
||||
/// 自定义模型列表
|
||||
pub custom_models: Option<Vec<String>>,
|
||||
}
|
||||
@@ -81,6 +83,8 @@ pub struct ProviderDisplay {
|
||||
pub region: Option<String>,
|
||||
/// 自定义模型列表
|
||||
pub custom_models: Vec<String>,
|
||||
/// 当前 Provider 声明的 Prompt Cache 模式(前端优先使用该值,不再只按 type 猜)
|
||||
pub prompt_cache_mode: Option<String>,
|
||||
pub api_key_count: usize,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
@@ -156,6 +160,9 @@ fn provider_to_display(provider: &ApiKeyProvider, api_key_count: usize) -> Provi
|
||||
location: provider.location.clone(),
|
||||
region: provider.region.clone(),
|
||||
custom_models: provider.custom_models.clone(),
|
||||
prompt_cache_mode: provider
|
||||
.effective_prompt_cache_mode()
|
||||
.map(|mode| mode.to_string()),
|
||||
api_key_count,
|
||||
created_at: provider.created_at.to_rfc3339(),
|
||||
updated_at: provider.updated_at.to_rfc3339(),
|
||||
@@ -306,6 +313,11 @@ pub fn add_custom_api_key_provider(
|
||||
request.project,
|
||||
request.location,
|
||||
request.region,
|
||||
request
|
||||
.prompt_cache_mode
|
||||
.map(|mode| mode.parse::<ApiProviderPromptCacheMode>())
|
||||
.transpose()
|
||||
.map_err(|e: String| format!("无效的 Prompt Cache 模式: {e}"))?,
|
||||
)?;
|
||||
|
||||
Ok(provider_to_display(&provider, 0))
|
||||
@@ -338,6 +350,11 @@ pub fn update_api_key_provider(
|
||||
request.project,
|
||||
request.location,
|
||||
request.region,
|
||||
request
|
||||
.prompt_cache_mode
|
||||
.map(|mode| mode.parse::<ApiProviderPromptCacheMode>())
|
||||
.transpose()
|
||||
.map_err(|e: String| format!("无效的 Prompt Cache 模式: {e}"))?,
|
||||
request.custom_models,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -2049,6 +2049,10 @@ fn resolve_runtime_message_usage_from_session(
|
||||
.cached_input_tokens
|
||||
.filter(|value| *value >= 0)
|
||||
.map(|value| value as u32),
|
||||
cache_creation_input_tokens: session
|
||||
.cache_creation_input_tokens
|
||||
.filter(|value| *value >= 0)
|
||||
.map(|value| value as u32),
|
||||
})
|
||||
}
|
||||
_ => None,
|
||||
@@ -2082,6 +2086,7 @@ fn persist_latest_assistant_message_usage(
|
||||
usage.input_tokens,
|
||||
usage.output_tokens,
|
||||
usage.cached_input_tokens,
|
||||
usage.cache_creation_input_tokens,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -2110,6 +2115,11 @@ fn build_compaction_session_metrics_update(
|
||||
} else {
|
||||
Some(0)
|
||||
};
|
||||
let cache_creation_input_tokens = if usage.usage.output_tokens.is_some() {
|
||||
usage.usage.cache_creation_input_tokens
|
||||
} else {
|
||||
Some(0)
|
||||
};
|
||||
|
||||
let current_window_tokens = usage
|
||||
.usage
|
||||
@@ -2121,6 +2131,7 @@ fn build_compaction_session_metrics_update(
|
||||
schedule_id,
|
||||
current_window_tokens,
|
||||
cached_input_tokens,
|
||||
cache_creation_input_tokens,
|
||||
accumulated_total_tokens: accumulated_total,
|
||||
accumulated_input_tokens: accumulated_input,
|
||||
accumulated_output_tokens: accumulated_output,
|
||||
@@ -3482,6 +3493,7 @@ mod tests {
|
||||
.input_tokens(Some(60))
|
||||
.output_tokens(Some(30))
|
||||
.cached_input_tokens(Some(12))
|
||||
.cache_creation_input_tokens(Some(4))
|
||||
.accumulated_total_tokens(Some(300))
|
||||
.accumulated_input_tokens(Some(200))
|
||||
.accumulated_output_tokens(Some(100))
|
||||
@@ -3494,7 +3506,9 @@ mod tests {
|
||||
|
||||
let usage = ProviderUsage::new(
|
||||
"gpt-4.1".to_string(),
|
||||
Usage::new(Some(120), Some(45), Some(165)).with_cached_input_tokens(Some(90)),
|
||||
Usage::new(Some(120), Some(45), Some(165))
|
||||
.with_cached_input_tokens(Some(90))
|
||||
.with_cache_creation_input_tokens(Some(30)),
|
||||
);
|
||||
|
||||
update_compaction_session_metrics(&session_config, &usage)
|
||||
@@ -3510,6 +3524,7 @@ mod tests {
|
||||
assert_eq!(updated.input_tokens, Some(45));
|
||||
assert_eq!(updated.output_tokens, Some(0));
|
||||
assert_eq!(updated.cached_input_tokens, Some(90));
|
||||
assert_eq!(updated.cache_creation_input_tokens, Some(30));
|
||||
assert_eq!(updated.accumulated_total_tokens, Some(465));
|
||||
assert_eq!(updated.accumulated_input_tokens, Some(320));
|
||||
assert_eq!(updated.accumulated_output_tokens, Some(145));
|
||||
@@ -3538,6 +3553,7 @@ mod tests {
|
||||
.input_tokens(Some(120))
|
||||
.output_tokens(Some(60))
|
||||
.cached_input_tokens(Some(24))
|
||||
.cache_creation_input_tokens(Some(8))
|
||||
.accumulated_total_tokens(Some(700))
|
||||
.accumulated_input_tokens(Some(500))
|
||||
.accumulated_output_tokens(Some(200))
|
||||
@@ -3563,6 +3579,7 @@ mod tests {
|
||||
assert_eq!(updated.input_tokens, Some(0));
|
||||
assert_eq!(updated.output_tokens, Some(0));
|
||||
assert_eq!(updated.cached_input_tokens, Some(0));
|
||||
assert_eq!(updated.cache_creation_input_tokens, Some(0));
|
||||
assert_eq!(updated.accumulated_total_tokens, Some(700));
|
||||
assert_eq!(updated.accumulated_input_tokens, Some(500));
|
||||
assert_eq!(updated.accumulated_output_tokens, Some(200));
|
||||
@@ -3591,6 +3608,7 @@ mod tests {
|
||||
.input_tokens(Some(10))
|
||||
.output_tokens(Some(10))
|
||||
.cached_input_tokens(Some(6))
|
||||
.cache_creation_input_tokens(Some(2))
|
||||
.accumulated_total_tokens(Some(200))
|
||||
.accumulated_input_tokens(Some(120))
|
||||
.accumulated_output_tokens(Some(80))
|
||||
@@ -3601,7 +3619,9 @@ mod tests {
|
||||
let session_config = SessionConfigBuilder::new(&session.id).build();
|
||||
let usage = ProviderUsage::new(
|
||||
"gpt-4.1".to_string(),
|
||||
Usage::new(Some(30), Some(15), Some(45)).with_cached_input_tokens(Some(18)),
|
||||
Usage::new(Some(30), Some(15), Some(45))
|
||||
.with_cached_input_tokens(Some(18))
|
||||
.with_cache_creation_input_tokens(Some(6)),
|
||||
);
|
||||
|
||||
update_compaction_session_metrics(&session_config, &usage)
|
||||
@@ -3617,6 +3637,7 @@ mod tests {
|
||||
assert_eq!(updated.input_tokens, Some(15));
|
||||
assert_eq!(updated.output_tokens, Some(0));
|
||||
assert_eq!(updated.cached_input_tokens, Some(18));
|
||||
assert_eq!(updated.cache_creation_input_tokens, Some(6));
|
||||
assert_eq!(updated.accumulated_total_tokens, Some(245));
|
||||
assert_eq!(updated.accumulated_input_tokens, Some(150));
|
||||
assert_eq!(updated.accumulated_output_tokens, Some(95));
|
||||
@@ -3642,6 +3663,7 @@ mod tests {
|
||||
.input_tokens(Some(204))
|
||||
.output_tokens(Some(88))
|
||||
.cached_input_tokens(Some(160))
|
||||
.cache_creation_input_tokens(Some(48))
|
||||
.apply()
|
||||
.await
|
||||
.expect("写入 usage 失败");
|
||||
@@ -3654,8 +3676,9 @@ mod tests {
|
||||
value.input_tokens,
|
||||
value.output_tokens,
|
||||
value.cached_input_tokens,
|
||||
value.cache_creation_input_tokens,
|
||||
)),
|
||||
Some((204, 88, Some(160)))
|
||||
Some((204, 88, Some(160), Some(48)))
|
||||
);
|
||||
}
|
||||
other => panic!("收到意外事件: {:?}", other),
|
||||
|
||||
@@ -253,6 +253,7 @@ pub async fn save_relay_api_key(
|
||||
None, // project
|
||||
None, // location
|
||||
None, // region
|
||||
None, // prompt_cache_mode
|
||||
)
|
||||
.map_err(|e| ConnectError {
|
||||
code: "CREATE_PROVIDER_FAILED".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user