feat(core): 将 Tavily API Key 从环境变量迁移到系统配置
- 新增 ServiceConfig 类型和 services 配置字段 - 添加 getServiceApiKey/saveServiceConfig/deleteServiceConfig API - 更新 web_search 和 web_extract 工具使用配置系统 - 新增 /api/services REST 端点管理第三方服务配置
This commit is contained in:
@@ -297,6 +297,11 @@ export {
|
||||
createOpenAICompatibleFactory,
|
||||
isValidProviderId,
|
||||
isValidUrl,
|
||||
// Service config
|
||||
getServiceConfig,
|
||||
getServiceApiKey,
|
||||
saveServiceConfig,
|
||||
deleteServiceConfig,
|
||||
} from './provider/index.js';
|
||||
|
||||
export type {
|
||||
@@ -313,6 +318,8 @@ export type {
|
||||
ProvidersConfigFile,
|
||||
ProviderListItem,
|
||||
ProviderDetail,
|
||||
ServiceConfig,
|
||||
ServiceType,
|
||||
} from './provider/index.js';
|
||||
|
||||
// File Index
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import type { ProvidersConfigFile, CustomProviderDefinition, ProviderConfig } from './types.js';
|
||||
import type { ProvidersConfigFile, CustomProviderDefinition, ProviderConfig, ServiceConfig, ServiceType } from './types.js';
|
||||
import { getConfigDir as getGlobalConfigDir } from '../constants/paths.js';
|
||||
|
||||
/** 配置文件名 */
|
||||
@@ -28,7 +28,7 @@ export async function loadProvidersConfig(): Promise<ProvidersConfigFile> {
|
||||
const configPath = getConfigPath();
|
||||
|
||||
if (!existsSync(configPath)) {
|
||||
return { providers: {}, configs: {} };
|
||||
return { providers: {}, configs: {}, services: {} };
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -37,10 +37,11 @@ export async function loadProvidersConfig(): Promise<ProvidersConfigFile> {
|
||||
return {
|
||||
providers: config.providers ?? {},
|
||||
configs: config.configs ?? {},
|
||||
services: config.services ?? {},
|
||||
};
|
||||
} catch {
|
||||
// 解析失败返回空配置
|
||||
return { providers: {}, configs: {} };
|
||||
return { providers: {}, configs: {}, services: {} };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,3 +84,43 @@ export function mergeProviderConfig(
|
||||
enabled: config?.enabled ?? true,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务配置
|
||||
*/
|
||||
export async function getServiceConfig(serviceId: ServiceType): Promise<ServiceConfig | undefined> {
|
||||
const config = await loadProvidersConfig();
|
||||
return config.services?.[serviceId];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取服务 API Key
|
||||
*/
|
||||
export async function getServiceApiKey(serviceId: ServiceType): Promise<string | undefined> {
|
||||
const serviceConfig = await getServiceConfig(serviceId);
|
||||
if (serviceConfig?.enabled === false) {
|
||||
return undefined;
|
||||
}
|
||||
return serviceConfig?.apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存服务配置
|
||||
*/
|
||||
export async function saveServiceConfig(serviceId: ServiceType, serviceConfig: Omit<ServiceConfig, 'id'>): Promise<void> {
|
||||
const config = await loadProvidersConfig();
|
||||
config.services = config.services ?? {};
|
||||
config.services[serviceId] = { ...serviceConfig, id: serviceId };
|
||||
await saveProvidersConfig(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除服务配置
|
||||
*/
|
||||
export async function deleteServiceConfig(serviceId: ServiceType): Promise<void> {
|
||||
const config = await loadProvidersConfig();
|
||||
if (config.services) {
|
||||
delete config.services[serviceId];
|
||||
await saveProvidersConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ export type {
|
||||
ProvidersConfigFile,
|
||||
ProviderListItem,
|
||||
ProviderDetail,
|
||||
ServiceConfig,
|
||||
ServiceType,
|
||||
} from './types.js';
|
||||
|
||||
// Registry
|
||||
@@ -42,6 +44,10 @@ export {
|
||||
saveProvidersConfig,
|
||||
resolveApiKey,
|
||||
getConfigPath,
|
||||
getServiceConfig,
|
||||
getServiceApiKey,
|
||||
saveServiceConfig,
|
||||
deleteServiceConfig,
|
||||
} from './config.js';
|
||||
|
||||
// Utils
|
||||
|
||||
@@ -122,8 +122,23 @@ export interface ProvidersConfigFile {
|
||||
providers?: Record<string, CustomProviderDefinition>;
|
||||
/** 提供商配置(API Key、选项等) */
|
||||
configs?: Record<string, ProviderConfig>;
|
||||
/** 第三方服务配置(如 Tavily) */
|
||||
services?: Record<string, ServiceConfig>;
|
||||
}
|
||||
|
||||
/** 第三方服务配置 */
|
||||
export interface ServiceConfig {
|
||||
/** 服务 ID */
|
||||
id: string;
|
||||
/** API Key */
|
||||
apiKey?: string;
|
||||
/** 是否启用 */
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
/** 已知的服务类型 */
|
||||
export type ServiceType = 'tavily';
|
||||
|
||||
/** 提供商列表项(API 响应用) */
|
||||
export interface ProviderListItem {
|
||||
id: string;
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { ToolResult } from '../../types/index.js';
|
||||
import type { ToolWithMetadata } from '../types.js';
|
||||
import { loadDescription } from '../load_description.js';
|
||||
import { getPermissionManager } from '../../permission/index.js';
|
||||
import { getServiceApiKey } from '../../provider/index.js';
|
||||
|
||||
export const webExtractTool: ToolWithMetadata = {
|
||||
name: 'web_extract',
|
||||
@@ -72,14 +73,14 @@ export const webExtractTool: ToolWithMetadata = {
|
||||
};
|
||||
}
|
||||
|
||||
// 获取 Tavily API Key(从环境变量)
|
||||
const apiKey = process.env.TAVILY_API_KEY;
|
||||
// 获取 Tavily API Key(从配置文件)
|
||||
const apiKey = await getServiceApiKey('tavily');
|
||||
|
||||
if (!apiKey) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: '未配置 Tavily API Key。请设置环境变量 TAVILY_API_KEY。',
|
||||
error: '未配置 Tavily API Key。请在设置中配置 Tavily 服务的 API Key。',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { ToolResult } from '../../types/index.js';
|
||||
import type { ToolWithMetadata } from '../types.js';
|
||||
import { loadDescription } from '../load_description.js';
|
||||
import { getPermissionManager } from '../../permission/index.js';
|
||||
import { getServiceApiKey } from '../../provider/index.js';
|
||||
|
||||
export const webSearchTool: ToolWithMetadata = {
|
||||
name: 'web_search',
|
||||
@@ -74,14 +75,14 @@ export const webSearchTool: ToolWithMetadata = {
|
||||
};
|
||||
}
|
||||
|
||||
// 获取 Tavily API Key(从环境变量)
|
||||
const apiKey = process.env.TAVILY_API_KEY;
|
||||
// 获取 Tavily API Key(从配置文件)
|
||||
const apiKey = await getServiceApiKey('tavily');
|
||||
|
||||
if (!apiKey) {
|
||||
return {
|
||||
success: false,
|
||||
output: '',
|
||||
error: '未配置 Tavily API Key。请设置环境变量 TAVILY_API_KEY。',
|
||||
error: '未配置 Tavily API Key。请在设置中配置 Tavily 服务的 API Key。',
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user