feat: 插件-工具合并 — 创建 pkg/plugins 共享模块并移除 tool-engine
- 新增 backend/pkg/plugins/ 共享模块:SDK 接口、PluginManager、ToolRegistry(含环形缓冲区调用日志) - 13 个通用插件从 plugin-manager 迁移至共享模块(import 路径统一) - ai-core 切换至共享 ToolRegistry,进程内执行(零网络开销),包装 6 个专属工具 - plugin-manager 迁移至共享模块,保留管理 REST API - 新增 DevTools 插件管理面板(侧边栏 → 🔌 插件管理) - 移除 tool-engine 服务(从 go.work、DevTools 配置、编译系统) - 工具调用记录 API 从 Tool-Engine 迁至 AI-Core(/api/v1/tools/calls) - ai-core ContextStore 启动时从 PostgreSQL 恢复会话历史 - 清理所有过时引用和备份文件 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+1
-15
@@ -57,6 +57,7 @@ export const DEVTOOLS_PORT = process.env.DEVTOOLS_PORT || 9090;
|
||||
export const LOGS_DIR = path.resolve(__dirname, '../logs');
|
||||
export const GATEWAY_URL = process.env.GATEWAY_URL || 'http://localhost:8080';
|
||||
export const TOOL_ENGINE_URL = process.env.TOOL_ENGINE_URL || 'http://localhost:8092';
|
||||
export const PLUGIN_MANAGER_URL = process.env.PLUGIN_MANAGER_URL || 'http://localhost:8094';
|
||||
export const ADMIN_USERNAME = process.env.ADMIN_USERNAME || 'admin';
|
||||
export const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'cyrene-dev-admin';
|
||||
|
||||
@@ -124,21 +125,6 @@ export const SERVICES = {
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'tool-engine': {
|
||||
name: '工具引擎',
|
||||
cwd: path.join(ROOT, 'backend/tool-engine'),
|
||||
command: './main',
|
||||
env: {
|
||||
PORT: '8092',
|
||||
DB_URL: process.env.DB_URL || 'postgres://cyrene:cyrene_pass@localhost:5432/cyrene_ai?sslmode=disable',
|
||||
IOT_SERVICE_URL: process.env.IOT_SERVICE_URL || process.env.IOT_DEBUG_SERVICE_URL || 'http://localhost:8083',
|
||||
},
|
||||
healthUrl: 'http://localhost:8092/api/v1/health',
|
||||
port: 8092,
|
||||
buildCommand: 'go',
|
||||
buildArgs: ['build', '-o', isWin ? 'main.exe' : 'main', './cmd/main.go'],
|
||||
goBin: GO_BIN,
|
||||
},
|
||||
'voice-service': {
|
||||
name: '语音识别服务',
|
||||
cwd: path.join(ROOT, 'backend/voice-service'),
|
||||
|
||||
+60
-14
@@ -17,7 +17,7 @@ import { execSync, spawn } from 'child_process';
|
||||
|
||||
import { processManager } from './process-manager.js';
|
||||
import { performanceMonitor } from './performance.js';
|
||||
import { SERVICES, DEVTOOLS_PORT, LOGS_DIR, logFile, GATEWAY_URL, TOOL_ENGINE_URL, ADMIN_USERNAME, ADMIN_PASSWORD } from './config.js';
|
||||
import { SERVICES, DEVTOOLS_PORT, LOGS_DIR, logFile, GATEWAY_URL, PLUGIN_MANAGER_URL, ADMIN_USERNAME, ADMIN_PASSWORD } from './config.js';
|
||||
|
||||
const AI_CORE_URL = process.env.AI_CORE_URL || 'http://localhost:8081';
|
||||
const MEMORY_SERVICE_URL = process.env.MEMORY_SERVICE_URL || 'http://localhost:8091';
|
||||
@@ -594,16 +594,14 @@ app.get('/api/iot/devices/:id/history', async (req, res) => {
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
|
||||
// ---- 工具调用记录代理 (转发到 tool-engine) ----
|
||||
// ---- 插件管理代理 (转发到 plugin-manager) ----
|
||||
|
||||
/**
|
||||
* 代理请求到 Tool-Engine
|
||||
* @param {string} path - Tool-Engine API 路径
|
||||
* @param {object} opts - fetch 选项
|
||||
* 代理请求到 Plugin-Manager
|
||||
*/
|
||||
async function proxyToToolEngine(path, opts = {}) {
|
||||
const url = `${TOOL_ENGINE_URL}${path}`;
|
||||
const logPrefix = `[ToolEngine代理]`;
|
||||
async function proxyToPluginManager(path, opts = {}) {
|
||||
const url = `${PLUGIN_MANAGER_URL}${path}`;
|
||||
const logPrefix = `[PluginManager代理]`;
|
||||
try {
|
||||
console.log(`${logPrefix} ${opts.method || 'GET'} ${path}`);
|
||||
const resp = await fetch(url, {
|
||||
@@ -622,11 +620,11 @@ async function proxyToToolEngine(path, opts = {}) {
|
||||
return {
|
||||
status: 502,
|
||||
body: {
|
||||
error: `Tool-Engine 不可达: ${err.message}`,
|
||||
errorType: isConnRefused ? 'tool_engine_not_running' : 'tool_engine_unreachable',
|
||||
error: `插件管理器不可达: ${err.message}`,
|
||||
errorType: isConnRefused ? 'plugin_manager_not_running' : 'plugin_manager_unreachable',
|
||||
hint: isConnRefused
|
||||
? 'Tool-Engine 服务未启动,请先在「服务管理」面板中启动 Tool-Engine'
|
||||
: 'Tool-Engine 服务无响应,请检查网络连接和服务状态',
|
||||
? '插件管理器服务未启动,请先在「服务管理」面板中启动 plugin-manager'
|
||||
: '插件管理器服务无响应,请检查网络连接和服务状态',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -808,6 +806,18 @@ app.get('/api/model-config/fetch-models/:name', async (req, res) => {
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
|
||||
// ---- 思考调度配置代理 ----
|
||||
app.get('/api/thinking-schedule', async (_req, res) => {
|
||||
const result = await proxyToGateway('/api/v1/admin/thinking-schedule');
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.put('/api/thinking-schedule', async (req, res) => {
|
||||
const result = await proxyToGateway('/api/v1/admin/thinking-schedule', {
|
||||
method: 'PUT', body: JSON.stringify(req.body),
|
||||
});
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
|
||||
// GET /api/tool-calls — 查询工具调用记录
|
||||
app.get('/api/tool-calls', async (req, res) => {
|
||||
const { tool_name, page, limit } = req.query;
|
||||
@@ -815,13 +825,49 @@ app.get('/api/tool-calls', async (req, res) => {
|
||||
if (tool_name) params.set('tool_name', tool_name);
|
||||
params.set('page', page || '1');
|
||||
params.set('limit', limit || '20');
|
||||
const result = await proxyToToolEngine(`/api/v1/tools/calls?${params.toString()}`);
|
||||
const result = await proxyToAICore(`/api/v1/tools/calls?${params.toString()}`);
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
|
||||
// GET /api/tool-calls/stats — 工具调用统计
|
||||
app.get('/api/tool-calls/stats', async (_req, res) => {
|
||||
const result = await proxyToToolEngine('/api/v1/tools/calls/stats');
|
||||
const result = await proxyToAICore('/api/v1/tools/calls/stats');
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
|
||||
// ---- 插件管理代理 (转发到 plugin-manager) ----
|
||||
app.get('/api/plugins', async (_req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/plugins');
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.get('/api/plugins/:id', async (req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/plugins/' + req.params.id);
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.post('/api/plugins/:id/enable', async (req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/plugins/' + req.params.id + '/enable', { method: 'POST' });
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.post('/api/plugins/:id/disable', async (req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/plugins/' + req.params.id + '/disable', { method: 'POST' });
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.post('/api/plugins/:id/reload', async (req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/plugins/' + req.params.id + '/reload', { method: 'POST' });
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.get('/api/plugins/:id/tools', async (req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/plugins/' + req.params.id + '/tools');
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.get('/api/tools', async (_req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/tools');
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
app.post('/api/tools/:id/execute', async (req, res) => {
|
||||
const result = await proxyToPluginManager('/api/v1/tools/' + req.params.id + '/execute', {
|
||||
method: 'POST', body: JSON.stringify(req.body),
|
||||
});
|
||||
res.status(result.status).json(result.body);
|
||||
});
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ class ProcessManager extends EventEmitter {
|
||||
}
|
||||
|
||||
// 对需要数据库的服务做前置检查
|
||||
if (['gateway', 'ai-core', 'memory-service', 'tool-engine', 'plugin-manager', 'platform-bridge'].includes(serviceId)) {
|
||||
if (['gateway', 'ai-core', 'memory-service', 'plugin-manager', 'platform-bridge'].includes(serviceId)) {
|
||||
this.emit('log', serviceId, 'system', '检查数据库连接状态...');
|
||||
await ensureDBOnline(serviceId, this);
|
||||
}
|
||||
@@ -450,11 +450,11 @@ class ProcessManager extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* 按顺序启动所有服务 (memory → tool-engine → iot → voice → ai-core → gateway → frontend)
|
||||
* 按顺序启动所有服务 (memory → iot → voice → ai-core → gateway → frontend)
|
||||
* 每步等待健康检查通过后再启动下一个
|
||||
*/
|
||||
async startAllSequential() {
|
||||
const order = ['memory-service', 'tool-engine', 'plugin-manager', 'iot-debug-service', 'voice-service', 'ai-core', 'platform-bridge', 'gateway', 'frontend'];
|
||||
const order = ['memory-service', 'plugin-manager', 'iot-debug-service', 'voice-service', 'ai-core', 'platform-bridge', 'gateway', 'frontend'];
|
||||
const results = [];
|
||||
|
||||
for (const id of order) {
|
||||
|
||||
Reference in New Issue
Block a user