fix(api): 修复401/400错误时的认证刷新逻辑并优化模型处理
为API调用和流式请求添加401/400错误时的认证刷新重试机制 修改antigravity-core中ensureRolesInContents方法,仅对非图像模型设置systemInstruction
This commit is contained in:
parent
509e9b73a7
commit
2828166b18
2 changed files with 45 additions and 18 deletions
|
|
@ -702,18 +702,20 @@ function toGeminiApiResponse(antigravityResponse) {
|
|||
* @param {Object} requestBody - 请求体
|
||||
* @returns {Object} 处理后的请求体
|
||||
*/
|
||||
function ensureRolesInContents(requestBody) {
|
||||
function ensureRolesInContents(requestBody, modelName) {
|
||||
delete requestBody.model;
|
||||
|
||||
if (requestBody.system_instruction) {
|
||||
delete requestBody.system_instruction;
|
||||
}
|
||||
|
||||
// 强制设置 systemInstruction
|
||||
requestBody.systemInstruction = {
|
||||
role: 'user',
|
||||
parts: [{ text: ANTIGRAVITY_SYSTEM_PROMPT }]
|
||||
};
|
||||
// 只有非图像模型才强制设置 systemInstruction
|
||||
if (!isImageModel(modelName)) {
|
||||
requestBody.systemInstruction = {
|
||||
role: 'user',
|
||||
parts: [{ text: ANTIGRAVITY_SYSTEM_PROMPT }]
|
||||
};
|
||||
}
|
||||
|
||||
if (requestBody.contents && Array.isArray(requestBody.contents)) {
|
||||
requestBody.contents.forEach(content => {
|
||||
|
|
@ -1262,9 +1264,9 @@ export class AntigravityApiService {
|
|||
selectedModel = this.availableModels[0];
|
||||
}
|
||||
|
||||
// 深拷贝请求体
|
||||
const processedRequestBody = ensureRolesInContents(JSON.parse(JSON.stringify(requestBody)));
|
||||
const actualModelName = alias2ModelName(selectedModel);
|
||||
// 深拷贝请求体
|
||||
const processedRequestBody = ensureRolesInContents(JSON.parse(JSON.stringify(requestBody)), actualModelName);
|
||||
const isClaudeModel = isClaude(actualModelName);
|
||||
|
||||
// 将处理后的请求体转换为 Antigravity 格式
|
||||
|
|
@ -1318,9 +1320,9 @@ export class AntigravityApiService {
|
|||
selectedModel = this.availableModels[0];
|
||||
}
|
||||
|
||||
// 深拷贝请求体
|
||||
const processedRequestBody = ensureRolesInContents(JSON.parse(JSON.stringify(requestBody)));
|
||||
const actualModelName = alias2ModelName(selectedModel);
|
||||
// 深拷贝请求体
|
||||
const processedRequestBody = ensureRolesInContents(JSON.parse(JSON.stringify(requestBody)), actualModelName);
|
||||
|
||||
// 将处理后的请求体转换为 Antigravity 格式
|
||||
const payload = geminiToAntigravity(actualModelName, { request: processedRequestBody }, this.projectId);
|
||||
|
|
|
|||
|
|
@ -722,7 +722,7 @@ export class IFlowApiService {
|
|||
/**
|
||||
* 调用 API
|
||||
*/
|
||||
async callApi(endpoint, body, model, retryCount = 0) {
|
||||
async callApi(endpoint, body, model, isRetry = false, retryCount = 0) {
|
||||
const maxRetries = this.config.REQUEST_MAX_RETRIES || 3;
|
||||
const baseDelay = this.config.REQUEST_BASE_DELAY || 1000;
|
||||
|
||||
|
|
@ -743,6 +743,18 @@ export class IFlowApiService {
|
|||
// 检查是否为可重试的网络错误
|
||||
const isNetworkError = isRetryableNetworkError(error);
|
||||
|
||||
// Handle 401/400 - refresh auth and retry once
|
||||
if ((status === 400 || status === 401) && !isRetry) {
|
||||
console.log(`[iFlow] Received ${status}. Refreshing auth and retrying...`);
|
||||
try {
|
||||
await this.initializeAuth(true);
|
||||
return this.callApi(endpoint, body, model, true, retryCount);
|
||||
} catch (authError) {
|
||||
console.error('[iFlow] Failed to refresh auth during retry:', authError.message);
|
||||
throw error; // throw original error if refresh fails
|
||||
}
|
||||
}
|
||||
|
||||
if (status === 401 || status === 403) {
|
||||
console.error(`[iFlow] Received ${status}. API Key might be invalid or expired.`);
|
||||
throw error;
|
||||
|
|
@ -753,7 +765,7 @@ export class IFlowApiService {
|
|||
const delay = baseDelay * Math.pow(2, retryCount);
|
||||
console.log(`[iFlow] Received 429 (Too Many Requests). Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
return this.callApi(endpoint, body, model, retryCount + 1);
|
||||
return this.callApi(endpoint, body, model, isRetry, retryCount + 1);
|
||||
}
|
||||
|
||||
// Handle other retryable errors (5xx server errors)
|
||||
|
|
@ -761,7 +773,7 @@ export class IFlowApiService {
|
|||
const delay = baseDelay * Math.pow(2, retryCount);
|
||||
console.log(`[iFlow] Received ${status} server error. Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
return this.callApi(endpoint, body, model, retryCount + 1);
|
||||
return this.callApi(endpoint, body, model, isRetry, retryCount + 1);
|
||||
}
|
||||
|
||||
// Handle network errors (ECONNRESET, ETIMEDOUT, etc.) with exponential backoff
|
||||
|
|
@ -770,7 +782,7 @@ export class IFlowApiService {
|
|||
const errorIdentifier = errorCode || errorMessage.substring(0, 50);
|
||||
console.log(`[iFlow] Network error (${errorIdentifier}). Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
return this.callApi(endpoint, body, model, retryCount + 1);
|
||||
return this.callApi(endpoint, body, model, isRetry, retryCount + 1);
|
||||
}
|
||||
|
||||
console.error(`[iFlow] Error calling API (Status: ${status}, Code: ${errorCode}):`, data || error.message);
|
||||
|
|
@ -785,7 +797,7 @@ export class IFlowApiService {
|
|||
* - 逐行处理 SSE 数据
|
||||
* - 正确处理 data: 前缀和 [DONE] 标记
|
||||
*/
|
||||
async *streamApi(endpoint, body, model, retryCount = 0) {
|
||||
async *streamApi(endpoint, body, model, isRetry = false, retryCount = 0) {
|
||||
const maxRetries = this.config.REQUEST_MAX_RETRIES || 3;
|
||||
const baseDelay = this.config.REQUEST_BASE_DELAY || 1000;
|
||||
|
||||
|
|
@ -881,6 +893,19 @@ export class IFlowApiService {
|
|||
// 检查是否为可重试的网络错误
|
||||
const isNetworkError = isRetryableNetworkError(error);
|
||||
|
||||
// Handle 401/400 during stream - refresh auth and retry once
|
||||
if ((status === 400 || status === 401) && !isRetry) {
|
||||
console.log(`[iFlow] Received ${status} during stream. Refreshing auth and retrying...`);
|
||||
try {
|
||||
await this.initializeAuth(true);
|
||||
yield* this.streamApi(endpoint, body, model, true, retryCount);
|
||||
return;
|
||||
} catch (authError) {
|
||||
console.error('[iFlow] Failed to refresh auth during stream retry:', authError.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
if (status === 401 || status === 403) {
|
||||
console.error(`[iFlow] Received ${status} during stream. API Key might be invalid or expired.`);
|
||||
throw error;
|
||||
|
|
@ -891,7 +916,7 @@ export class IFlowApiService {
|
|||
const delay = baseDelay * Math.pow(2, retryCount);
|
||||
console.log(`[iFlow] Received 429 (Too Many Requests) during stream. Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
yield* this.streamApi(endpoint, body, model, retryCount + 1);
|
||||
yield* this.streamApi(endpoint, body, model, isRetry, retryCount + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -900,7 +925,7 @@ export class IFlowApiService {
|
|||
const delay = baseDelay * Math.pow(2, retryCount);
|
||||
console.log(`[iFlow] Received ${status} server error during stream. Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
yield* this.streamApi(endpoint, body, model, retryCount + 1);
|
||||
yield* this.streamApi(endpoint, body, model, isRetry, retryCount + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -910,7 +935,7 @@ export class IFlowApiService {
|
|||
const errorIdentifier = errorCode || errorMessage.substring(0, 50);
|
||||
console.log(`[iFlow] Network error (${errorIdentifier}) during stream. Retrying in ${delay}ms... (attempt ${retryCount + 1}/${maxRetries})`);
|
||||
await new Promise(resolve => setTimeout(resolve, delay));
|
||||
yield* this.streamApi(endpoint, body, model, retryCount + 1);
|
||||
yield* this.streamApi(endpoint, body, model, isRetry, retryCount + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue