feat(kiro): 增强账号池健康检查配置并优化凭证加载逻辑

为 provider_pools.json 配置文件新增 checkHealth 字段,允许灵活控制各账号的健康检查行为。同时重构 Kiro OAuth 凭证加载机制,统一处理指定文件和目录扫描的逻辑,提升凭证管理的可靠性。

此外,在多语言 README 文档中补充 10.18 版本更新说明,告知用户 Kiro 服务的最新动态。
This commit is contained in:
hex2077 2025-10-18 16:12:13 +08:00
parent 52417dd805
commit 5d4283edc6
6 changed files with 47 additions and 31 deletions

View file

@ -28,6 +28,8 @@
> 8.29 Added account pool mode, which supports multiple accounts for all providers, with built-in polling, failover (requires client retry), and configuration degradation. Requires adding PROVIDER_POOLS_FILE_PATH to config, see the configuration file: provider_pools.json for details. > 8.29 Added account pool mode, which supports multiple accounts for all providers, with built-in polling, failover (requires client retry), and configuration degradation. Requires adding PROVIDER_POOLS_FILE_PATH to config, see the configuration file: provider_pools.json for details.
> >
> 9.1 Added Qwen Code CLI support, can use qwen3-coder-plus model > 9.1 Added Qwen Code CLI support, can use qwen3-coder-plus model
>
> 10.18 Kiro open registration, new accounts get 500 credits, now supports Claude Sonnet4.5
--- ---

View file

@ -29,6 +29,8 @@
> 8.29 アカウントプールモードを追加。すべてのプロバイダーで複数アカウントの設定をサポート。ラウンドロビン、フェイルオーバークライアント再試行必要、設定ダウングレードを内蔵。configでPROVIDER_POOLS_FILE_PATH設定が必要。詳細は設定ファイルprovider_pools.json参照 > 8.29 アカウントプールモードを追加。すべてのプロバイダーで複数アカウントの設定をサポート。ラウンドロビン、フェイルオーバークライアント再試行必要、設定ダウングレードを内蔵。configでPROVIDER_POOLS_FILE_PATH設定が必要。詳細は設定ファイルprovider_pools.json参照
> >
> 9.1 Qwen Code CLIサポートを密かに追加、qwen3-coder-plusモデルが使用可能 > 9.1 Qwen Code CLIサポートを密かに追加、qwen3-coder-plusモデルが使用可能
>
> 10.18 Kiroはオープン登録、新規アカウントに500クレジット付与、Claude Sonnet4.5に対応
--- ---

View file

@ -29,6 +29,8 @@
> 8.29 新增账号池模式可支持所有provider配置多个账号自带轮询故障转移需要客户端重试和配置降级。需要在 config 新增配置 PROVIDER_POOLS_FILE_PATH 详见配置文件provider_pools.json > 8.29 新增账号池模式可支持所有provider配置多个账号自带轮询故障转移需要客户端重试和配置降级。需要在 config 新增配置 PROVIDER_POOLS_FILE_PATH 详见配置文件provider_pools.json
> >
> 9.1 偷摸的新增 Qwen Code CLI 支持,可使用 qwen3-coder-plus 模型 > 9.1 偷摸的新增 Qwen Code CLI 支持,可使用 qwen3-coder-plus 模型
>
> 10.18 Kiro开放注册新号送500额度已支持Claude Sonnet4.5
--- ---

View file

@ -4,6 +4,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, "checkModelName": null,
"checkHealth": true,
"uuid": "2f579c65-d3c5-41b1-9985-9f6e3d7bf39c", "uuid": "2f579c65-d3c5-41b1-9985-9f6e3d7bf39c",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -15,6 +16,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, "checkModelName": null,
"checkHealth": true,
"uuid": "e284628d-302f-456d-91f3-6095386fb3b8", "uuid": "e284628d-302f-456d-91f3-6095386fb3b8",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -28,6 +30,7 @@
"OPENAI_API_KEY": "sk-openai-key", "OPENAI_API_KEY": "sk-openai-key",
"OPENAI_BASE_URL": "https://api.openai.com/v1", "OPENAI_BASE_URL": "https://api.openai.com/v1",
"checkModelName": null, "checkModelName": null,
"checkHealth": true,
"uuid": "e284628d-302f-456d-91f3-609538678968", "uuid": "e284628d-302f-456d-91f3-609538678968",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -41,6 +44,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, "checkModelName": null,
"checkHealth": true,
"uuid": "ac200154-26b8-4f5f-8650-e8cc738b06e3", "uuid": "ac200154-26b8-4f5f-8650-e8cc738b06e3",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -52,6 +56,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, "checkModelName": null,
"checkHealth": true,
"uuid": "4f8afcc2-a9bb-4b96-bb50-3b9667a71f54", "uuid": "4f8afcc2-a9bb-4b96-bb50-3b9667a71f54",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -65,6 +70,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, "checkModelName": null,
"checkHealth": true,
"uuid": "bb87047a-3b1d-4249-adbb-1087ecd58128", "uuid": "bb87047a-3b1d-4249-adbb-1087ecd58128",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -76,6 +82,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, "checkModelName": null,
"checkHealth": true,
"uuid": "7c2002c6-122a-4db0-af06-8a0ff433801a", "uuid": "7c2002c6-122a-4db0-af06-8a0ff433801a",
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
@ -89,6 +96,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, "checkModelName": null,
"checkHealth": true,
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
"usageCount": 0, "usageCount": 0,
@ -99,6 +107,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, "checkModelName": null,
"checkHealth": true,
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
"usageCount": 0, "usageCount": 0,
@ -111,6 +120,7 @@
"QWEN_OAUTH_CREDS_FILE_PATH": "./qwen_creds.json", "QWEN_OAUTH_CREDS_FILE_PATH": "./qwen_creds.json",
"uuid": "658a2114-c4c9-d713-b8d4-ceabf0e0bf18", "uuid": "658a2114-c4c9-d713-b8d4-ceabf0e0bf18",
"checkModelName": null, "checkModelName": null,
"checkHealth": true,
"isHealthy": true, "isHealthy": true,
"lastUsed": null, "lastUsed": null,
"usageCount": 0, "usageCount": 0,

View file

@ -336,41 +336,38 @@ async initializeAuth(forceRefresh = false) {
this.base64Creds = null; this.base64Creds = null;
} }
// Priority 2: Load from a specific file path if provided and not already loaded from token file // Priority 2 & 3 合并: 从指定文件路径或目录加载凭证
const credPath = this.credsFilePath || path.join(this.credPath, KIRO_AUTH_TOKEN_FILE); // 读取指定的 credPath 文件以及目录下的其他 JSON 文件(排除当前文件)
if (credPath) { const targetFilePath = this.credsFilePath || path.join(this.credPath, KIRO_AUTH_TOKEN_FILE);
console.debug(`[Kiro Auth] Attempting to load credentials from specified file: ${credPath}`); const dirPath = path.dirname(targetFilePath);
const credentialsFromFile = await loadCredentialsFromFile(credPath); const targetFileName = path.basename(targetFilePath);
if (credentialsFromFile) {
Object.assign(mergedCredentials, credentialsFromFile); console.debug(`[Kiro Auth] Attempting to load credentials from directory: ${dirPath}`);
console.info(`[Kiro Auth] Successfully loaded credentials from ${credPath}.`);
} else { try {
console.warn(`[Kiro Auth] Could not load credentials from specified file path: ${credPath}`); // 首先尝试读取目标文件
const targetCredentials = await loadCredentialsFromFile(targetFilePath);
if (targetCredentials) {
Object.assign(mergedCredentials, targetCredentials);
console.info(`[Kiro Auth] Successfully loaded OAuth credentials from ${targetFilePath}`);
} }
}
// 然后读取目录下的其他 JSON 文件(排除目标文件本身)
// Priority 3: Load from default directory only if no specific file path is configured const files = await fs.readdir(dirPath);
if (!this.credsFilePath) { for (const file of files) {
const dirPath = this.credPath; if (file.endsWith('.json') && file !== targetFileName) {
console.debug(`[Kiro Auth] Attempting to load credentials from directory: ${dirPath}`); const filePath = path.join(dirPath, file);
try { const credentials = await loadCredentialsFromFile(filePath);
const files = await fs.readdir(dirPath); if (credentials) {
for (const file of files) { // 保留已有的 expiresAt,避免被覆盖
if (file.endsWith('.json') && file !== KIRO_AUTH_TOKEN_FILE) { credentials.expiresAt = mergedCredentials.expiresAt;
const filePath = path.join(dirPath, file); Object.assign(mergedCredentials, credentials);
const credentials = await loadCredentialsFromFile(filePath); console.debug(`[Kiro Auth] Loaded Client credentials from ${file}`);
if (credentials) {
credentials.expiresAt = mergedCredentials.expiresAt;
Object.assign(mergedCredentials, credentials);
console.debug(`[Kiro Auth] Loaded credentials from ${file}`);
}
} }
} }
} catch (error) {
console.debug(`[Kiro Auth] Could not read credential directory ${dirPath}: ${error.message}`);
} }
} else { } catch (error) {
console.debug(`[Kiro Auth] Skipping directory scan because specific file path is configured: ${this.credsFilePath}`); console.warn(`[Kiro Auth] Error loading credentials from directory ${dirPath}: ${error.message}`);
} }
// console.log('[Kiro Auth] Merged credentials:', mergedCredentials); // console.log('[Kiro Auth] Merged credentials:', mergedCredentials);

View file

@ -189,6 +189,9 @@ export class ProviderPoolManager {
// Create a temporary service adapter for health check // Create a temporary service adapter for health check
const tempConfig = { ...providerConfig, MODEL_PROVIDER: providerType }; const tempConfig = { ...providerConfig, MODEL_PROVIDER: providerType };
const serviceAdapter = getServiceAdapter(tempConfig); const serviceAdapter = getServiceAdapter(tempConfig);
if(!providerConfig.checkHealth){
return true;
}
// Determine a suitable model name for health check // Determine a suitable model name for health check
// First, try to get it from the provider configuration // First, try to get it from the provider configuration