Files
ai-terminal-assistant/packages/server/src/routes/services.ts
T
kurihada 2afa7bb103 feat(core): 将 Tavily API Key 从环境变量迁移到系统配置
- 新增 ServiceConfig 类型和 services 配置字段
- 添加 getServiceApiKey/saveServiceConfig/deleteServiceConfig API
- 更新 web_search 和 web_extract 工具使用配置系统
- 新增 /api/services REST 端点管理第三方服务配置
2025-12-17 13:01:29 +08:00

156 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Services API Routes
*
* 第三方服务配置管理 REST API(如 Tavily
*/
import { Hono } from 'hono';
import type { ServiceConfig, ServiceType } from '@ai-assistant/core';
import {
loadProvidersConfig,
getServiceConfig,
saveServiceConfig,
deleteServiceConfig,
} from '@ai-assistant/core';
export const servicesRouter = new Hono();
/** 服务元信息 */
interface ServiceInfo {
id: ServiceType;
name: string;
description: string;
website: string;
}
/** 已知服务列表 */
const KNOWN_SERVICES: ServiceInfo[] = [
{
id: 'tavily',
name: 'Tavily',
description: '网络搜索和网页内容提取 API',
website: 'https://tavily.com',
},
];
/**
* GET /services - List all services
*/
servicesRouter.get('/', async (c) => {
try {
const config = await loadProvidersConfig();
const services = config.services ?? {};
const data = KNOWN_SERVICES.map((info) => {
const serviceConfig = services[info.id];
return {
...info,
enabled: serviceConfig?.enabled ?? false,
hasApiKey: !!serviceConfig?.apiKey,
};
});
return c.json({
success: true,
data,
});
} catch (error) {
return c.json(
{
success: false,
error: error instanceof Error ? error.message : 'Failed to list services',
},
500
);
}
});
/**
* GET /services/:id - Get service config
*/
servicesRouter.get('/:id', async (c) => {
const id = c.req.param('id') as ServiceType;
try {
const info = KNOWN_SERVICES.find((s) => s.id === id);
if (!info) {
return c.json({ success: false, error: `Unknown service: ${id}` }, 404);
}
const serviceConfig = await getServiceConfig(id);
return c.json({
success: true,
data: {
...info,
enabled: serviceConfig?.enabled ?? false,
hasApiKey: !!serviceConfig?.apiKey,
},
});
} catch (error) {
return c.json(
{
success: false,
error: error instanceof Error ? error.message : 'Failed to get service',
},
500
);
}
});
/**
* PUT /services/:id - Update service config
*/
servicesRouter.put('/:id', async (c) => {
const id = c.req.param('id') as ServiceType;
try {
const info = KNOWN_SERVICES.find((s) => s.id === id);
if (!info) {
return c.json({ success: false, error: `Unknown service: ${id}` }, 404);
}
const body = await c.req.json();
const { apiKey, enabled } = body as { apiKey?: string; enabled?: boolean };
await saveServiceConfig(id, { apiKey, enabled });
return c.json({
success: true,
message: `Service ${id} config updated`,
});
} catch (error) {
return c.json(
{
success: false,
error: error instanceof Error ? error.message : 'Failed to update service config',
},
400
);
}
});
/**
* DELETE /services/:id - Delete service config
*/
servicesRouter.delete('/:id', async (c) => {
const id = c.req.param('id') as ServiceType;
try {
await deleteServiceConfig(id);
return c.json({
success: true,
message: `Service ${id} config removed`,
});
} catch (error) {
return c.json(
{
success: false,
error: error instanceof Error ? error.message : 'Failed to remove service config',
},
400
);
}
});