diff --git a/src/providers/claude/claude-core.js b/src/providers/claude/claude-core.js
index 2f84a48..c90a1f7 100644
--- a/src/providers/claude/claude-core.js
+++ b/src/providers/claude/claude-core.js
@@ -122,7 +122,7 @@ export class ClaudeApiService {
return this.callApi(endpoint, body, isRetry, retryCount + 1);
}
- logger.error(`[Claude API] Error calling API (Status: ${status}, Code: ${errorCode}):`, error.response ? error.response.data : error.message);
+ logger.error(`[Claude API] Error calling API (Status: ${status}, Code: ${errorCode}):`, error.message);
throw error;
}
}
diff --git a/src/providers/claude/claude-kiro.js b/src/providers/claude/claude-kiro.js
index 883d36e..08b9634 100644
--- a/src/providers/claude/claude-kiro.js
+++ b/src/providers/claude/claude-kiro.js
@@ -40,7 +40,7 @@ const KIRO_CONSTANTS = {
};
// 从 provider-models.js 获取支持的模型列表
-const KIRO_MODELS = getProviderModels('claude-kiro-oauth');
+const KIRO_MODELS = getProviderModels(MODEL_PROVIDER.KIRO_API);
// 完整的模型映射表
const FULL_MODEL_MAPPING = {
@@ -793,7 +793,24 @@ async saveCredentialsToFile(filePath, newData) {
async buildCodewhispererRequest(messages, model, tools = null, inSystemPrompt = null, thinking = null) {
const conversationId = uuidv4();
+ // 内置的 systemPrompt 前缀
+ const builtInPrefix = `
+ 你一定不能说自己是 kiro ,这是非常重要的一点。
+ 你只能回答用户的问题,不能回答任何关于 kiro 的问题。
+ 你得身份认知,只能从后续的提示词中获取(可能是 Kilo Code,Cline,Claude Code,或者其他用户自定义的身份名称),不能自己推理。如果没有,就说自己是 ”开发者何夕2077,你现在使用的不是原版Claude,而是AIClient-2-API”。
+
+
+ 你是 {{identity}},一名拥有多种编程语言、框架、设计模式和最佳实践丰富知识的高级软件工程师。
+ `;
+
let systemPrompt = this.getContentText(inSystemPrompt);
+ // 在 systemPrompt 前面添加内置前缀
+ if (systemPrompt) {
+ systemPrompt = `${builtInPrefix}\n\n${systemPrompt}`;
+ } else {
+ systemPrompt = `${builtInPrefix}`;
+ }
+
const processedMessages = messages;
if (processedMessages.length === 0) {
@@ -1719,7 +1736,7 @@ async saveCredentialsToFile(filePath, newData) {
return this.buildClaudeResponse(responseText, false, 'assistant', model, toolCalls, inputTokens);
} catch (error) {
logger.error('[Kiro] Error in generateContent:', error);
- throw new Error(`Error processing response: ${error.message}`);
+ throw error;
}
}
@@ -2033,7 +2050,7 @@ async saveCredentialsToFile(filePath, newData) {
return;
}
- logger.error(`[Kiro] Stream API call failed (Status: ${status}, Code: ${errorCode}):`, error.message);
+ logger.error(`[Kiro] Stream API call failed (Status: ${status}, Code: ${errorCode}):`, error.message);
throw error;
} finally {
// 确保流被关闭,释放资源
@@ -2427,7 +2444,7 @@ async saveCredentialsToFile(filePath, newData) {
} catch (error) {
logger.error('[Kiro] Error in streaming generation:', error);
- throw new Error(`Error processing response: ${error.message}`);
+ throw error;
}
}
diff --git a/src/providers/forward/forward-core.js b/src/providers/forward/forward-core.js
index 4e0da66..fd36389 100644
--- a/src/providers/forward/forward-core.js
+++ b/src/providers/forward/forward-core.js
@@ -87,7 +87,7 @@ export class ForwardApiService {
return this.callApi(endpoint, body, isRetry, retryCount + 1);
}
- logger.error(`[Forward API] Error calling API (Status: ${status}, Code: ${errorCode}):`, data || error.message);
+ logger.error(`[Forward API] Error calling API (Status: ${status}, Code: ${errorCode}):`, errorMessage);
throw error;
}
}
@@ -139,6 +139,8 @@ export class ForwardApiService {
return;
}
+ const errorMessage = error.message || '';
+ logger.error(`[Forward API] Error calling streaming API (Status: ${status || errorCode}):`, errorMessage);
throw error;
}
}
diff --git a/src/providers/gemini/antigravity-core.js b/src/providers/gemini/antigravity-core.js
index 07334c1..7f1be8a 100644
--- a/src/providers/gemini/antigravity-core.js
+++ b/src/providers/gemini/antigravity-core.js
@@ -55,7 +55,7 @@ const DEFAULT_THINKING_MIN = 1024;
const DEFAULT_THINKING_MAX = 100000;
// 获取 Antigravity 模型列表
-const ANTIGRAVITY_MODELS = getProviderModels('gemini-antigravity');
+const ANTIGRAVITY_MODELS = getProviderModels(MODEL_PROVIDER.ANTIGRAVITY);
// 模型别名映射 - 别名 -> 真实模型名
const MODEL_ALIAS_MAP = {
@@ -1107,7 +1107,7 @@ export class AntigravityApiService {
// 检查是否为可重试的网络错误
const isNetworkError = isRetryableNetworkError(error);
- logger.error(`[Antigravity API] Error calling ${method} on ${baseURL}:`, status, error.message);
+ logger.error(`[Antigravity API] Error calling (Status: ${status}, Code: ${errorCode}):`, error.message);
if ((status === 400 || status === 401) && !isRetry) {
logger.info('[Antigravity API] Received 401/400. Triggering background refresh via PoolManager...');
@@ -1209,7 +1209,7 @@ export class AntigravityApiService {
// 检查是否为可重试的网络错误
const isNetworkError = isRetryableNetworkError(error);
- logger.error(`[Antigravity API] Error during stream ${method} on ${baseURL}:`, status, error.message);
+ logger.error(`[Antigravity API] Error during stream (Status: ${status}, Code: ${errorCode}):`, error.message);
if ((status === 400 || status === 401) && !isRetry) {
logger.info('[Antigravity API] Received 401/400 during stream. Triggering background refresh via PoolManager...');
diff --git a/src/providers/gemini/gemini-core.js b/src/providers/gemini/gemini-core.js
index 6d2614f..ff9eb59 100644
--- a/src/providers/gemini/gemini-core.js
+++ b/src/providers/gemini/gemini-core.js
@@ -36,7 +36,7 @@ const DEFAULT_CODE_ASSIST_ENDPOINT = 'https://cloudcode-pa.googleapis.com';
const DEFAULT_CODE_ASSIST_API_VERSION = 'v1internal';
const OAUTH_CLIENT_ID = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com';
const OAUTH_CLIENT_SECRET = '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';
-const GEMINI_MODELS = getProviderModels('gemini-cli-oauth');
+const GEMINI_MODELS = getProviderModels(MODEL_PROVIDER.GEMINI_CLI);
const ANTI_TRUNCATION_MODELS = GEMINI_MODELS.map(model => `anti-${model}`);
function is_anti_truncation_model(model) {
@@ -489,7 +489,7 @@ export class GeminiApiService {
// 检查是否为可重试的网络错误
const isNetworkError = isRetryableNetworkError(error);
- logger.error(`[Gemini API] Error calling ${method}:`, status, error.message);
+ logger.error(`[Gemini API] Error calling (Status: ${status}, Code: ${errorCode}):`, errorMessage);
// Handle 401 (Unauthorized) - refresh auth and retry once
if ((status === 400 || status === 401) && !isRetry) {
@@ -568,7 +568,7 @@ export class GeminiApiService {
// 检查是否为可重试的网络错误
const isNetworkError = isRetryableNetworkError(error);
- logger.error(`[Gemini API] Error during stream ${method}:`, status, error.message);
+ logger.error(`[Gemini API] Error during stream (Status: ${status}, Code: ${errorCode}):`, errorMessage);
// Handle 401 (Unauthorized) - refresh auth and retry once
if ((status === 400 || status === 401) && !isRetry) {
diff --git a/src/providers/openai/codex-core.js b/src/providers/openai/codex-core.js
index 897b960..73222ca 100644
--- a/src/providers/openai/codex-core.js
+++ b/src/providers/openai/codex-core.js
@@ -148,11 +148,12 @@ export class CodexApiService {
const url = `${this.baseUrl}/responses`;
const body = this.prepareRequestBody(model, requestBody, true);
- const headers = this.buildHeaders(body.prompt_cache_key);
+ const headers = this.buildHeaders(body.prompt_cache_key, true);
try {
const config = {
headers,
+ responseType: 'text', // 确保以文本形式接收 SSE 流
timeout: 120000 // 2 分钟超时
};
@@ -184,8 +185,10 @@ export class CodexApiService {
error.shouldSwitchCredential = true;
error.skipErrorCount = true;
throw error;
+ } else {
+ logger.error(`[Codex] Error calling non-stream API (Status: ${error.response?.status}, Code: ${error.code || 'N/A'}):`, error.message);
+ throw error;
}
- throw error;
}
}
@@ -216,7 +219,7 @@ export class CodexApiService {
const url = `${this.baseUrl}/responses`;
const body = this.prepareRequestBody(model, requestBody, true);
- const headers = this.buildHeaders(body.prompt_cache_key);
+ const headers = this.buildHeaders(body.prompt_cache_key, true);
try {
const config = {
@@ -254,6 +257,7 @@ export class CodexApiService {
error.skipErrorCount = true;
throw error;
} else {
+ logger.error(`[Codex] Error calling streaming API (Status: ${error.response?.status}, Code: ${error.code || 'N/A'}):`, error.message);
throw error;
}
}
@@ -262,21 +266,34 @@ export class CodexApiService {
/**
* 构建请求头
*/
- buildHeaders(cacheId) {
- return {
- 'version': '0.98.0',
+ buildHeaders(cacheId, stream = true) {
+ const headers = {
+ 'version': '0.101.0',
'x-codex-beta-features': 'powershell_utf8',
'x-oai-web-search-eligible': 'true',
- 'session_id': cacheId,
- 'accept': 'text/event-stream',
'authorization': `Bearer ${this.accessToken}`,
'chatgpt-account-id': this.accountId,
'content-type': 'application/json',
- 'user-agent': 'codex_cli_rs/0.89.0 (Windows 10.0.26100; x86_64) WindowsTerminal',
+ 'user-agent': 'codex_cli_rs/0.101.0 (Windows 10.0.26100; x86_64) WindowsTerminal',
'originator': 'codex_cli_rs',
'host': 'chatgpt.com',
- 'Connection': 'close'
+ 'Connection': 'Keep-Alive'
};
+
+ // 设置 Conversation_id 和 Session_id
+ if (cacheId) {
+ headers['Conversation_id'] = cacheId;
+ headers['Session_id'] = cacheId;
+ }
+
+ // 根据是否流式设置 Accept 头
+ if (stream) {
+ headers['accept'] = 'text/event-stream';
+ } else {
+ headers['accept'] = 'application/json';
+ }
+
+ return headers;
}
/**
@@ -438,22 +455,32 @@ export class CodexApiService {
* 解析非流式响应
*/
parseNonStreamResponse(data) {
+ // 确保 data 是字符串
+ const responseText = typeof data === 'string' ? data : String(data);
+
// 从 SSE 流中提取 response.completed 事件
- const lines = data.split('\n');
+ const lines = responseText.split('\n');
for (const line of lines) {
if (line.startsWith('data: ')) {
const jsonData = line.slice(6).trim();
+ if (!jsonData || jsonData === '[DONE]') {
+ continue;
+ }
try {
const parsed = JSON.parse(jsonData);
if (parsed.type === 'response.completed') {
return parsed;
}
} catch (e) {
- // 继续解析
+ // 继续解析下一行
+ logger.debug('[Codex] Failed to parse SSE line:', e.message);
}
}
}
- throw new Error('No completed response found in Codex response');
+
+ // 如果没有找到 response.completed,抛出错误
+ logger.error('[Codex] No completed response found in Codex response');
+ throw new Error('stream error: stream disconnected before completion: stream closed before response.completed');
}
/**
@@ -472,7 +499,8 @@ export class CodexApiService {
{ id: 'gpt-5.1-codex-max', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'openai' },
{ id: 'gpt-5.2', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'openai' },
{ id: 'gpt-5.2-codex', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'openai' },
- { id: 'gpt-5.3-codex', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'openai' }
+ { id: 'gpt-5.3-codex', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'openai' },
+ { id: 'gpt-5.3-codex-spark', object: 'model', created: Math.floor(Date.now() / 1000), owned_by: 'openai' }
]
};
}
diff --git a/src/providers/openai/iflow-core.js b/src/providers/openai/iflow-core.js
index 696ce83..fe5e6c5 100644
--- a/src/providers/openai/iflow-core.js
+++ b/src/providers/openai/iflow-core.js
@@ -23,9 +23,11 @@ import * as https from 'https';
import { promises as fs } from 'fs';
import * as path from 'path';
import * as os from 'os';
+import * as crypto from 'crypto';
import { configureAxiosProxy } from '../../utils/proxy-utils.js';
import { isRetryableNetworkError, MODEL_PROVIDER, formatExpiryLog } from '../../utils/common.js';
import { getProviderPoolManager } from '../../services/service-manager.js';
+import { getProviderModels } from '../provider-models.js';
// iFlow API 端点
const IFLOW_API_BASE_URL = 'https://apis.iflow.cn/v1';
@@ -36,32 +38,10 @@ const IFLOW_OAUTH_CLIENT_ID = '10009311001';
const IFLOW_OAUTH_CLIENT_SECRET = '4Z3YjXycVsQvyGF1etiNlIBB4RsqSDtW';
// 默认模型列表
-const IFLOW_MODELS = [
- // iFlow 特有模型
- 'iflow-rome-30ba3b',
- // Qwen 模型
- 'qwen3-coder-plus',
- 'qwen3-max',
- 'qwen3-vl-plus',
- 'qwen3-max-preview',
- 'qwen3-32b',
- 'qwen3-235b-a22b-thinking-2507',
- 'qwen3-235b-a22b-instruct',
- 'qwen3-235b',
- // Kimi 模型
- 'kimi-k2-0905',
- 'kimi-k2',
- // GLM 模型
- 'glm-4.6',
- 'glm-4.7',
- // DeepSeek 模型
- 'deepseek-v3.2',
- 'deepseek-r1',
- 'deepseek-v3'
-];
+const IFLOW_MODELS = getProviderModels(MODEL_PROVIDER.IFLOW_API);
// 支持 thinking 的模型前缀
-const THINKING_MODEL_PREFIXES = ['glm-4', 'qwen3-235b-a22b-thinking', 'deepseek-r1'];
+const THINKING_MODEL_PREFIXES = ['glm-', 'qwen3-235b-a22b-thinking', 'deepseek-r1'];
// ==================== Token 管理 ====================
@@ -294,6 +274,33 @@ async function fetchUserInfo(accessToken, axiosInstance = null) {
// ==================== 请求处理工具函数 ====================
+/**
+ * 生成 UUID v4
+ * @returns {string} - UUID 字符串
+ */
+function generateUUID() {
+ return crypto.randomUUID();
+}
+
+/**
+ * 创建 iFlow 签名
+ * 签名格式: HMAC-SHA256(userAgent:sessionId:timestamp, apiKey)
+ * @param {string} userAgent - User-Agent
+ * @param {string} sessionID - Session ID
+ * @param {number} timestamp - 时间戳(毫秒)
+ * @param {string} apiKey - API Key
+ * @returns {string} - 十六进制签名
+ */
+function createIFlowSignature(userAgent, sessionID, timestamp, apiKey) {
+ if (!apiKey) {
+ return '';
+ }
+ const payload = `${userAgent}:${sessionID}:${timestamp}`;
+ const hmac = crypto.createHmac('sha256', apiKey);
+ hmac.update(payload);
+ return hmac.digest('hex');
+}
+
/**
* 检查模型是否支持 thinking 配置
* @param {string} model - 模型名称
@@ -359,6 +366,9 @@ function applyIFlowThinkingConfig(body, model) {
* 保留消息历史中的 reasoning_content
* 对于支持 thinking 的模型,保留 assistant 消息中的 reasoning_content
*
+ * 对于 GLM-4.6/4.7 和 MiniMax M2/M2.1,建议在消息历史中包含完整的 assistant
+ * 响应(包括 reasoning_content)以保持更好的上下文连续性。
+ *
* @param {Object} body - 请求体
* @param {string} model - 模型名称
* @returns {Object} - 处理后的请求体
@@ -368,11 +378,13 @@ function preserveReasoningContentInMessages(body, model) {
const lowerModel = model.toLowerCase();
- // 只对支持 thinking 的模型应用
+ // 只对支持 thinking 且需要历史保留的模型应用
const needsPreservation = lowerModel.startsWith('glm-4') ||
- lowerModel.includes('thinking') ||
- lowerModel.startsWith('deepseek-r1');
- if (!needsPreservation) return body;
+ lowerModel.startsWith('minimax-m2');
+
+ if (!needsPreservation) {
+ return body;
+ }
const messages = body.messages;
if (!Array.isArray(messages)) return body;
@@ -382,8 +394,10 @@ function preserveReasoningContentInMessages(body, model) {
msg.role === 'assistant' && msg.reasoning_content && msg.reasoning_content !== ''
);
+ // 如果 reasoning content 已经存在,说明消息格式正确
+ // 客户端已经正确地在历史中保留了推理内容
if (hasReasoningContent) {
- logger.info(`[iFlow] reasoning_content found in message history for ${model}`);
+ logger.debug(`[iFlow] reasoning_content found in message history for ${model}`);
}
return body;
@@ -735,12 +749,28 @@ export class IFlowApiService {
* @returns {Object} - 请求头
*/
_getHeaders(stream = false) {
+ // 生成 session-id
+ const sessionID = 'session-' + generateUUID();
+
+ // 生成时间戳(毫秒)
+ const timestamp = Date.now();
+
+ // 生成签名
+ const signature = createIFlowSignature(IFLOW_USER_AGENT, sessionID, timestamp, this.apiKey);
+
const headers = {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`,
'User-Agent': IFLOW_USER_AGENT,
+ 'session-id': sessionID,
+ 'x-iflow-timestamp': timestamp.toString(),
};
+ // 只有在签名生成成功时才添加
+ if (signature) {
+ headers['x-iflow-signature'] = signature;
+ }
+
if (stream) {
headers['Accept'] = 'text/event-stream';
} else {
@@ -824,7 +854,7 @@ export class IFlowApiService {
return this.callApi(endpoint, body, model, isRetry, retryCount + 1);
}
- logger.error(`[iFlow] Error calling API (Status: ${status}, Code: ${errorCode}):`, data || error.message);
+ logger.error(`[iFlow] Error calling API (Status: ${status}, Code: ${errorCode}):`, errorMessage);
throw error;
}
}
@@ -985,7 +1015,7 @@ export class IFlowApiService {
return;
}
- logger.error(`[iFlow] Error calling streaming API (Status: ${status}, Code: ${errorCode}):`, data || error.message);
+ logger.error(`[iFlow] Error calling streaming API (Status: ${status}, Code: ${errorCode}):`, errorMessage);
throw error;
}
}
@@ -1055,7 +1085,7 @@ export class IFlowApiService {
}
// 需要手动添加的模型列表
- const manualModels = ['glm-4.7', 'kimi-k2.5', 'minimax-m2.1'];
+ const manualModels = ['glm-4.7', 'glm-5', 'kimi-k2.5', 'minimax-m2.1', 'minimax-m2.5'];
try {
const response = await this.axiosInstance.get('/models', {
diff --git a/src/providers/openai/openai-core.js b/src/providers/openai/openai-core.js
index 065320f..a1ce70a 100644
--- a/src/providers/openai/openai-core.js
+++ b/src/providers/openai/openai-core.js
@@ -98,7 +98,7 @@ export class OpenAIApiService {
return this.callApi(endpoint, body, isRetry, retryCount + 1);
}
- logger.error(`[OpenAI API] Error calling API (Status: ${status}, Code: ${errorCode}):`, data || error.message);
+ logger.error(`[OpenAI API] Error calling API (Status: ${status}, Code: ${errorCode}):`, errorMessage);
throw error;
}
}
@@ -183,7 +183,7 @@ export class OpenAIApiService {
return;
}
- logger.error(`[OpenAI API] Error calling streaming API (Status: ${status}, Code: ${errorCode}):`, data || error.message);
+ logger.error(`[OpenAI API] Error calling streaming API (Status: ${status}, Code: ${errorCode}):`, errorMessage);
throw error;
}
}
diff --git a/src/providers/openai/openai-responses-core.js b/src/providers/openai/openai-responses-core.js
index bca7a03..210496b 100644
--- a/src/providers/openai/openai-responses-core.js
+++ b/src/providers/openai/openai-responses-core.js
@@ -82,7 +82,7 @@ export class OpenAIResponsesApiService {
return this.callApi(endpoint, body, isRetry, retryCount + 1);
}
- logger.error(`Error calling OpenAI Responses API (Status: ${status}):`, data || error.message);
+ logger.error(`Error calling OpenAI Responses API (Status: ${status}):`, error.message);
throw error;
}
}
@@ -151,7 +151,7 @@ export class OpenAIResponsesApiService {
return;
}
- logger.error(`Error calling OpenAI Responses streaming API (Status: ${status}):`, data || error.message);
+ logger.error(`Error calling OpenAI Responses streaming API (Status: ${status}):`, error.message);
throw error;
}
}
diff --git a/src/providers/openai/qwen-core.js b/src/providers/openai/qwen-core.js
index d566d0e..ae8aa2e 100644
--- a/src/providers/openai/qwen-core.js
+++ b/src/providers/openai/qwen-core.js
@@ -19,7 +19,7 @@ import { getProviderPoolManager } from '../../services/service-manager.js';
const QWEN_DIR = '.qwen';
const QWEN_CREDENTIAL_FILENAME = 'oauth_creds.json';
// 从 provider-models.js 获取支持的模型列表
-const QWEN_MODELS = getProviderModels('openai-qwen-oauth');
+const QWEN_MODELS = getProviderModels(MODEL_PROVIDER.QWEN_API);
const QWEN_MODEL_LIST = QWEN_MODELS.map(id => ({
id: id,
name: id.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')
@@ -645,7 +645,7 @@ export class QwenApiService {
return this.callApiWithAuthAndRetry(endpoint, body, isStream, retryCount + 1);
}
- logger.error(`[QwenApiService] Error calling API (Status: ${status}, Code: ${errorCode}):`, data);
+ logger.error(`[QwenApiService] Error calling API (Status: ${status}, Code: ${errorCode}):`, errorMessage);
throw error;
}
}
diff --git a/src/providers/provider-models.js b/src/providers/provider-models.js
index abcee8c..1eef5bf 100644
--- a/src/providers/provider-models.js
+++ b/src/providers/provider-models.js
@@ -66,8 +66,10 @@ export const PROVIDER_MODELS = {
'deepseek-v3',
// 手动定义
'glm-4.7',
+ 'glm-5',
'kimi-k2.5',
'minimax-m2.1',
+ 'minimax-m2.5',
],
'openai-codex-oauth': [
'gpt-5',
@@ -79,7 +81,8 @@ export const PROVIDER_MODELS = {
'gpt-5.1-codex-max',
'gpt-5.2',
'gpt-5.2-codex',
- 'gpt-5.3-codex'
+ 'gpt-5.3-codex',
+ 'gpt-5.3-codex-spark'
],
'forward-api': []
};
diff --git a/src/utils/common.js b/src/utils/common.js
index 00eaa50..1933d36 100644
--- a/src/utils/common.js
+++ b/src/utils/common.js
@@ -494,7 +494,7 @@ export async function handleStreamRequest(res, service, model, requestBody, from
// 如果底层未标记,且不跳过错误计数,则在此处标记
if (!credentialMarkedUnhealthy && !skipErrorCount && providerPoolManager && pooluuid) {
// 400 报错码通常是请求参数问题,不记录为提供商错误
- if (error.code === 400) {
+ if (error.response?.status === 400) {
logger.info(`[Provider Pool] Skipping unhealthy marking for ${toProvider} (${pooluuid}) due to status 400 (client error)`);
} else {
logger.info(`[Provider Pool] Marking ${toProvider} as unhealthy due to stream error (status: ${status || 'unknown'})`);
@@ -692,7 +692,7 @@ export async function handleUnaryRequest(res, service, model, requestBody, fromP
// 如果底层未标记,且不跳过错误计数,则在此处标记
if (!credentialMarkedUnhealthy && !skipErrorCount && providerPoolManager && pooluuid) {
// 400 报错码通常是请求参数问题,不记录为提供商错误
- if (error.code === 400) {
+ if (error.response?.status === 400) {
logger.info(`[Provider Pool] Skipping unhealthy marking for ${toProvider} (${pooluuid}) due to status 400 (client error)`);
} else {
logger.info(`[Provider Pool] Marking ${toProvider} as unhealthy due to unary error (status: ${status || 'unknown'})`);