diff --git a/src/claude/claude-core.js b/src/claude/claude-core.js index 13273cd..01789d2 100644 --- a/src/claude/claude-core.js +++ b/src/claude/claude-core.js @@ -1,4 +1,6 @@ import axios from 'axios'; +import * as http from 'http'; +import * as https from 'https'; /** * Claude API Core Service Class. @@ -27,8 +29,24 @@ export class ClaudeApiService { * @returns {object} Axios instance. */ createClient() { + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: this.baseUrl, + httpAgent, + httpsAgent, headers: { 'x-api-key': this.apiKey, 'Content-Type': 'application/json', diff --git a/src/claude/claude-kiro.js b/src/claude/claude-kiro.js index 7e08576..bce1a17 100644 --- a/src/claude/claude-kiro.js +++ b/src/claude/claude-kiro.js @@ -308,15 +308,15 @@ export class KiroApiService { // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 const httpAgent = new http.Agent({ keepAlive: true, - maxSockets: 200, // 每个主机最多 10 个连接 + maxSockets: 100, // 每个主机最多 10 个连接 maxFreeSockets: 5, // 最多保留 5 个空闲连接 - timeout: 60000, // 空闲连接 60 秒后关闭 + timeout: 120000, // 空闲连接 60 秒后关闭 }); const httpsAgent = new https.Agent({ keepAlive: true, maxSockets: 100, maxFreeSockets: 5, - timeout: 60000, + timeout: 120000, }); const axiosConfig = { diff --git a/src/gemini/antigravity-core.js b/src/gemini/antigravity-core.js index 7692232..0c10915 100644 --- a/src/gemini/antigravity-core.js +++ b/src/gemini/antigravity-core.js @@ -1,5 +1,6 @@ import { OAuth2Client } from 'google-auth-library'; import * as http from 'http'; +import * as https from 'https'; import { promises as fs } from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -9,6 +10,20 @@ import open from 'open'; import { API_ACTIONS, formatExpiryTime } from '../common.js'; import { getProviderModels } from '../provider-models.js'; +// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 +const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); +const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); + // --- Constants --- const AUTH_REDIRECT_PORT = 8086; const CREDENTIALS_DIR = '.antigravity'; @@ -210,7 +225,14 @@ function ensureRolesInContents(requestBody) { export class AntigravityApiService { constructor(config) { - this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET); + // 配置 OAuth2Client 使用自定义的 HTTP agent + this.authClient = new OAuth2Client({ + clientId: OAUTH_CLIENT_ID, + clientSecret: OAUTH_CLIENT_SECRET, + transporterOptions: { + agent: httpsAgent, + }, + }); this.availableModels = []; this.isInitialized = false; diff --git a/src/gemini/gemini-core.js b/src/gemini/gemini-core.js index eee6791..fa0adf0 100644 --- a/src/gemini/gemini-core.js +++ b/src/gemini/gemini-core.js @@ -1,5 +1,6 @@ import { OAuth2Client } from 'google-auth-library'; import * as http from 'http'; +import * as https from 'https'; import { promises as fs } from 'fs'; import * as path from 'path'; import * as os from 'os'; @@ -8,6 +9,20 @@ import open from 'open'; import { API_ACTIONS, formatExpiryTime } from '../common.js'; import { getProviderModels } from '../provider-models.js'; +// 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 +const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); +const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, +}); + // --- Constants --- const AUTH_REDIRECT_PORT = 8085; const CREDENTIALS_DIR = '.gemini'; @@ -177,7 +192,14 @@ async function* apply_anti_truncation_to_stream(service, model, requestBody) { export class GeminiApiService { constructor(config) { - this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET); + // 配置 OAuth2Client 使用自定义的 HTTP agent + this.authClient = new OAuth2Client({ + clientId: OAUTH_CLIENT_ID, + clientSecret: OAUTH_CLIENT_SECRET, + transporterOptions: { + agent: httpsAgent, + }, + }); this.availableModels = []; this.isInitialized = false; diff --git a/src/openai/openai-core.js b/src/openai/openai-core.js index e966f62..ad77b90 100644 --- a/src/openai/openai-core.js +++ b/src/openai/openai-core.js @@ -1,4 +1,6 @@ import axios from 'axios'; +import * as http from 'http'; +import * as https from 'https'; // Assumed OpenAI API specification service for interacting with third-party models export class OpenAIApiService { @@ -12,8 +14,24 @@ export class OpenAIApiService { this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false; console.log(`[OpenAI] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`); + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: this.baseUrl, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` diff --git a/src/openai/openai-responses-core.js b/src/openai/openai-responses-core.js index 9052acc..80e15c5 100644 --- a/src/openai/openai-responses-core.js +++ b/src/openai/openai-responses-core.js @@ -1,4 +1,6 @@ import axios from 'axios'; +import * as http from 'http'; +import * as https from 'https'; // OpenAI Responses API specification service for interacting with third-party models export class OpenAIResponsesApiService { @@ -9,14 +11,39 @@ export class OpenAIResponsesApiService { this.config = config; this.apiKey = config.OPENAI_API_KEY; this.baseUrl = config.OPENAI_BASE_URL || 'https://api.openai.com/v1'; - // console.log(`[OpenAIResponsesApiService] Base URL: ${JSON.stringify(config)}`); - this.axiosInstance = axios.create({ + this.useSystemProxy = config?.USE_SYSTEM_PROXY_OPENAI ?? false; + console.log(`[OpenAIResponses] System proxy ${this.useSystemProxy ? 'enabled' : 'disabled'}`); + + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + + const axiosConfig = { baseURL: this.baseUrl, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}` } - }); + }; + + // 禁用系统代理以避免HTTPS代理错误 + if (!this.useSystemProxy) { + axiosConfig.proxy = false; + } + + this.axiosInstance = axios.create(axiosConfig); } async callApi(endpoint, body, isRetry = false, retryCount = 0) { diff --git a/src/openai/qwen-core.js b/src/openai/qwen-core.js index c830d90..61dc65b 100644 --- a/src/openai/qwen-core.js +++ b/src/openai/qwen-core.js @@ -3,6 +3,8 @@ import crypto from 'crypto'; import path from 'node:path'; import { promises as fs, unlinkSync } from 'node:fs'; import * as os from 'os'; +import * as http from 'http'; +import * as https from 'https'; import open from 'open'; import { EventEmitter } from 'events'; import { randomUUID } from 'node:crypto'; @@ -187,13 +189,28 @@ export class QwenApiService { console.log('[Qwen] Initializing Qwen API Service...'); await this._initializeAuth(); + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: DEFAULT_QWEN_BASE_URL, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer `, }, - }; // 禁用系统代理 @@ -501,8 +518,24 @@ export class QwenApiService { try { const { token, endpoint: qwenBaseUrl } = await this.getValidToken(); + // 配置 HTTP/HTTPS agent 限制连接池大小,避免资源泄漏 + const httpAgent = new http.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const httpsAgent = new https.Agent({ + keepAlive: true, + maxSockets: 100, + maxFreeSockets: 5, + timeout: 120000, + }); + const axiosConfig = { baseURL: qwenBaseUrl, + httpAgent, + httpsAgent, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, @@ -510,8 +543,6 @@ export class QwenApiService { 'X-DashScope-UserAgent': userAgent, 'X-DashScope-AuthType': 'qwen-oauth', }, - // 添加 HTTPS 代理修复相关配置 - httpsAgent: undefined, // axios-https-proxy-fix 会自动处理 }; // 禁用系统代理