fix(api): 修复401/400错误时的认证刷新逻辑并优化模型处理

为API调用和流式请求添加401/400错误时的认证刷新重试机制
修改antigravity-core中ensureRolesInContents方法,仅对非图像模型设置systemInstruction
This commit is contained in:
hex2077 2026-01-08 12:46:25 +08:00
parent 509e9b73a7
commit 2828166b18
2 changed files with 45 additions and 18 deletions

View file

@ -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);

View file

@ -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;
}