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:
2026-05-25 20:52:39 +08:00
parent 5325eaca3f
commit 673ff752c5
78 changed files with 1313 additions and 5187 deletions
+11 -2
View File
@@ -185,8 +185,17 @@ func main() {
logger.Println("[INFO] 模型配置文件不存在,回退到 .env LLM 配置")
}
router.Setup(r, hub, cfg, sessionStore, reminderStore, briefingStore, automationStore, fileStore, ruleEngine, knowledgeStore, nil, db, modelConfigStore)
// 初始化思考调度配置存储
thinkingScheduleStore, err := config.NewThinkingScheduleStore("../thinking_schedule.json")
if err != nil {
logger.Printf("[WARN] 思考调度配置存储初始化失败: %v", err)
thinkingScheduleStore = nil
} else {
logger.Println("[INFO] 思考调度配置文件已加载 (thinking_schedule.json)")
}
router.Setup(r, hub, cfg, sessionStore, reminderStore, briefingStore, automationStore, fileStore, ruleEngine, knowledgeStore, nil, db, modelConfigStore, thinkingScheduleStore)
// 启动提醒调度器
if reminderStore != nil {
handler.StartReminderScheduler(reminderStore, hub)
@@ -238,8 +238,8 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
// 增大 scanner buffer 以处理大块 SSE 数据
scanner.Buffer(make([]byte, 0, 64*1024), 1024*1024)
// 通知端 AI 开始生成回复
client.SendMessage(ws.ServerMessage{
// 通知所有客户端 AI 开始生成回复
h.broadcastToUser(client.UserID, ws.ServerMessage{
Type: "stream_start",
MessageID: "msg_" + generateID(),
SessionID: client.SessionID,
@@ -336,7 +336,7 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
Timestamp: time.Now().UnixMilli(),
ClientInfo: clientInfo,
})
client.SendMessage(ws.ServerMessage{
h.broadcastToUser(client.UserID, ws.ServerMessage{
Type: "response",
MessageID: reviewMsgID,
Content: rm.Content,
@@ -363,8 +363,8 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
Text: seg.Text,
})
}
// 发送断句事件给
client.SendMessage(ws.ServerMessage{
// 发送断句事件给所有客户
h.broadcastToUser(client.UserID, ws.ServerMessage{
Type: "stream_segments",
MessageID: msgID,
Segments: segments,
@@ -408,7 +408,7 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
Content: part,
})
}
client.SendMessage(ws.ServerMessage{
h.broadcastToUser(client.UserID, ws.ServerMessage{
Type: "multi_message",
MessageID: msgID,
SessionID: client.SessionID,
@@ -419,8 +419,8 @@ func (h *ChatHandler) streamResponse(client *ws.Client, mode string, reqBody []b
})
}
// 发送 stream_end
client.SendMessage(ws.ServerMessage{
// 发送 stream_end 到所有客户端
h.broadcastToUser(client.UserID, ws.ServerMessage{
Type: "stream_end",
MessageID: msgID,
SessionID: client.SessionID,
@@ -919,6 +919,16 @@ func randomStr(n int) string {
return hex.EncodeToString(b)[:n]
}
// broadcastToUser sends a server message to ALL connected clients for a user.
func (h *ChatHandler) broadcastToUser(userID string, msg ws.ServerMessage) {
data, err := json.Marshal(msg)
if err != nil {
logger.Printf("[chat] 序列化广播消息失败: %v", err)
return
}
h.hub.SendToUser(userID, data)
}
// parseMultiMessage 检测并解析多消息格式
// 如果文本包含空行分隔的多条消息,拆分为多条;否则返回单条
func parseMultiMessage(text string) []string {
+9 -1
View File
@@ -15,7 +15,7 @@ import (
)
// Setup 注册所有路由
func Setup(r *gin.Engine, hub *ws.Hub, cfg *config.Config, sessionStore *store.SessionStore, reminderStore *store.ReminderStore, briefingStore *store.BriefingStore, automationStore *store.AutomationStore, fileStore *store.FileStore, ruleEngine *engine.RuleEngine, knowledgeStore *store.KnowledgeStore, imageHandler *handler.ImageHandler, db interface{}, modelConfigStore *config.ModelsConfigStore) {
func Setup(r *gin.Engine, hub *ws.Hub, cfg *config.Config, sessionStore *store.SessionStore, reminderStore *store.ReminderStore, briefingStore *store.BriefingStore, automationStore *store.AutomationStore, fileStore *store.FileStore, ruleEngine *engine.RuleEngine, knowledgeStore *store.KnowledgeStore, imageHandler *handler.ImageHandler, db interface{}, modelConfigStore *config.ModelsConfigStore, thinkingScheduleStore *config.ThinkingScheduleStore) {
// 限流器
rateLimiter := middleware.NewRateLimiter(10, 20) // 每秒10个请求,突发20
@@ -37,6 +37,7 @@ func Setup(r *gin.Engine, hub *ws.Hub, cfg *config.Config, sessionStore *store.S
automationHandler := handler.NewAutomationHandler(automationStore, ruleEngine)
knowledgeHandler := handler.NewKnowledgeHandler(knowledgeStore, fileStore)
modelConfigHandler := handler.NewModelConfigHandler(modelConfigStore)
thinkingScheduleHandler := handler.NewThinkingScheduleHandler(thinkingScheduleStore)
if imageHandler == nil {
imageHandler = handler.NewImageHandler(cfg, fileStore)
}
@@ -226,6 +227,13 @@ func Setup(r *gin.Engine, hub *ws.Hub, cfg *config.Config, sessionStore *store.S
models.POST("/health-check", modelConfigHandler.TestProvider)
models.GET("/fetch-models/:name", modelConfigHandler.ProxyListModels)
}
// 思考调度配置
thinkingSchedule := admin.Group("/thinking-schedule")
{
thinkingSchedule.GET("", thinkingScheduleHandler.GetSchedule)
thinkingSchedule.PUT("", thinkingScheduleHandler.SetSchedule)
}
}
}