From 44054f0f52c1b7d415e380db5ed9465ec4033a75 Mon Sep 17 00:00:00 2001 From: Chiron <598621670@qq.com> Date: Wed, 7 Jan 2026 15:27:22 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=B7=BB=E5=8A=A0=20IFlow=20provider=20?= =?UTF-8?q?=E5=AF=B9=20OpenAI=20=E6=A0=BC=E5=BC=8F=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 provider_calls.rs 中实现 IFlowOAuth 和 IFlowCookie 的处理逻辑 - 修复 deepseek-chat 模型请求返回 400 Bad Request 的问题 - 支持 IFlow 的 token 缓存和自动刷新机制 --- .../src/server/handlers/provider_calls.rs | 143 +++++++++++++++++- 1 file changed, 139 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/server/handlers/provider_calls.rs b/src-tauri/src/server/handlers/provider_calls.rs index ca7a30b2b..a7dfe1149 100644 --- a/src-tauri/src/server/handlers/provider_calls.rs +++ b/src-tauri/src/server/handlers/provider_calls.rs @@ -59,7 +59,8 @@ use crate::models::anthropic::AnthropicMessagesRequest; use crate::models::openai::ChatCompletionRequest; use crate::models::provider_pool_model::{CredentialData, ProviderCredential}; use crate::providers::{ - AntigravityProvider, ClaudeCustomProvider, KiroProvider, OpenAICustomProvider, VertexProvider, + AntigravityProvider, ClaudeCustomProvider, IFlowProvider, KiroProvider, OpenAICustomProvider, + VertexProvider, }; use crate::server::AppState; use crate::server_utils::{ @@ -1919,11 +1920,145 @@ pub async fn call_provider_openai( .into_response() } } + // IFlow 凭证类型 - 支持 OpenAI 格式 + CredentialData::IFlowOAuth { creds_file_path } => { + let db = match &state.db { + Some(db) => db, + None => { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({"error": {"message": "Database not available"}})), + ) + .into_response(); + } + }; + + // 获取缓存的 token + let token = match state + .token_cache + .get_valid_token(db, &credential.uuid) + .await + { + Ok(t) => t, + Err(e) => { + tracing::warn!("[POOL] IFlow token cache miss, loading from source: {}", e); + let mut iflow = IFlowProvider::new(); + if let Err(e) = iflow.load_credentials_from_path(creds_file_path).await { + let _ = state.pool_service.mark_unhealthy( + db, + &credential.uuid, + Some(&format!("Failed to load IFlow credentials: {}", e)), + ); + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({"error": {"message": format!("Failed to load IFlow credentials: {}", e)}})), + ) + .into_response(); + } + if let Err(e) = iflow.ensure_valid_token().await { + let _ = state.pool_service.mark_unhealthy( + db, + &credential.uuid, + Some(&format!("IFlow token refresh failed: {}", e)), + ); + return ( + StatusCode::UNAUTHORIZED, + Json(serde_json::json!({"error": {"message": format!("IFlow token refresh failed: {}", e)}})), + ) + .into_response(); + } + iflow.credentials.access_token.unwrap_or_default() + } + }; + + let mut iflow = IFlowProvider::new(); + iflow.credentials.access_token = Some(token); + + let request_json = serde_json::to_value(request).unwrap_or_default(); + match iflow.call_api(&request_json).await { + Ok(response) => { + let status = response.status(); + let headers = response.headers().clone(); + + match response.bytes().await { + Ok(body) => { + let mut response_builder = Response::builder().status(status); + for (key, value) in headers.iter() { + response_builder = response_builder.header(key, value); + } + response_builder.body(Body::from(body)).unwrap_or_else(|_| { + (StatusCode::INTERNAL_SERVER_ERROR, "Failed to build response").into_response() + }) + } + Err(e) => { + tracing::error!("[IFlow] Failed to read response body: {}", e); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({"error": {"message": format!("Failed to read IFlow response: {}", e)}})), + ) + .into_response() + } + } + } + Err(e) => { + tracing::error!("[IFlow] API call failed: {}", e); + ( + StatusCode::BAD_GATEWAY, + Json(serde_json::json!({"error": {"message": format!("IFlow API call failed: {}", e)}})), + ) + .into_response() + } + } + } + CredentialData::IFlowCookie { creds_file_path } => { + let mut iflow = IFlowProvider::new(); + if let Err(e) = iflow.load_credentials_from_path(creds_file_path).await { + return ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({"error": {"message": format!("Failed to load IFlow credentials: {}", e)}})), + ) + .into_response(); + } + + let request_json = serde_json::to_value(request).unwrap_or_default(); + match iflow.call_api(&request_json).await { + Ok(response) => { + let status = response.status(); + let headers = response.headers().clone(); + + match response.bytes().await { + Ok(body) => { + let mut response_builder = Response::builder().status(status); + for (key, value) in headers.iter() { + response_builder = response_builder.header(key, value); + } + response_builder.body(Body::from(body)).unwrap_or_else(|_| { + (StatusCode::INTERNAL_SERVER_ERROR, "Failed to build response").into_response() + }) + } + Err(e) => { + tracing::error!("[IFlow] Failed to read response body: {}", e); + ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(serde_json::json!({"error": {"message": format!("Failed to read IFlow response: {}", e)}})), + ) + .into_response() + } + } + } + Err(e) => { + tracing::error!("[IFlow] API call failed: {}", e); + ( + StatusCode::BAD_GATEWAY, + Json(serde_json::json!({"error": {"message": format!("IFlow API call failed: {}", e)}})), + ) + .into_response() + } + } + } // 新增的凭证类型暂不支持 OpenAI 格式 CredentialData::CodexOAuth { .. } - | CredentialData::ClaudeOAuth { .. } - | CredentialData::IFlowOAuth { .. } - | CredentialData::IFlowCookie { .. } => { + | CredentialData::ClaudeOAuth { .. } => { ( StatusCode::BAD_REQUEST, Json(serde_json::json!({"error": {"message": "This credential type does not support OpenAI format yet"}})),