fix(provider): 修复健康检查逻辑并添加checkModelName字段
实现实际的健康检查逻辑,通过临时服务适配器进行API调用验证 为所有provider配置添加checkModelName字段用于健康检查 修正初始化日志中的服务名称错误
This commit is contained in:
parent
7ca3763d33
commit
bd30a5f8d3
3 changed files with 88 additions and 11 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
{
|
{
|
||||||
"OPENAI_API_KEY": "sk-openai-key1",
|
"OPENAI_API_KEY": "sk-openai-key1",
|
||||||
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
||||||
|
"checkModelName": null,
|
||||||
"uuid": "2f579c65-d3c5-41b1-9985-9f6e3d7bf39c",
|
"uuid": "2f579c65-d3c5-41b1-9985-9f6e3d7bf39c",
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
|
|
@ -13,6 +14,7 @@
|
||||||
{
|
{
|
||||||
"OPENAI_API_KEY": "sk-openai-key2",
|
"OPENAI_API_KEY": "sk-openai-key2",
|
||||||
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
"OPENAI_BASE_URL": "https://api.openai.com/v1",
|
||||||
|
"checkModelName": null,
|
||||||
"uuid": "e284628d-302f-456d-91f3-6095386fb3b8",
|
"uuid": "e284628d-302f-456d-91f3-6095386fb3b8",
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
|
|
@ -25,6 +27,7 @@
|
||||||
{
|
{
|
||||||
"GEMINI_OAUTH_CREDS_FILE_PATH": "./credentials1.json",
|
"GEMINI_OAUTH_CREDS_FILE_PATH": "./credentials1.json",
|
||||||
"PROJECT_ID": "your-project-id-1",
|
"PROJECT_ID": "your-project-id-1",
|
||||||
|
"checkModelName": null,
|
||||||
"uuid": "ac200154-26b8-4f5f-8650-e8cc738b06e3",
|
"uuid": "ac200154-26b8-4f5f-8650-e8cc738b06e3",
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
|
|
@ -35,6 +38,7 @@
|
||||||
{
|
{
|
||||||
"GEMINI_OAUTH_CREDS_FILE_PATH": "./credentials2.json",
|
"GEMINI_OAUTH_CREDS_FILE_PATH": "./credentials2.json",
|
||||||
"PROJECT_ID": "your-project-id-2",
|
"PROJECT_ID": "your-project-id-2",
|
||||||
|
"checkModelName": null,
|
||||||
"uuid": "4f8afcc2-a9bb-4b96-bb50-3b9667a71f54",
|
"uuid": "4f8afcc2-a9bb-4b96-bb50-3b9667a71f54",
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
|
|
@ -47,6 +51,7 @@
|
||||||
{
|
{
|
||||||
"CLAUDE_API_KEY": "sk-claude-key1",
|
"CLAUDE_API_KEY": "sk-claude-key1",
|
||||||
"CLAUDE_BASE_URL": "https://api.anthropic.com",
|
"CLAUDE_BASE_URL": "https://api.anthropic.com",
|
||||||
|
"checkModelName": null,
|
||||||
"uuid": "bb87047a-3b1d-4249-adbb-1087ecd58128",
|
"uuid": "bb87047a-3b1d-4249-adbb-1087ecd58128",
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
|
|
@ -57,6 +62,7 @@
|
||||||
{
|
{
|
||||||
"CLAUDE_API_KEY": "sk-claude-key2",
|
"CLAUDE_API_KEY": "sk-claude-key2",
|
||||||
"CLAUDE_BASE_URL": "https://api.anthropic.com",
|
"CLAUDE_BASE_URL": "https://api.anthropic.com",
|
||||||
|
"checkModelName": null,
|
||||||
"uuid": "7c2002c6-122a-4db0-af06-8a0ff433801a",
|
"uuid": "7c2002c6-122a-4db0-af06-8a0ff433801a",
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
|
|
@ -69,6 +75,7 @@
|
||||||
{
|
{
|
||||||
"KIRO_OAUTH_CREDS_FILE_PATH": "./kiro_creds1.json",
|
"KIRO_OAUTH_CREDS_FILE_PATH": "./kiro_creds1.json",
|
||||||
"uuid": "2c69d0ac-b86f-43d8-9d17-0d300afc5cfd",
|
"uuid": "2c69d0ac-b86f-43d8-9d17-0d300afc5cfd",
|
||||||
|
"checkModelName": null,
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
"usageCount": 0,
|
"usageCount": 0,
|
||||||
|
|
@ -78,6 +85,7 @@
|
||||||
{
|
{
|
||||||
"KIRO_OAUTH_CREDS_FILE_PATH": "./kiro_creds2.json",
|
"KIRO_OAUTH_CREDS_FILE_PATH": "./kiro_creds2.json",
|
||||||
"uuid": "7482abe6-8083-4288-bb7d-d8ecb7c461e2",
|
"uuid": "7482abe6-8083-4288-bb7d-d8ecb7c461e2",
|
||||||
|
"checkModelName": null,
|
||||||
"isHealthy": true,
|
"isHealthy": true,
|
||||||
"lastUsed": null,
|
"lastUsed": null,
|
||||||
"usageCount": 0,
|
"usageCount": 0,
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ export class KiroApiService {
|
||||||
|
|
||||||
async initialize() {
|
async initialize() {
|
||||||
if (this.isInitialized) return;
|
if (this.isInitialized) return;
|
||||||
console.log('[Kiro] Initializing Gemini API Service...');
|
console.log('[Kiro] Initializing Kiro API Service...');
|
||||||
await this.initializeAuth();
|
await this.initializeAuth();
|
||||||
const macSha256 = await getMacAddressSha256();
|
const macSha256 = await getMacAddressSha256();
|
||||||
this.axiosInstance = axios.create({
|
this.axiosInstance = axios.create({
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
import * as fs from 'fs'; // Import fs module
|
import * as fs from 'fs'; // Import fs module
|
||||||
|
import { getServiceAdapter } from './adapter.js';
|
||||||
|
import { MODEL_PROVIDER } from './common.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages a pool of API service providers, handling their health and selection.
|
* Manages a pool of API service providers, handling their health and selection.
|
||||||
|
|
@ -146,17 +148,22 @@ export class ProviderPoolManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO: Implement actual health check logic for each provider type
|
// Perform actual health check based on provider type
|
||||||
// For now, if a provider was unhealthy and enough time has passed,
|
const isHealthy = await this._checkProviderHealth(providerType, providerConfig);
|
||||||
// we optimistically mark it healthy and reset error count.
|
|
||||||
// A more robust system would involve actual API calls or pings here.
|
if (isHealthy) {
|
||||||
if (!providerStatus.config.isHealthy) {
|
if (!providerStatus.config.isHealthy) {
|
||||||
// Only reset and mark healthy if it was unhealthy and we are attempting a check after interval
|
// Provider was unhealthy but is now healthy
|
||||||
this.markProviderHealthy(providerType, providerConfig);
|
this.markProviderHealthy(providerType, providerConfig);
|
||||||
console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Marked Healthy (re-evaluation)`);
|
console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Marked Healthy (actual check)`);
|
||||||
|
} else {
|
||||||
|
// Provider was already healthy and still is
|
||||||
|
console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Still Healthy`);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// For already healthy providers, just log or perform a lighter check if needed
|
// Provider is not healthy
|
||||||
console.log(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}): Still Healthy`);
|
console.warn(`[ProviderPoolManager] Health check for ${JSON.stringify(providerConfig)} (${providerType}) failed: Provider is not responding correctly.`);
|
||||||
|
this.markProviderUnhealthy(providerType, providerConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -167,6 +174,68 @@ export class ProviderPoolManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs an actual health check for a specific provider.
|
||||||
|
* @param {string} providerType - The type of the provider.
|
||||||
|
* @param {object} providerConfig - The configuration of the provider to check.
|
||||||
|
* @returns {Promise<boolean>} - True if the provider is healthy, false otherwise.
|
||||||
|
*/
|
||||||
|
async _checkProviderHealth(providerType, providerConfig) {
|
||||||
|
try {
|
||||||
|
// Create a temporary service adapter for health check
|
||||||
|
const tempConfig = { ...providerConfig, MODEL_PROVIDER: providerType };
|
||||||
|
const serviceAdapter = getServiceAdapter(tempConfig);
|
||||||
|
|
||||||
|
// Determine a suitable model name for health check
|
||||||
|
// First, try to get it from the provider configuration
|
||||||
|
let modelName = providerConfig.checkModelName;
|
||||||
|
|
||||||
|
// If not specified in config, use default model names based on provider type
|
||||||
|
if (!modelName) {
|
||||||
|
switch (providerType) {
|
||||||
|
case MODEL_PROVIDER.GEMINI_CLI:
|
||||||
|
modelName = 'gemini-2.5-flash'; // Example model name for Gemini
|
||||||
|
break;
|
||||||
|
case MODEL_PROVIDER.OPENAI_CUSTOM:
|
||||||
|
modelName = 'gpt-3.5-turbo'; // Example model name for OpenAI
|
||||||
|
break;
|
||||||
|
case MODEL_PROVIDER.CLAUDE_CUSTOM:
|
||||||
|
modelName = 'claude-3-7-sonnet-20250219'; // Example model name for Claude
|
||||||
|
break;
|
||||||
|
case MODEL_PROVIDER.KIRO_API:
|
||||||
|
modelName = 'claude-3-7-sonnet-20250219'; // Example model name for Kiro API
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`[ProviderPoolManager] Unknown provider type for health check: ${providerType}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform a lightweight API call to check health
|
||||||
|
const healthCheckRequest = {
|
||||||
|
contents: [{
|
||||||
|
role: 'user',
|
||||||
|
parts: [{ text: 'Hello, are you ok?' }]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
// For OpenAI and Claude providers, we need a different request format
|
||||||
|
if (providerType === MODEL_PROVIDER.OPENAI_CUSTOM || providerType === MODEL_PROVIDER.CLAUDE_CUSTOM || providerType === MODEL_PROVIDER.KIRO_API) {
|
||||||
|
healthCheckRequest.messages = [{ role: 'user', content: 'Hello, are you ok?' }];
|
||||||
|
healthCheckRequest.model = modelName;
|
||||||
|
delete healthCheckRequest.contents;
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(`[ProviderPoolManager] Health check request for ${modelName}: ${JSON.stringify(healthCheckRequest)}`);
|
||||||
|
await serviceAdapter.generateContent(modelName, healthCheckRequest);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[ProviderPoolManager] Health check failed for ${providerType}: ${error.message}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the current provider pools configuration to the JSON file.
|
* Saves the current provider pools configuration to the JSON file.
|
||||||
* @private
|
* @private
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue