diff --git a/server/api.exe b/server/api.exe index 0d06de7..8bf8f5a 100644 Binary files a/server/api.exe and b/server/api.exe differ diff --git a/server/cmd/api.exe b/server/cmd/api.exe new file mode 100644 index 0000000..cc84596 Binary files /dev/null and b/server/cmd/api.exe differ diff --git a/server/cmd/api/data/x_agents.db b/server/cmd/api/data/x_agents.db new file mode 100644 index 0000000..8ad6abf Binary files /dev/null and b/server/cmd/api/data/x_agents.db differ diff --git a/server/cmd/api/main.go b/server/cmd/api/main.go index afea6f3..e645f92 100644 --- a/server/cmd/api/main.go +++ b/server/cmd/api/main.go @@ -147,64 +147,70 @@ func main() { } // 3. 自动迁移表 - if err := db.AutoMigrate(&model.DatabaseInfo{}, &model.SubTableInfo{}, &model.ModelInfo{}, &model.KnowledgeBase{}, &model.KnowledgeDocument{}, &model.User{}, &model.Role{}, &model.Tool{}, &model.MCP{}, &model.Skill{}, &model.Agent{}, &model.AgentSkill{}, &model.AgentKnowledgeBase{}, &model.AgentMemory{}, &model.AgentTeam{}, &model.AgentTask{}, &model.ChatSession{}, &model.ChatMessage{}, &model.ChatGroup{}).Error; err != nil { + log.Println("Starting AutoMigrate...") + err = db.AutoMigrate(&model.DatabaseInfo{}, &model.SubTableInfo{}, &model.ModelInfo{}, &model.KnowledgeBase{}, &model.KnowledgeDocument{}, &model.User{}, &model.Role{}, &model.Tool{}, &model.MCP{}, &model.Skill{}, &model.Agent{}, &model.AgentSkill{}, &model.AgentKnowledgeBase{}, &model.AgentMemory{}, &model.AgentTeam{}, &model.AgentTask{}, &model.ChatSession{}, &model.ChatMessage{}, &model.ChatGroup{}) + if err != nil { log.Printf("Warning: AutoMigrate error: %v", err) } + log.Println("AutoMigrate completed") - // 3.2 确保 agents 表存在(使用 SQL 强制创建) - db.Exec(` - CREATE TABLE IF NOT EXISTS agents ( - id VARCHAR(191) PRIMARY KEY, - name VARCHAR(100) NOT NULL, - description TEXT, - owner_id VARCHAR(50) NOT NULL, - INDEX idx_owner_id (owner_id), - skills TEXT, - role_description TEXT, - model_provider VARCHAR(50), - model_name VARCHAR(100), - is_supervisor TINYINT(1) DEFAULT 0, - is_active TINYINT(1) DEFAULT 1, - created_at DATETIME(3), - updated_at DATETIME(3) - ) - `) + // 3.2 确保 agents 表存在(仅 MySQL 模式) + if cfg.DatabaseType != "sqlite" { + db.Exec(` + CREATE TABLE IF NOT EXISTS agents ( + id VARCHAR(191) PRIMARY KEY, + name VARCHAR(100) NOT NULL, + description TEXT, + owner_id VARCHAR(50) NOT NULL, + INDEX idx_owner_id (owner_id), + skills TEXT, + role_description TEXT, + model_provider VARCHAR(50), + model_name VARCHAR(100), + is_supervisor TINYINT(1) DEFAULT 0, + is_active TINYINT(1) DEFAULT 1, + created_at DATETIME(3), + updated_at DATETIME(3) + ) + `) + } - // 3.1 确保 users 和 roles 表存在(使用 SQL 强制创建) - db.Exec(` - CREATE TABLE IF NOT EXISTS roles ( - id VARCHAR(191) PRIMARY KEY, - name VARCHAR(191) UNIQUE, - permissions TEXT, - created_at DATETIME(3), - updated_at DATETIME(3) - ) - `) - db.Exec(` - CREATE TABLE IF NOT EXISTS users ( - id VARCHAR(191) PRIMARY KEY, - username VARCHAR(50) UNIQUE NOT NULL, - password VARCHAR(191) NOT NULL, - email VARCHAR(191), - role_id VARCHAR(50) NOT NULL, - is_active BOOLEAN DEFAULT TRUE, - created_at DATETIME(3), - updated_at DATETIME(3), - INDEX idx_users_username (username), - INDEX idx_users_email (email) - ) - `) + // 3.1 确保 users 和 roles 表存在(仅 MySQL 模式) + if cfg.DatabaseType != "sqlite" { + db.Exec(` + CREATE TABLE IF NOT EXISTS roles ( + id VARCHAR(191) PRIMARY KEY, + name VARCHAR(191) UNIQUE, + permissions TEXT, + created_at DATETIME(3), + updated_at DATETIME(3) + ) + `) + db.Exec(` + CREATE TABLE IF NOT EXISTS users ( + id VARCHAR(191) PRIMARY KEY, + username VARCHAR(50) UNIQUE NOT NULL, + password VARCHAR(191) NOT NULL, + email VARCHAR(191), + role_id VARCHAR(50) NOT NULL, + is_active BOOLEAN DEFAULT TRUE, + created_at DATETIME(3), + updated_at DATETIME(3), + INDEX idx_users_username (username), + INDEX idx_users_email (email) + ) + `) - // 3.2 确保 tools 表存在(使用 SQL 强制创建) - db.Exec(` - CREATE TABLE IF NOT EXISTS tools ( - id VARCHAR(191) PRIMARY KEY, - name VARCHAR(100) UNIQUE NOT NULL, - description TEXT, - category VARCHAR(50) NOT NULL, - provider VARCHAR(100), - security_level VARCHAR(20) DEFAULT 'safe', - require_approval BOOLEAN DEFAULT FALSE, + // 3.2 确保 tools 表存在(使用 SQL 强制创建) + db.Exec(` + CREATE TABLE IF NOT EXISTS tools ( + id VARCHAR(191) PRIMARY KEY, + name VARCHAR(100) UNIQUE NOT NULL, + description TEXT, + category VARCHAR(50) NOT NULL, + provider VARCHAR(100), + security_level VARCHAR(20) DEFAULT 'safe', + require_approval BOOLEAN DEFAULT FALSE, parameters TEXT, status VARCHAR(20) DEFAULT 'active', created_at DATETIME(3), @@ -214,6 +220,7 @@ func main() { INDEX idx_tools_status (status) ) `) + } // 3.3 确保 MCP 表存在 db.Exec(` @@ -404,7 +411,7 @@ func main() { // 初始化群聊服务 chatGroupRepo := repository.NewChatGroupRepository(db) - chatGroupService := service.NewChatGroupService(chatGroupRepo, agentRepo) + chatGroupService := service.NewChatGroupService(chatGroupRepo, agentRepo, cfg.PythonServiceURL) chatGroupHandler := handler.NewChatGroupHandler(chatGroupService) var uploadHandler *handler.UploadHandler @@ -548,7 +555,8 @@ func main() { toolGroup := r.Group("/tool") { toolGroup.GET("/list", toolHandler.List) - toolGroup.GET("/sync", toolHandler.Sync) // 手动同步 + toolGroup.GET("/sync", toolHandler.Sync) // 手动同步 + toolGroup.POST("/sync-from-python", toolHandler.SyncFromPython) // 从Python同步 toolGroup.GET("/:id", toolHandler.GetByID) toolGroup.POST("/add", toolHandler.Create) toolGroup.PUT("/:id", toolHandler.Update) diff --git a/server/cmd/api_new.exe b/server/cmd/api_new.exe new file mode 100644 index 0000000..d18e51c Binary files /dev/null and b/server/cmd/api_new.exe differ diff --git a/server/config/config.yaml b/server/config/config.yaml index 05e185b..05908d5 100644 --- a/server/config/config.yaml +++ b/server/config/config.yaml @@ -2,15 +2,17 @@ port: "8082" jwt_secret: "dev-secret-key" -# 数据库配置 +# 数据库配置 (类型: mysql 或 sqlite) +database_type: "mysql" database_host: "localhost" -database_port: "6036" +database_port: "3306" database_user: "root" database_password: "root" database_name: "x_agents" +sqlite_path: "./data/x_agents.db" # AI 服务配置 -python_service_url: "http://localhost:8081" +python_service_url: "http://localhost:8001" ai_core_service_addr: "localhost:50051" # 文件上传配置 (local 或 minio) diff --git a/server/data/x_agents.db b/server/data/x_agents.db new file mode 100644 index 0000000..da396e9 Binary files /dev/null and b/server/data/x_agents.db differ diff --git a/server/docs/docs.go b/server/docs/docs.go index 565738b..4ee71eb 100644 --- a/server/docs/docs.go +++ b/server/docs/docs.go @@ -15,6 +15,150 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/api/agent/chat": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "单智能体对话", + "parameters": [ + { + "description": "对话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.ChatRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.ChatResponse" + } + } + } + } + }, + "/api/agent/chat/stream": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "text/event-stream" + ], + "tags": [ + "智能体管理" + ], + "summary": "单智能体对话(流式输出)", + "parameters": [ + { + "description": "对话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.ChatRequest" + } + } + ], + "responses": {} + } + }, + "/api/agent/create": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "创建智能体", + "parameters": [ + { + "description": "创建智能体请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.CreateAgentRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.CreateAgentResponse" + } + } + } + } + }, + "/api/agent/list": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "获取智能体列表", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.ListAgentsResponse" + } + } + } + } + }, + "/api/agent/team/chat": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "多智能体群聊", + "parameters": [ + { + "description": "群聊请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.TeamChatRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.TeamChatResponse" + } + } + } + } + }, "/api/file_proxy": { "get": { "description": "代理访问文件,解决 MinIO 内网和 HTTPS 问题", @@ -1829,6 +1973,283 @@ const docTemplate = `{ } } }, + "/skill/add": { + "post": { + "description": "创建新的技能,支持文件上传。管理员用户(admin)上传为system技能,存到core/agents/skills/system/;其他用户上传为user技能,存到core/agents/skills/user/", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "创建技能", + "parameters": [ + { + "type": "string", + "description": "技能名称", + "name": "skill_name", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "技能描述", + "name": "skill_desc", + "in": "formData" + }, + { + "type": "string", + "description": "技能类型(system/user),不传则根据用户角色自动判断", + "name": "skill_type", + "in": "formData" + }, + { + "type": "file", + "description": "技能文件(SKILL.md)", + "name": "file", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "{\"message\": \"skill created\", \"skill\": {}}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/skill/content": { + "get": { + "description": "获取指定技能对应的 SKILL.md 文件内容", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "技能管理" + ], + "summary": "获取技能文件内容", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "文件内容", + "schema": { + "type": "string" + } + } + } + } + }, + "/skill/list": { + "get": { + "description": "获取所有技能列表,支持按类型筛选(system/user)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "获取技能列表", + "parameters": [ + { + "type": "string", + "description": "技能类型: system(系统技能)/user(用户技能)", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"list\": [], \"total\": 0}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/skill/sync": { + "get": { + "description": "从文件系统扫描 skills 目录并同步到数据库。扫描 account/admin/skills(系统技能) 和 account/{username}/skills(用户技能)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "手动同步技能", + "responses": { + "200": { + "description": "{\"message\": \"skills synced\", \"count\": 0}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/skill/{id}": { + "get": { + "description": "根据ID获取技能详情", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "获取技能详情", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"skill\": {}}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "put": { + "description": "更新技能信息\n更新技能信息,支持文件上传", + "consumes": [ + "application/json", + "multipart/form-data" + ], + "produces": [ + "application/json", + "application/json" + ], + "tags": [ + "技能管理", + "技能管理" + ], + "summary": "更新技能", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "技能信息", + "name": "skill", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.Skill" + } + }, + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "技能名称", + "name": "skill_name", + "in": "formData" + }, + { + "type": "string", + "description": "技能描述", + "name": "skill_desc", + "in": "formData" + }, + { + "type": "string", + "description": "技能类型", + "name": "skill_type", + "in": "formData" + }, + { + "type": "file", + "description": "技能文件(SKILL.md)", + "name": "file", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "{\"message\": \"skill updated\"}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "delete": { + "description": "删除技能", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "删除技能", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"message\": \"skill deleted\"}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, "/sub-table/add": { "post": { "description": "添加数据库的子表映射关系", @@ -2464,9 +2885,665 @@ const docTemplate = `{ } } } + }, + "/api/chat/sessions": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的聊天会话", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "创建会话", + "parameters": [ + { + "description": "创建会话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.CreateSessionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取用户的会话列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "获取会话列表", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "user_id", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "每页数量", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "偏移量", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SessionListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/chat/sessions/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取会话详情", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "获取会话详情", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "更新会话信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "更新会话", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "更新会话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.UpdateSessionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "删除会话", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "删除会话", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/chat/sessions/{id}/messages": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取会话的消息历史", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "获取会话消息历史", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "每页数量", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "偏移量", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.MessageListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/chat/messages": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "保存聊天消息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "保存消息", + "parameters": [ + { + "description": "创建消息请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.CreateMessageRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatMessage" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/agent/{id}/memories": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取记忆列表,支持分类和类型筛选", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆列表", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"}, + {"type": "string", "description": "记忆分类", "name": "category", "in": "query"}, + {"type": "string", "description": "记忆类型", "name": "memory_type", "in": "query"}, + {"type": "integer", "description": "每页数量", "name": "limit", "in": "query"}, + {"type": "integer", "description": "偏移量", "name": "offset", "in": "query"} + ], + "responses": { + "200": { + "description": "OK", + "schema": {"$ref": "#/definitions/model.MemoryListResponse"} + } + } + }, + "post": { + "security": [{"BearerAuth": []}], + "description": "创建新记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "创建记忆", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"description": "创建记忆请求", "name": "request", "in": "body", "required": true, "schema": {"$ref": "#/definitions/model.CreateMemoryRequest"}} + ], + "responses": { + "200": { + "description": "OK", + "schema": {"$ref": "#/definitions/model.AgentMemory"} + } + } + } + }, + "/api/agent/{id}/memories/search": { + "post": { + "security": [{"BearerAuth": []}], + "description": "搜索记忆,支持关键词、标签、分类筛选", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "搜索记忆", + "responses": { + "200": { + "description": "OK", + "schema": {"$ref": "#/definitions/model.MemoryListResponse"} + } + } + } + }, + "/api/agent/{id}/memories/categories": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取记忆分类列表", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆分类列表", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/{id}/memories/tags": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取记忆标签列表", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆标签列表", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/{id}/memories/export": { + "get": { + "security": [{"BearerAuth": []}], + "description": "导出记忆,支持JSON和CSV格式", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "导出记忆", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"}, + {"type": "string", "description": "导出格式 (json/csv)", "name": "format", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/{id}/memories/import": { + "post": { + "security": [{"BearerAuth": []}], + "description": "导入记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "导入记忆", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"description": "导入记忆请求", "name": "request", "in": "body", "required": true, "schema": {"$ref": "#/definitions/model.ImportMemoryRequest"}} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/memories/{memory_id}": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取单个记忆详情", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆详情", + "parameters": [ + {"type": "string", "description": "记忆ID", "name": "memory_id", "in": "path", "required": true} + ], + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.AgentMemory"}}, + "404": {"description": "Not Found"} + } + }, + "put": { + "security": [{"BearerAuth": []}], + "description": "更新记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "更新记忆", + "parameters": [ + {"type": "string", "description": "记忆ID", "name": "memory_id", "in": "path", "required": true}, + {"description": "更新记忆请求", "name": "request", "in": "body", "required": true, "schema": {"$ref": "#/definitions/model.UpdateMemoryRequest"}} + ], + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.AgentMemory"}}, + "404": {"description": "Not Found"} + } + }, + "delete": { + "security": [{"BearerAuth": []}], + "description": "删除记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "删除记忆", + "parameters": [ + {"type": "string", "description": "记忆ID", "name": "memory_id", "in": "path", "required": true} + ], + "responses": { + "200": {"description": "OK"}, + "404": {"description": "Not Found"} + } + } } }, "definitions": { + "handler.ChatRequest": { + "type": "object", + "required": [ + "agent_id", + "message" + ], + "properties": { + "agent_id": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "model_id": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "use_xbot": { + "type": "boolean" + } + } + }, + "handler.ChatResponse": { + "type": "object", + "properties": { + "agent_id": { + "type": "integer" + }, + "duration_ms": { + "type": "integer" + }, + "metadata": {}, + "reply": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "tokens_used": { + "type": "integer" + }, + "tools_used": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "handler.CreateAgentRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "avatar": { + "type": "string" + }, + "description": { + "type": "string" + }, + "knowledge": { + "description": "知识库", + "type": "string" + }, + "model_name": { + "type": "string" + }, + "model_provider": { + "description": "模型配置", + "type": "string" + }, + "name": { + "type": "string" + }, + "prompt": { + "description": "自定义提示词", + "type": "string" + }, + "skills": { + "type": "array", + "items": { + "type": "string" + } + }, + "skills_mode": { + "description": "技能配置", + "type": "string" + } + } + }, + "handler.CreateAgentResponse": { + "type": "object", + "properties": { + "agent_id": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "handler.ListAgentsResponse": { + "type": "object", + "properties": { + "agents": { + "type": "array", + "items": {} + } + } + }, "handler.LoginRequest": { "type": "object", "required": [ @@ -2509,6 +3586,56 @@ const docTemplate = `{ } } }, + "handler.TeamChatRequest": { + "type": "object", + "required": [ + "member_agent_ids", + "message", + "supervisor_agent_id" + ], + "properties": { + "member_agent_ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "message": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "strategy": { + "type": "string" + }, + "supervisor_agent_id": { + "type": "integer" + } + } + }, + "handler.TeamChatResponse": { + "type": "object", + "properties": { + "duration_ms": { + "type": "integer" + }, + "metadata": {}, + "reply": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "strategy": { + "type": "string" + }, + "subtask_results": {}, + "supervisor_agent_id": { + "type": "integer" + } + } + }, "model.CPUInfo": { "type": "object", "properties": { @@ -3153,6 +4280,41 @@ const docTemplate = `{ } } }, + "model.Skill": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "created_by": { + "description": "创建者用户名", + "type": "string" + }, + "id": { + "type": "string" + }, + "path": { + "description": "skill 文件路径", + "type": "string" + }, + "skill_desc": { + "type": "string" + }, + "skill_name": { + "type": "string" + }, + "skill_type": { + "description": "system / user", + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "model.StorageConfig": { "type": "object", "properties": { @@ -3479,6 +4641,268 @@ const docTemplate = `{ "type": "string" } } + }, + "model.ChatSession": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "会话ID" + }, + "user_id": { + "type": "string", + "description": "用户ID" + }, + "agent_id": { + "type": "string", + "description": "Agent ID" + }, + "title": { + "type": "string", + "description": "会话标题" + }, + "model_id": { + "type": "string", + "description": "模型ID" + }, + "status": { + "type": "string", + "description": "会话状态 (active/archived)" + }, + "created_at": { + "type": "string", + "description": "创建时间" + }, + "updated_at": { + "type": "string", + "description": "更新时间" + } + } + }, + "model.ChatMessage": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "消息ID" + }, + "session_id": { + "type": "string", + "description": "会话ID" + }, + "role": { + "type": "string", + "description": "角色 (user/assistant/system)" + }, + "content": { + "type": "string", + "description": "消息内容" + }, + "tokens_used": { + "type": "integer", + "description": "使用的token数" + }, + "duration_ms": { + "type": "integer", + "description": "响应耗时(毫秒)" + }, + "metadata": { + "type": "string", + "description": "额外信息(JSON格式)" + }, + "created_at": { + "type": "string", + "description": "创建时间" + } + } + }, + "model.CreateSessionRequest": { + "type": "object", + "required": ["user_id", "agent_id"], + "properties": { + "user_id": { + "type": "string", + "description": "用户ID" + }, + "agent_id": { + "type": "string", + "description": "Agent ID" + }, + "title": { + "type": "string", + "description": "会话标题" + }, + "model_id": { + "type": "string", + "description": "模型ID" + } + } + }, + "model.UpdateSessionRequest": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "会话标题" + }, + "status": { + "type": "string", + "description": "会话状态 (active/archived)" + } + } + }, + "model.CreateMessageRequest": { + "type": "object", + "required": ["session_id", "role", "content"], + "properties": { + "session_id": { + "type": "string", + "description": "会话ID" + }, + "role": { + "type": "string", + "description": "角色 (user/assistant)" + }, + "content": { + "type": "string", + "description": "消息内容" + }, + "tokens_used": { + "type": "integer", + "description": "使用的token数" + }, + "duration_ms": { + "type": "integer", + "description": "响应耗时(毫秒)" + }, + "metadata": { + "type": "string", + "description": "额外信息(JSON格式)" + } + } + }, + "model.SessionListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "total": { + "type": "integer", + "description": "总数" + } + } + }, + "model.MessageListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/model.ChatMessage" + } + }, + "total": { + "type": "integer", + "description": "总数" + } + } + }, + "model.AgentMemory": { + "type": "object", + "properties": { + "id": {"type": "string", "description": "记忆ID"}, + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型 (experience/preference/conversation/fact)"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签,JSON数组格式"}, + "keywords": {"type": "string", "description": "关键词,用于搜索"}, + "importance": {"type": "integer", "description": "重要性等级 (1-10)"}, + "is_pinned": {"type": "boolean", "description": "是否置顶"}, + "created_at": {"type": "string", "description": "创建时间"}, + "updated_at": {"type": "string", "description": "更新时间"} + } + }, + "model.CreateMemoryRequest": { + "type": "object", + "required": ["agent_id", "content"], + "properties": { + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签"}, + "keywords": {"type": "string", "description": "关键词"}, + "importance": {"type": "integer", "description": "重要性等级"}, + "is_pinned": {"type": "boolean", "description": "是否置顶"} + } + }, + "model.SearchMemoryRequest": { + "type": "object", + "required": ["agent_id"], + "properties": { + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "keyword": {"type": "string", "description": "搜索关键词"}, + "tags": {"type": "string", "description": "标签筛选"}, + "category": {"type": "string", "description": "记忆分类"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "min_score": {"type": "integer", "description": "最小重要性分数"}, + "limit": {"type": "integer", "description": "每页数量"}, + "offset": {"type": "integer", "description": "偏移量"} + } + }, + "model.UpdateMemoryRequest": { + "type": "object", + "properties": { + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签"}, + "keywords": {"type": "string", "description": "关键词"}, + "importance": {"type": "integer", "description": "重要性等级"}, + "is_pinned": {"type": "boolean", "description": "是否置顶"} + } + }, + "model.ImportMemoryRequest": { + "type": "object", + "required": ["agent_id", "memories"], + "properties": { + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "memories": { + "type": "array", + "items": {"$ref": "#/definitions/model.ImportMemoryItem"} + } + } + }, + "model.ImportMemoryItem": { + "type": "object", + "required": ["content"], + "properties": { + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签"}, + "keywords": {"type": "string", "description": "关键词"}, + "importance": {"type": "integer", "description": "重要性等级"} + } + }, + "model.MemoryListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": {"$ref": "#/definitions/model.AgentMemory"} + }, + "total": {"type": "integer", "description": "总数"} + } } } }` diff --git a/server/docs/swagger.json b/server/docs/swagger.json index 7d92a49..192fee1 100644 --- a/server/docs/swagger.json +++ b/server/docs/swagger.json @@ -4,6 +4,150 @@ "contact": {} }, "paths": { + "/api/agent/chat": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "单智能体对话", + "parameters": [ + { + "description": "对话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.ChatRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.ChatResponse" + } + } + } + } + }, + "/api/agent/chat/stream": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "text/event-stream" + ], + "tags": [ + "智能体管理" + ], + "summary": "单智能体对话(流式输出)", + "parameters": [ + { + "description": "对话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.ChatRequest" + } + } + ], + "responses": {} + } + }, + "/api/agent/create": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "创建智能体", + "parameters": [ + { + "description": "创建智能体请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.CreateAgentRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.CreateAgentResponse" + } + } + } + } + }, + "/api/agent/list": { + "get": { + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "获取智能体列表", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.ListAgentsResponse" + } + } + } + } + }, + "/api/agent/team/chat": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "智能体管理" + ], + "summary": "多智能体群聊", + "parameters": [ + { + "description": "群聊请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/handler.TeamChatRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/handler.TeamChatResponse" + } + } + } + } + }, "/api/file_proxy": { "get": { "description": "代理访问文件,解决 MinIO 内网和 HTTPS 问题", @@ -1818,6 +1962,283 @@ } } }, + "/skill/add": { + "post": { + "description": "创建新的技能,支持文件上传。管理员用户(admin)上传为system技能,存到core/agents/skills/system/;其他用户上传为user技能,存到core/agents/skills/user/", + "consumes": [ + "multipart/form-data" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "创建技能", + "parameters": [ + { + "type": "string", + "description": "技能名称", + "name": "skill_name", + "in": "formData", + "required": true + }, + { + "type": "string", + "description": "技能描述", + "name": "skill_desc", + "in": "formData" + }, + { + "type": "string", + "description": "技能类型(system/user),不传则根据用户角色自动判断", + "name": "skill_type", + "in": "formData" + }, + { + "type": "file", + "description": "技能文件(SKILL.md)", + "name": "file", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "{\"message\": \"skill created\", \"skill\": {}}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/skill/content": { + "get": { + "description": "获取指定技能对应的 SKILL.md 文件内容", + "consumes": [ + "application/json" + ], + "produces": [ + "text/plain" + ], + "tags": [ + "技能管理" + ], + "summary": "获取技能文件内容", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "文件内容", + "schema": { + "type": "string" + } + } + } + } + }, + "/skill/list": { + "get": { + "description": "获取所有技能列表,支持按类型筛选(system/user)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "获取技能列表", + "parameters": [ + { + "type": "string", + "description": "技能类型: system(系统技能)/user(用户技能)", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "{\"list\": [], \"total\": 0}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/skill/sync": { + "get": { + "description": "从文件系统扫描 skills 目录并同步到数据库。扫描 account/admin/skills(系统技能) 和 account/{username}/skills(用户技能)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "手动同步技能", + "responses": { + "200": { + "description": "{\"message\": \"skills synced\", \"count\": 0}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "/skill/{id}": { + "get": { + "description": "根据ID获取技能详情", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "获取技能详情", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"skill\": {}}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "put": { + "description": "更新技能信息\n更新技能信息,支持文件上传", + "consumes": [ + "application/json", + "multipart/form-data" + ], + "produces": [ + "application/json", + "application/json" + ], + "tags": [ + "技能管理", + "技能管理" + ], + "summary": "更新技能", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "技能信息", + "name": "skill", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.Skill" + } + }, + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "技能名称", + "name": "skill_name", + "in": "formData" + }, + { + "type": "string", + "description": "技能描述", + "name": "skill_desc", + "in": "formData" + }, + { + "type": "string", + "description": "技能类型", + "name": "skill_type", + "in": "formData" + }, + { + "type": "file", + "description": "技能文件(SKILL.md)", + "name": "file", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "{\"message\": \"skill updated\"}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "delete": { + "description": "删除技能", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "技能管理" + ], + "summary": "删除技能", + "parameters": [ + { + "type": "string", + "description": "技能ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "{\"message\": \"skill deleted\"}", + "schema": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, "/sub-table/add": { "post": { "description": "添加数据库的子表映射关系", @@ -2453,9 +2874,656 @@ } } } + }, + "/api/chat/sessions": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "创建新的聊天会话", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "创建会话", + "parameters": [ + { + "description": "创建会话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.CreateSessionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取用户的会话列表", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "获取会话列表", + "parameters": [ + { + "type": "string", + "description": "用户ID", + "name": "user_id", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "每页数量", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "偏移量", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.SessionListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/chat/sessions/{id}": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "根据ID获取会话详情", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "获取会话详情", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "put": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "更新会话信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "更新会话", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "更新会话请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.UpdateSessionRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "delete": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "删除会话", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "删除会话", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/chat/sessions/{id}/messages": { + "get": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "获取会话的消息历史", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "获取会话消息历史", + "parameters": [ + { + "type": "string", + "description": "会话ID", + "name": "id", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "每页数量", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "description": "偏移量", + "name": "offset", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.MessageListResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "/api/chat/messages": { + "post": { + "security": [ + { + "BearerAuth": [] + } + ], + "description": "保存聊天消息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "会话管理" + ], + "summary": "保存消息", + "parameters": [ + { + "description": "创建消息请求", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/model.CreateMessageRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/model.ChatMessage" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "404": { + "description": "Not Found", + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + } + }, + "/api/agent/{id}/memories": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取记忆列表,支持分类和类型筛选", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆列表", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"}, + {"type": "string", "description": "记忆分类", "name": "category", "in": "query"}, + {"type": "string", "description": "记忆类型", "name": "memory_type", "in": "query"}, + {"type": "integer", "description": "每页数量", "name": "limit", "in": "query"}, + {"type": "integer", "description": "偏移量", "name": "offset", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.MemoryListResponse"}} + } + }, + "post": { + "security": [{"BearerAuth": []}], + "description": "创建新记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "创建记忆", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"description": "创建记忆请求", "name": "request", "in": "body", "required": true, "schema": {"$ref": "#/definitions/model.CreateMemoryRequest"}} + ], + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.AgentMemory"}} + } + } + }, + "/api/agent/{id}/memories/search": { + "post": { + "security": [{"BearerAuth": []}], + "description": "搜索记忆,支持关键词、标签、分类筛选", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "搜索记忆", + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.MemoryListResponse"}} + } + } + }, + "/api/agent/{id}/memories/categories": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取记忆分类列表", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆分类列表", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/{id}/memories/tags": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取记忆标签列表", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆标签列表", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/{id}/memories/export": { + "get": { + "security": [{"BearerAuth": []}], + "description": "导出记忆,支持JSON和CSV格式", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "导出记忆", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"type": "string", "description": "用户ID", "name": "user_id", "in": "query"}, + {"type": "string", "description": "导出格式 (json/csv)", "name": "format", "in": "query"} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/{id}/memories/import": { + "post": { + "security": [{"BearerAuth": []}], + "description": "导入记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "导入记忆", + "parameters": [ + {"type": "string", "description": "Agent ID", "name": "id", "in": "path", "required": true}, + {"description": "导入记忆请求", "name": "request", "in": "body", "required": true, "schema": {"$ref": "#/definitions/model.ImportMemoryRequest"}} + ], + "responses": { + "200": {"description": "OK", "schema": {"type": "object"}} + } + } + }, + "/api/agent/memories/{memory_id}": { + "get": { + "security": [{"BearerAuth": []}], + "description": "获取单个记忆详情", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "获取记忆详情", + "parameters": [ + {"type": "string", "description": "记忆ID", "name": "memory_id", "in": "path", "required": true} + ], + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.AgentMemory"}}, + "404": {"description": "Not Found"} + } + }, + "put": { + "security": [{"BearerAuth": []}], + "description": "更新记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "更新记忆", + "parameters": [ + {"type": "string", "description": "记忆ID", "name": "memory_id", "in": "path", "required": true}, + {"description": "更新记忆请求", "name": "request", "in": "body", "required": true, "schema": {"$ref": "#/definitions/model.UpdateMemoryRequest"}} + ], + "responses": { + "200": {"description": "OK", "schema": {"$ref": "#/definitions/model.AgentMemory"}}, + "404": {"description": "Not Found"} + } + }, + "delete": { + "security": [{"BearerAuth": []}], + "description": "删除记忆", + "consumes": ["application/json"], + "produces": ["application/json"], + "tags": ["记忆管理"], + "summary": "删除记忆", + "parameters": [ + {"type": "string", "description": "记忆ID", "name": "memory_id", "in": "path", "required": true} + ], + "responses": { + "200": {"description": "OK"}, + "404": {"description": "Not Found"} + } } }, "definitions": { + "handler.ChatRequest": { + "type": "object", + "required": [ + "agent_id", + "message" + ], + "properties": { + "agent_id": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "model_id": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "use_xbot": { + "type": "boolean" + } + } + }, + "handler.ChatResponse": { + "type": "object", + "properties": { + "agent_id": { + "type": "integer" + }, + "duration_ms": { + "type": "integer" + }, + "metadata": {}, + "reply": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "tokens_used": { + "type": "integer" + }, + "tools_used": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "handler.CreateAgentRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "avatar": { + "type": "string" + }, + "description": { + "type": "string" + }, + "knowledge": { + "description": "知识库", + "type": "string" + }, + "model_name": { + "type": "string" + }, + "model_provider": { + "description": "模型配置", + "type": "string" + }, + "name": { + "type": "string" + }, + "prompt": { + "description": "自定义提示词", + "type": "string" + }, + "skills": { + "type": "array", + "items": { + "type": "string" + } + }, + "skills_mode": { + "description": "技能配置", + "type": "string" + } + } + }, + "handler.CreateAgentResponse": { + "type": "object", + "properties": { + "agent_id": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "handler.ListAgentsResponse": { + "type": "object", + "properties": { + "agents": { + "type": "array", + "items": {} + } + } + }, "handler.LoginRequest": { "type": "object", "required": [ @@ -2498,6 +3566,56 @@ } } }, + "handler.TeamChatRequest": { + "type": "object", + "required": [ + "member_agent_ids", + "message", + "supervisor_agent_id" + ], + "properties": { + "member_agent_ids": { + "type": "array", + "items": { + "type": "integer" + } + }, + "message": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "strategy": { + "type": "string" + }, + "supervisor_agent_id": { + "type": "integer" + } + } + }, + "handler.TeamChatResponse": { + "type": "object", + "properties": { + "duration_ms": { + "type": "integer" + }, + "metadata": {}, + "reply": { + "type": "string" + }, + "session_id": { + "type": "string" + }, + "strategy": { + "type": "string" + }, + "subtask_results": {}, + "supervisor_agent_id": { + "type": "integer" + } + } + }, "model.CPUInfo": { "type": "object", "properties": { @@ -3142,6 +4260,41 @@ } } }, + "model.Skill": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "created_by": { + "description": "创建者用户名", + "type": "string" + }, + "id": { + "type": "string" + }, + "path": { + "description": "skill 文件路径", + "type": "string" + }, + "skill_desc": { + "type": "string" + }, + "skill_name": { + "type": "string" + }, + "skill_type": { + "description": "system / user", + "type": "string" + }, + "status": { + "type": "string" + }, + "updated_at": { + "type": "string" + } + } + }, "model.StorageConfig": { "type": "object", "properties": { @@ -3468,6 +4621,268 @@ "type": "string" } } + }, + "model.ChatSession": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "会话ID" + }, + "user_id": { + "type": "string", + "description": "用户ID" + }, + "agent_id": { + "type": "string", + "description": "Agent ID" + }, + "title": { + "type": "string", + "description": "会话标题" + }, + "model_id": { + "type": "string", + "description": "模型ID" + }, + "status": { + "type": "string", + "description": "会话状态 (active/archived)" + }, + "created_at": { + "type": "string", + "description": "创建时间" + }, + "updated_at": { + "type": "string", + "description": "更新时间" + } + } + }, + "model.ChatMessage": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "消息ID" + }, + "session_id": { + "type": "string", + "description": "会话ID" + }, + "role": { + "type": "string", + "description": "角色 (user/assistant/system)" + }, + "content": { + "type": "string", + "description": "消息内容" + }, + "tokens_used": { + "type": "integer", + "description": "使用的token数" + }, + "duration_ms": { + "type": "integer", + "description": "响应耗时(毫秒)" + }, + "metadata": { + "type": "string", + "description": "额外信息(JSON格式)" + }, + "created_at": { + "type": "string", + "description": "创建时间" + } + } + }, + "model.CreateSessionRequest": { + "type": "object", + "required": ["user_id", "agent_id"], + "properties": { + "user_id": { + "type": "string", + "description": "用户ID" + }, + "agent_id": { + "type": "string", + "description": "Agent ID" + }, + "title": { + "type": "string", + "description": "会话标题" + }, + "model_id": { + "type": "string", + "description": "模型ID" + } + } + }, + "model.UpdateSessionRequest": { + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "会话标题" + }, + "status": { + "type": "string", + "description": "会话状态 (active/archived)" + } + } + }, + "model.CreateMessageRequest": { + "type": "object", + "required": ["session_id", "role", "content"], + "properties": { + "session_id": { + "type": "string", + "description": "会话ID" + }, + "role": { + "type": "string", + "description": "角色 (user/assistant)" + }, + "content": { + "type": "string", + "description": "消息内容" + }, + "tokens_used": { + "type": "integer", + "description": "使用的token数" + }, + "duration_ms": { + "type": "integer", + "description": "响应耗时(毫秒)" + }, + "metadata": { + "type": "string", + "description": "额外信息(JSON格式)" + } + } + }, + "model.SessionListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/model.ChatSession" + } + }, + "total": { + "type": "integer", + "description": "总数" + } + } + }, + "model.MessageListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": { + "$ref": "#/definitions/model.ChatMessage" + } + }, + "total": { + "type": "integer", + "description": "总数" + } + } + }, + "model.AgentMemory": { + "type": "object", + "properties": { + "id": {"type": "string", "description": "记忆ID"}, + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型 (experience/preference/conversation/fact)"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签,JSON数组格式"}, + "keywords": {"type": "string", "description": "关键词,用于搜索"}, + "importance": {"type": "integer", "description": "重要性等级 (1-10)"}, + "is_pinned": {"type": "boolean", "description": "是否置顶"}, + "created_at": {"type": "string", "description": "创建时间"}, + "updated_at": {"type": "string", "description": "更新时间"} + } + }, + "model.CreateMemoryRequest": { + "type": "object", + "required": ["agent_id", "content"], + "properties": { + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签"}, + "keywords": {"type": "string", "description": "关键词"}, + "importance": {"type": "integer", "description": "重要性等级"}, + "is_pinned": {"type": "boolean", "description": "是否置顶"} + } + }, + "model.SearchMemoryRequest": { + "type": "object", + "required": ["agent_id"], + "properties": { + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "keyword": {"type": "string", "description": "搜索关键词"}, + "tags": {"type": "string", "description": "标签筛选"}, + "category": {"type": "string", "description": "记忆分类"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "min_score": {"type": "integer", "description": "最小重要性分数"}, + "limit": {"type": "integer", "description": "每页数量"}, + "offset": {"type": "integer", "description": "偏移量"} + } + }, + "model.UpdateMemoryRequest": { + "type": "object", + "properties": { + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签"}, + "keywords": {"type": "string", "description": "关键词"}, + "importance": {"type": "integer", "description": "重要性等级"}, + "is_pinned": {"type": "boolean", "description": "是否置顶"} + } + }, + "model.ImportMemoryRequest": { + "type": "object", + "required": ["agent_id", "memories"], + "properties": { + "agent_id": {"type": "string", "description": "Agent ID"}, + "user_id": {"type": "string", "description": "用户ID"}, + "memories": { + "type": "array", + "items": {"$ref": "#/definitions/model.ImportMemoryItem"} + } + } + }, + "model.ImportMemoryItem": { + "type": "object", + "required": ["content"], + "properties": { + "content": {"type": "string", "description": "记忆内容"}, + "memory_type": {"type": "string", "description": "记忆类型"}, + "category": {"type": "string", "description": "记忆分类"}, + "tags": {"type": "string", "description": "标签"}, + "keywords": {"type": "string", "description": "关键词"}, + "importance": {"type": "integer", "description": "重要性等级"} + } + }, + "model.MemoryListResponse": { + "type": "object", + "properties": { + "list": { + "type": "array", + "items": {"$ref": "#/definitions/model.AgentMemory"} + }, + "total": {"type": "integer", "description": "总数"} + } } } } \ No newline at end of file diff --git a/server/docs/swagger.yaml b/server/docs/swagger.yaml index 65a979f..df5441b 100644 --- a/server/docs/swagger.yaml +++ b/server/docs/swagger.yaml @@ -1,4 +1,82 @@ definitions: + handler.ChatRequest: + properties: + agent_id: + type: integer + message: + type: string + model_id: + type: string + session_id: + type: string + use_xbot: + type: boolean + required: + - agent_id + - message + type: object + handler.ChatResponse: + properties: + agent_id: + type: integer + duration_ms: + type: integer + metadata: {} + reply: + type: string + session_id: + type: string + tokens_used: + type: integer + tools_used: + items: + type: string + type: array + type: object + handler.CreateAgentRequest: + properties: + avatar: + type: string + description: + type: string + knowledge: + description: 知识库 + type: string + model_name: + type: string + model_provider: + description: 模型配置 + type: string + name: + type: string + prompt: + description: 自定义提示词 + type: string + skills: + items: + type: string + type: array + skills_mode: + description: 技能配置 + type: string + required: + - name + type: object + handler.CreateAgentResponse: + properties: + agent_id: + type: integer + message: + type: string + name: + type: string + type: object + handler.ListAgentsResponse: + properties: + agents: + items: {} + type: array + type: object handler.LoginRequest: properties: password: @@ -27,6 +105,40 @@ definitions: - password - username type: object + handler.TeamChatRequest: + properties: + member_agent_ids: + items: + type: integer + type: array + message: + type: string + session_id: + type: string + strategy: + type: string + supervisor_agent_id: + type: integer + required: + - member_agent_ids + - message + - supervisor_agent_id + type: object + handler.TeamChatResponse: + properties: + duration_ms: + type: integer + metadata: {} + reply: + type: string + session_id: + type: string + strategy: + type: string + subtask_results: {} + supervisor_agent_id: + type: integer + type: object model.CPUInfo: properties: core_count: @@ -482,6 +594,30 @@ definitions: - uri - username type: object + model.Skill: + properties: + created_at: + type: string + created_by: + description: 创建者用户名 + type: string + id: + type: string + path: + description: skill 文件路径 + type: string + skill_desc: + type: string + skill_name: + type: string + skill_type: + description: system / user + type: string + status: + type: string + updated_at: + type: string + type: object model.StorageConfig: properties: access_key_id: @@ -708,9 +844,530 @@ definitions: sub_table_name: type: string type: object + model.ChatSession: + properties: + agent_id: + description: Agent ID + type: string + created_at: + description: 创建时间 + type: string + id: + description: 会话ID + type: string + model_id: + description: 模型ID + type: string + status: + description: 会话状态 (active/archived) + type: string + title: + description: 会话标题 + type: string + updated_at: + description: 更新时间 + type: string + user_id: + description: 用户ID + type: string + type: object + model.ChatMessage: + properties: + content: + description: 消息内容 + type: string + created_at: + description: 创建时间 + type: string + duration_ms: + description: 响应耗时(毫秒) + type: integer + id: + description: 消息ID + type: string + metadata: + description: 额外信息(JSON格式) + type: string + role: + description: 角色 (user/assistant/system) + type: string + session_id: + description: 会话ID + type: string + tokens_used: + description: 使用的token数 + type: integer + type: object + model.CreateSessionRequest: + properties: + agent_id: + description: Agent ID + type: string + model_id: + description: 模型ID + type: string + title: + description: 会话标题 + type: string + user_id: + description: 用户ID + type: string + required: + - user_id + - agent_id + type: object + model.UpdateSessionRequest: + properties: + status: + description: 会话状态 (active/archived) + type: string + title: + description: 会话标题 + type: string + type: object + model.CreateMessageRequest: + properties: + content: + description: 消息内容 + type: string + duration_ms: + description: 响应耗时(毫秒) + type: integer + metadata: + description: 额外信息(JSON格式) + type: string + role: + description: 角色 (user/assistant) + type: string + session_id: + description: 会话ID + type: string + tokens_used: + description: 使用的token数 + type: integer + required: + - session_id + - role + - content + type: object + model.SessionListResponse: + properties: + list: + items: + $ref: '#/definitions/model.ChatSession' + type: array + total: + description: 总数 + type: integer + type: object + model.MessageListResponse: + properties: + list: + items: + $ref: '#/definitions/model.ChatMessage' + type: array + total: + description: 总数 + type: integer + type: object + model.AgentMemory: + properties: + agent_id: + description: Agent ID + type: string + category: + description: 记忆分类 + type: string + content: + description: 记忆内容 + type: string + created_at: + description: 创建时间 + type: string + id: + description: 记忆ID + type: string + importance: + description: 重要性等级 (1-10) + type: integer + is_pinned: + description: 是否置顶 + type: boolean + keywords: + description: 关键词,用于搜索 + type: string + memory_type: + description: 记忆类型 (experience/preference/conversation/fact) + type: string + tags: + description: 标签,JSON数组格式 + type: string + updated_at: + description: 更新时间 + type: string + user_id: + description: 用户ID + type: string + type: object + model.CreateMemoryRequest: + properties: + agent_id: + description: Agent ID + type: string + category: + description: 记忆分类 + type: string + content: + description: 记忆内容 + type: string + importance: + description: 重要性等级 (1-10) + type: integer + is_pinned: + description: 是否置顶 + type: boolean + keywords: + description: 关键词 + type: string + memory_type: + description: 记忆类型 + type: string + tags: + description: 标签 + type: string + user_id: + description: 用户ID + type: string + required: + - agent_id + - content + type: object + model.SearchMemoryRequest: + properties: + agent_id: + description: Agent ID + type: string + category: + description: 记忆分类 + type: string + keyword: + description: 搜索关键词 + type: string + limit: + description: 每页数量 + type: integer + memory_type: + description: 记忆类型 + type: string + min_score: + description: 最小重要性分数 + type: integer + offset: + description: 偏移量 + type: integer + tags: + description: 标签筛选 + type: string + user_id: + description: 用户ID + type: string + required: + - agent_id + type: object + model.UpdateMemoryRequest: + properties: + category: + description: 记忆分类 + type: string + content: + description: 记忆内容 + type: string + importance: + description: 重要性等级 + type: integer + is_pinned: + description: 是否置顶 + type: boolean + keywords: + description: 关键词 + type: string + memory_type: + description: 记忆类型 + type: string + tags: + description: 标签 + type: string + type: object + model.ImportMemoryRequest: + properties: + agent_id: + description: Agent ID + type: string + memories: + description: 要导入的记忆列表 + items: + $ref: '#/definitions/model.ImportMemoryItem' + type: array + user_id: + description: 用户ID + type: string + required: + - agent_id + - memories + type: object + model.ImportMemoryItem: + properties: + category: + description: 记忆分类 + type: string + content: + description: 记忆内容 + type: string + importance: + description: 重要性等级 + type: integer + keywords: + description: 关键词 + type: string + memory_type: + description: 记忆类型 + type: string + tags: + description: 标签 + type: string + required: + - content + type: object + model.MemoryListResponse: + properties: + list: + items: + $ref: '#/definitions/model.AgentMemory' + type: array + total: + description: 总数 + type: integer + type: object + model.ChatGroup: + properties: + agent_ids: + description: 群聊中的Agent ID列表(JSON数组格式) + type: string + created_at: + description: 创建时间 + type: string + description: + description: 群聊描述 + type: string + id: + description: 群聊ID + type: string + name: + description: 群聊名称 + type: string + status: + description: 群聊状态 (active/archived) + type: string + updated_at: + description: 更新时间 + type: string + user_id: + description: 用户ID + type: string + type: object + model.CreateGroupRequest: + properties: + agent_ids: + description: Agent ID列表(JSON数组格式) + type: string + description: + description: 群聊描述 + type: string + name: + description: 群聊名称 + type: string + user_id: + description: 用户ID + type: string + required: + - name + - agent_ids + type: object + model.UpdateGroupRequest: + properties: + agent_ids: + description: Agent ID列表 + type: string + description: + description: 群聊描述 + type: string + name: + description: 群聊名称 + type: string + status: + description: 群聊状态 + type: string + type: object + model.GroupChatRequest: + properties: + agent_ids: + description: Agent ID列表(可选,覆盖群聊中配置的Agent) + type: string + message: + description: 消息内容 + type: string + session_id: + description: 关联的会话ID + type: string + required: + - message + type: object + model.GroupChatResponse: + properties: + duration_ms: + description: 响应耗时(毫秒) + type: integer + reply: + description: 汇总回复 + type: string + session_id: + description: 会话ID + type: string + strategy: + description: 策略 (parallel/sequential) + type: string + subtask_results: + description: 子任务结果列表 + items: + $ref: '#/definitions/model.SubtaskResult' + type: array + tokens_used: + description: 使用的token数 + type: integer + type: object + model.SubtaskResult: + properties: + agent_id: + description: Agent ID + type: string + agent_name: + description: Agent 名称 + type: string + duration_ms: + description: 响应耗时(毫秒) + type: integer + reply: + description: Agent 回复 + type: string + tokens_used: + description: 使用的token数 + type: integer + type: object + model.GroupListResponse: + properties: + list: + items: + $ref: '#/definitions/model.ChatGroup' + type: array + total: + description: 总数 + type: integer + type: object info: contact: {} paths: + /api/agent/chat: + post: + consumes: + - application/json + parameters: + - description: 对话请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/handler.ChatRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.ChatResponse' + summary: 单智能体对话 + tags: + - 智能体管理 + /api/agent/chat/stream: + post: + consumes: + - application/json + parameters: + - description: 对话请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/handler.ChatRequest' + produces: + - text/event-stream + responses: {} + summary: 单智能体对话(流式输出) + tags: + - 智能体管理 + /api/agent/create: + post: + consumes: + - application/json + parameters: + - description: 创建智能体请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/handler.CreateAgentRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.CreateAgentResponse' + summary: 创建智能体 + tags: + - 智能体管理 + /api/agent/list: + get: + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.ListAgentsResponse' + summary: 获取智能体列表 + tags: + - 智能体管理 + /api/agent/team/chat: + post: + consumes: + - application/json + parameters: + - description: 群聊请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/handler.TeamChatRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/handler.TeamChatResponse' + summary: 多智能体群聊 + tags: + - 智能体管理 /api/file_proxy: get: consumes: @@ -1916,6 +2573,194 @@ paths: summary: 获取关系列表 tags: - Neo4j + /skill/{id}: + delete: + consumes: + - application/json + description: 删除技能 + parameters: + - description: 技能ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: '{"message": "skill deleted"}' + schema: + additionalProperties: true + type: object + summary: 删除技能 + tags: + - 技能管理 + get: + consumes: + - application/json + description: 根据ID获取技能详情 + parameters: + - description: 技能ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: '{"skill": {}}' + schema: + additionalProperties: true + type: object + summary: 获取技能详情 + tags: + - 技能管理 + put: + consumes: + - application/json + - multipart/form-data + description: |- + 更新技能信息 + 更新技能信息,支持文件上传 + parameters: + - description: 技能ID + in: path + name: id + required: true + type: string + - description: 技能信息 + in: body + name: skill + required: true + schema: + $ref: '#/definitions/model.Skill' + - description: 技能ID + in: path + name: id + required: true + type: string + - description: 技能名称 + in: formData + name: skill_name + type: string + - description: 技能描述 + in: formData + name: skill_desc + type: string + - description: 技能类型 + in: formData + name: skill_type + type: string + - description: 技能文件(SKILL.md) + in: formData + name: file + type: file + produces: + - application/json + - application/json + responses: + "200": + description: '{"message": "skill updated"}' + schema: + additionalProperties: true + type: object + summary: 更新技能 + tags: + - 技能管理 + - 技能管理 + /skill/add: + post: + consumes: + - multipart/form-data + description: 创建新的技能,支持文件上传。管理员用户(admin)上传为system技能,存到core/agents/skills/system/;其他用户上传为user技能,存到core/agents/skills/user/ + parameters: + - description: 技能名称 + in: formData + name: skill_name + required: true + type: string + - description: 技能描述 + in: formData + name: skill_desc + type: string + - description: 技能类型(system/user),不传则根据用户角色自动判断 + in: formData + name: skill_type + type: string + - description: 技能文件(SKILL.md) + in: formData + name: file + type: file + produces: + - application/json + responses: + "200": + description: '{"message": "skill created", "skill": {}}' + schema: + additionalProperties: true + type: object + summary: 创建技能 + tags: + - 技能管理 + /skill/content: + get: + consumes: + - application/json + description: 获取指定技能对应的 SKILL.md 文件内容 + parameters: + - description: 技能ID + in: path + name: id + required: true + type: string + produces: + - text/plain + responses: + "200": + description: 文件内容 + schema: + type: string + summary: 获取技能文件内容 + tags: + - 技能管理 + /skill/list: + get: + consumes: + - application/json + description: 获取所有技能列表,支持按类型筛选(system/user) + parameters: + - description: '技能类型: system(系统技能)/user(用户技能)' + in: query + name: type + type: string + produces: + - application/json + responses: + "200": + description: '{"list": [], "total": 0}' + schema: + additionalProperties: true + type: object + summary: 获取技能列表 + tags: + - 技能管理 + /skill/sync: + get: + consumes: + - application/json + description: 从文件系统扫描 skills 目录并同步到数据库。扫描 account/admin/skills(系统技能) 和 account/{username}/skills(用户技能) + produces: + - application/json + responses: + "200": + description: '{"message": "skills synced", "count": 0}' + schema: + additionalProperties: true + type: object + summary: 手动同步技能 + tags: + - 技能管理 /sub-table/{id}: delete: consumes: @@ -2336,4 +3181,681 @@ paths: summary: 获取所有用户 tags: - 用户管理 + /api/chat/sessions: + post: + consumes: + - application/json + description: 创建新的聊天会话 + parameters: + - description: 创建会话请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.CreateSessionRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatSession' + "400": + description: Bad Request + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 创建会话 + tags: + - 会话管理 + get: + consumes: + - application/json + description: 获取用户的会话列表 + parameters: + - description: 用户ID + in: query + name: user_id + required: true + type: string + - description: 每页数量 + in: query + name: limit + type: integer + - description: 偏移量 + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.SessionListResponse' + "400": + description: Bad Request + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 获取会话列表 + tags: + - 会话管理 + /api/chat/sessions/{id}: + get: + consumes: + - application/json + description: 根据ID获取会话详情 + parameters: + - description: 会话ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatSession' + "404": + description: Not Found + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 获取会话详情 + tags: + - 会话管理 + put: + consumes: + - application/json + description: 更新会话信息 + parameters: + - description: 会话ID + in: path + name: id + required: true + type: string + - description: 更新会话请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.UpdateSessionRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatSession' + "404": + description: Not Found + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 更新会话 + tags: + - 会话管理 + delete: + consumes: + - application/json + description: 删除会话 + parameters: + - description: 会话ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + additionalProperties: + type: string + type: object + "404": + description: Not Found + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 删除会话 + tags: + - 会话管理 + /api/chat/sessions/{id}/messages: + get: + consumes: + - application/json + description: 获取会话的消息历史 + parameters: + - description: 会话ID + in: path + name: id + required: true + type: string + - description: 每页数量 + in: query + name: limit + type: integer + - description: 偏移量 + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.MessageListResponse' + "400": + description: Bad Request + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 获取会话消息历史 + tags: + - 会话管理 + /api/chat/messages: + post: + consumes: + - application/json + description: 保存聊天消息 + parameters: + - description: 创建消息请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.CreateMessageRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatMessage' + "400": + description: Bad Request + schema: + additionalProperties: + type: string + type: object + "404": + description: Not Found + schema: + additionalProperties: + type: string + type: object + security: + - BearerAuth: [] + summary: 保存消息 + tags: + - 会话管理 + /api/agent/{id}/memories: + get: + consumes: + - application/json + description: 获取记忆列表,支持分类和类型筛选 + parameters: + - description: Agent ID + in: path + name: id + required: true + type: string + - description: 用户ID + in: query + name: user_id + type: string + - description: 记忆分类 + in: query + name: category + type: string + - description: 记忆类型 + in: query + name: memory_type + type: string + - description: 每页数量 + in: query + name: limit + type: integer + - description: 偏移量 + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.MemoryListResponse' + security: + - BearerAuth: [] + summary: 获取记忆列表 + tags: + - 记忆管理 + post: + consumes: + - application/json + description: 创建新记忆 + parameters: + - description: Agent ID + in: path + name: id + required: true + type: string + - description: 创建记忆请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.CreateMemoryRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.AgentMemory' + security: + - BearerAuth: [] + summary: 创建记忆 + tags: + - 记忆管理 + /api/agent/{id}/memories/search: + post: + consumes: + - application/json + description: 搜索记忆,支持关键词、标签、分类筛选 + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.MemoryListResponse' + security: + - BearerAuth: [] + summary: 搜索记忆 + tags: + - 记忆管理 + /api/agent/{id}/memories/categories: + get: + consumes: + - application/json + description: 获取记忆分类列表 + parameters: + - description: Agent ID + in: path + name: id + required: true + type: string + - description: 用户ID + in: query + name: user_id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: object + security: + - BearerAuth: [] + summary: 获取记忆分类列表 + tags: + - 记忆管理 + /api/agent/{id}/memories/tags: + get: + consumes: + - application/json + description: 获取记忆标签列表 + parameters: + - description: Agent ID + in: path + name: id + required: true + type: string + - description: 用户ID + in: query + name: user_id + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: object + security: + - BearerAuth: [] + summary: 获取记忆标签列表 + tags: + - 记忆管理 + /api/agent/{id}/memories/export: + get: + consumes: + - application/json + description: 导出记忆,支持JSON和CSV格式 + parameters: + - description: Agent ID + in: path + name: id + required: true + type: string + - description: 用户ID + in: query + name: user_id + type: string + - description: 导出格式 (json/csv) + in: query + name: format + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + type: object + security: + - BearerAuth: [] + summary: 导出记忆 + tags: + - 记忆管理 + /api/agent/{id}/memories/import: + post: + consumes: + - application/json + description: 导入记忆 + parameters: + - description: Agent ID + in: path + name: id + required: true + type: string + - description: 导入记忆请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.ImportMemoryRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + type: object + security: + - BearerAuth: [] + summary: 导入记忆 + tags: + - 记忆管理 + /api/agent/memories/{memory_id}: + get: + consumes: + - application/json + description: 获取单个记忆详情 + parameters: + - description: 记忆ID + in: path + name: memory_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.AgentMemory' + "404": + description: Not Found + security: + - BearerAuth: [] + summary: 获取记忆详情 + tags: + - 记忆管理 + put: + consumes: + - application/json + description: 更新记忆 + parameters: + - description: 记忆ID + in: path + name: memory_id + required: true + type: string + - description: 更新记忆请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.UpdateMemoryRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.AgentMemory' + "404": + description: Not Found + security: + - BearerAuth: [] + summary: 更新记忆 + tags: + - 记忆管理 + delete: + consumes: + - application/json + description: 删除记忆 + parameters: + - description: 记忆ID + in: path + name: memory_id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + security: + - BearerAuth: [] + summary: 删除记忆 + tags: + - 记忆管理 + /api/chat/groups: + post: + consumes: + - application/json + description: 创建新的群聊 + parameters: + - description: 创建群聊请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.CreateGroupRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatGroup' + "400": + description: Bad Request + security: + - BearerAuth: [] + summary: 创建群聊 + tags: + - 群聊管理 + get: + consumes: + - application/json + description: 获取用户的群聊列表 + parameters: + - description: 用户ID + in: query + name: user_id + required: true + type: string + - description: 每页数量 + in: query + name: limit + type: integer + - description: 偏移量 + in: query + name: offset + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.GroupListResponse' + "400": + description: Bad Request + security: + - BearerAuth: [] + summary: 获取群聊列表 + tags: + - 群聊管理 + /api/chat/groups/{id}: + get: + consumes: + - application/json + description: 根据ID获取群聊详情 + parameters: + - description: 群聊ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatGroup' + "404": + description: Not Found + security: + - BearerAuth: [] + summary: 获取群聊详情 + tags: + - 群聊管理 + put: + consumes: + - application/json + description: 更新群聊信息 + parameters: + - description: 群聊ID + in: path + name: id + required: true + type: string + - description: 更新群聊请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.UpdateGroupRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.ChatGroup' + "404": + description: Not Found + security: + - BearerAuth: [] + summary: 更新群聊 + tags: + - 群聊管理 + delete: + consumes: + - application/json + description: 删除群聊 + parameters: + - description: 群聊ID + in: path + name: id + required: true + type: string + produces: + - application/json + responses: + "200": + description: OK + "404": + description: Not Found + security: + - BearerAuth: [] + summary: 删除群聊 + tags: + - 群聊管理 + /api/chat/groups/{id}/chat: + post: + consumes: + - application/json + description: 群聊对话(多智能体) + parameters: + - description: 群聊ID + in: path + name: id + required: true + type: string + - description: 群聊对话请求 + in: body + name: request + required: true + schema: + $ref: '#/definitions/model.GroupChatRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/model.GroupChatResponse' + "400": + description: Bad Request + security: + - BearerAuth: [] + summary: 群聊对话 + tags: + - 群聊管理 swagger: "2.0" diff --git a/server/go.mod b/server/go.mod index fd632a0..43971c8 100644 --- a/server/go.mod +++ b/server/go.mod @@ -4,36 +4,41 @@ go 1.25.0 require ( github.com/gin-gonic/gin v1.12.0 + github.com/glebarez/sqlite v1.11.0 github.com/go-sql-driver/mysql v1.7.0 github.com/golang-jwt/jwt/v5 v5.2.0 github.com/google/uuid v1.6.0 github.com/lib/pq v1.10.9 + github.com/minio/minio-go/v7 v7.0.99 + github.com/shirou/gopsutil/v3 v3.24.5 github.com/spf13/viper v1.18.2 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.1 + github.com/swaggo/swag v1.16.6 golang.org/x/crypto v0.48.0 + google.golang.org/grpc v1.79.2 + google.golang.org/protobuf v1.36.11 + gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.2 - gorm.io/gorm v1.25.5 + gorm.io/gorm v1.25.7 ) require ( github.com/KyleBanks/depth v1.2.1 // indirect - github.com/PuerkitoBio/purell v1.2.1 // indirect - github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/bytedance/gopkg v0.1.3 // indirect github.com/bytedance/sonic v1.15.0 // indirect github.com/bytedance/sonic/loader v0.5.0 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/cloudwego/base64x v0.1.6 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/gin-contrib/sse v1.1.0 // indirect + github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-openapi/jsonpointer v0.22.5 // indirect github.com/go-openapi/jsonreference v0.21.5 // indirect github.com/go-openapi/spec v0.22.4 // indirect - github.com/go-openapi/swag v0.25.5 // indirect github.com/go-openapi/swag/conv v0.25.5 // indirect github.com/go-openapi/swag/jsonname v0.25.5 // indirect github.com/go-openapi/swag/jsonutils v0.25.5 // indirect @@ -49,7 +54,6 @@ require ( github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // indirect @@ -57,11 +61,9 @@ require ( github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect - github.com/mailru/easyjson v0.9.1 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.99 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -70,32 +72,25 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.6.0 // indirect github.com/quic-go/quic-go v0.59.0 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rs/xid v1.6.0 // indirect - github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect - github.com/shirou/gopsutil/v3 v3.24.5 // indirect - github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/swaggo/files v1.0.1 // indirect - github.com/swaggo/gin-swagger v1.6.1 // indirect - github.com/swaggo/swag v1.16.6 // indirect github.com/tinylib/msgp v1.6.1 // indirect github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.3.1 // indirect - github.com/urfave/cli/v2 v2.27.7 // indirect - github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect - go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.25.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect @@ -106,10 +101,9 @@ require ( golang.org/x/text v0.34.0 // indirect golang.org/x/tools v0.42.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect - google.golang.org/grpc v1.79.2 // indirect - google.golang.org/protobuf v1.36.11 // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - sigs.k8s.io/yaml v1.6.0 // indirect + modernc.org/libc v1.22.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.5.0 // indirect + modernc.org/sqlite v1.23.1 // indirect ) diff --git a/server/go.sum b/server/go.sum index a96c9ed..78f5ce7 100644 --- a/server/go.sum +++ b/server/go.sum @@ -1,29 +1,15 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= -github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28= -github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M= github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM= -github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= -github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= -github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= -github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.15.0 h1:/PXeWFaR5ElNcVE84U0dOHjiMHQOwNIx3K4ymzh/uSE= github.com/bytedance/sonic v1.15.0/go.mod h1:tFkWrPz0/CUCLEF4ri4UkHekCIcdnkqXw9VduqpJh0k= github.com/bytedance/sonic/loader v0.5.0 h1:gXH3KVnatgY7loH5/TkeVyXPfESoqSBSBEiDd5VjlgE= github.com/bytedance/sonic/loader v0.5.0/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M= github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU= -github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo= -github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -34,20 +20,24 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= -github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= -github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w= github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM= -github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8= github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc= +github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= +github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= +github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= +github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/jsonpointer v0.22.5 h1:8on/0Yp4uTb9f4XvTrM2+1CPrV05QPZXu+rvu2o9jcA= @@ -56,14 +46,15 @@ github.com/go-openapi/jsonreference v0.21.5 h1:6uCGVXU/aNF13AQNggxfysJ+5ZcU4nEAe github.com/go-openapi/jsonreference v0.21.5/go.mod h1:u25Bw85sX4E2jzFodh1FOKMTZLcfifd1Q+iKKOUxExw= github.com/go-openapi/spec v0.22.4 h1:4pxGjipMKu0FzFiu/DPwN3CTBRlVM2yLf/YTWorYfDQ= github.com/go-openapi/spec v0.22.4/go.mod h1:WQ6Ai0VPWMZgMT4XySjlRIE6GP1bGQOtEThn3gcWLtQ= -github.com/go-openapi/swag v0.25.5 h1:pNkwbUEeGwMtcgxDr+2GBPAk4kT+kJ+AaB+TMKAg+TU= -github.com/go-openapi/swag v0.25.5/go.mod h1:B3RT6l8q7X803JRxa2e59tHOiZlX1t8viplOcs9CwTA= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-openapi/swag/conv v0.25.5 h1:wAXBYEXJjoKwE5+vc9YHhpQOFj2JYBMF2DUi+tGu97g= github.com/go-openapi/swag/conv v0.25.5/go.mod h1:CuJ1eWvh1c4ORKx7unQnFGyvBbNlRKbnRyAvDvzWA4k= github.com/go-openapi/swag/jsonname v0.25.5 h1:8p150i44rv/Drip4vWI3kGi9+4W9TdI3US3uUYSFhSo= github.com/go-openapi/swag/jsonname v0.25.5/go.mod h1:jNqqikyiAK56uS7n8sLkdaNY/uq6+D2m2LANat09pKU= github.com/go-openapi/swag/jsonutils v0.25.5 h1:XUZF8awQr75MXeC+/iaw5usY/iM7nXPDwdG3Jbl9vYo= github.com/go-openapi/swag/jsonutils v0.25.5/go.mod h1:48FXUaz8YsDAA9s5AnaUvAmry1UcLcNVWUjY42XkrN4= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5 h1:SX6sE4FrGb4sEnnxbFL/25yZBb5Hcg1inLeErd86Y1U= +github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.5/go.mod h1:/2KvOTrKWjVA5Xli3DZWdMCZDzz3uV/T7bXwrKWPquo= github.com/go-openapi/swag/loading v0.25.5 h1:odQ/umlIZ1ZVRteI6ckSrvP6e2w9UTF5qgNdemJHjuU= github.com/go-openapi/swag/loading v0.25.5/go.mod h1:I8A8RaaQ4DApxhPSWLNYWh9NvmX2YKMoB9nwvv6oW6g= github.com/go-openapi/swag/stringutils v0.25.5 h1:NVkoDOA8YBgtAR/zvCx5rhJKtZF3IzXcDdwOsYzrB6M= @@ -72,36 +63,34 @@ github.com/go-openapi/swag/typeutils v0.25.5 h1:EFJ+PCga2HfHGdo8s8VJXEVbeXRCYwzz github.com/go-openapi/swag/typeutils v0.25.5/go.mod h1:itmFmScAYE1bSD8C4rS0W+0InZUBrB2xSPbWt6DLGuc= github.com/go-openapi/swag/yamlutils v0.25.5 h1:kASCIS+oIeoc55j28T4o8KwlV2S4ZLPT6G0iq2SSbVQ= github.com/go-openapi/swag/yamlutils v0.25.5/go.mod h1:Gek1/SjjfbYvM+Iq4QGwa/2lEXde9n2j4a3wI3pNuOQ= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0 h1:7SgOMTvJkM8yWrQlU8Jm18VeDPuAvB/xWrdxFJkoFag= +github.com/go-openapi/testify/enable/yaml/v2 v2.4.0/go.mod h1:14iV8jyyQlinc9StD7w1xVPW3CO3q1Gj04Jy//Kw4VM= +github.com/go-openapi/testify/v2 v2.4.0 h1:8nsPrHVCWkQ4p8h1EsRVymA2XABB4OT40gcvAu+voFM= +github.com/go-openapi/testify/v2 v2.4.0/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= -github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= -github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= -github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM= github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= +github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -110,29 +99,19 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= -github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= -github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU= -github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/klauspost/crc32 v1.3.0 h1:sSmTt3gUt81RP655XGZPElI0PelVTZ6YwCRnPSupoFM= github.com/klauspost/crc32 v1.3.0/go.mod h1:D7kQaZhnkX/Y0tstFGf8VUzv2UofNGqCjnC3zdHB0Hw= -github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= -github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -141,10 +120,6 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= -github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/minio/crc64nvme v1.1.1 h1:8dwx/Pz49suywbO+auHCBpCtlW1OfpcLN7wYgVR6wAI= @@ -160,8 +135,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= -github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM= @@ -175,20 +148,23 @@ github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8= github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII= github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw= github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= -github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= -github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -204,16 +180,12 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= @@ -230,38 +202,37 @@ github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+F github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= -github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY= github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4= -github.com/urfave/cli/v2 v2.27.7 h1:bH59vdhbjLv3LAvIu6gd0usJHgoTTPhCFib8qqOwXYU= -github.com/urfave/cli/v2 v2.27.7/go.mod h1:CyNAG/xg+iAOg0N4MPGZqVmv2rCoP267496AOXUZjA4= -github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342 h1:FnBeRrxr7OU4VvAzt5X7s6266i6cSVkkFPS0TuXWbIg= -github.com/xrash/smetrics v0.0.0-20250705151800-55b8f293f342/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.mongodb.org/mongo-driver/v2 v2.5.0 h1:yXUhImUjjAInNcpTcAlPHiT7bIXhshCTL3jVBkF3xaE= go.mongodb.org/mongo-driver/v2 v2.5.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= -go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= -go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= -golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.25.0 h1:qnk6Ksugpi5Bz32947rkUgDt9/s5qvqDPl/gBKdMJLE= golang.org/x/arch v0.25.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= -golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= @@ -273,10 +244,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -289,20 +256,11 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= -golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= -golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -312,10 +270,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -325,34 +279,32 @@ golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k= golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww= google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.2 h1:QC2HRskSE75wBuOxe0+iCkyJZ+RqpudsQtqkp+IMuXs= gorm.io/driver/mysql v1.5.2/go.mod h1:pQLhh1Ut/WUAySdTHwBpBv6+JKcj+ua4ZFx1QQTBzb8= gorm.io/gorm v1.25.2-0.20230530020048-26663ab9bf55/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k= -gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= -gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= -sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= +gorm.io/gorm v1.25.7 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE= +modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds= +modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= +modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM= +modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk= diff --git a/server/internal/config/config.go b/server/internal/config/config.go index 2e6673d..ed0cfa2 100644 --- a/server/internal/config/config.go +++ b/server/internal/config/config.go @@ -3,7 +3,10 @@ package config import ( "fmt" "log" + "os" + "path/filepath" + "github.com/glebarez/sqlite" "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" @@ -11,15 +14,31 @@ import ( "github.com/spf13/viper" ) +// 获取项目根目录 +func getProjectRoot() string { + // 从当前工作目录向上查找 .env 文件 + dir, _ := os.Getwd() + for i := 0; i < 5; i++ { + if _, err := os.Stat(filepath.Join(dir, ".env")); err == nil { + return dir + } + dir = filepath.Dir(dir) + } + // 默认返回当前目录 + return "." +} + type Config struct { Port string JWTSecret string + DatabaseType string // 数据库类型: mysql 或 sqlite DatabaseHost string DatabasePort string DatabaseUser string DatabasePassword string DatabaseName string DatabaseURL string // 拼接后的完整连接字符串 + SQLitePath string // SQLite 数据库文件路径 PythonServiceURL string AICoreServiceAddr string // AI-Core gRPC 服务地址,如 "localhost:50051" // 文件上传配置 @@ -36,23 +55,22 @@ type Config struct { } func Load() *Config { - viper.SetConfigName("config") - viper.SetConfigType("yaml") - viper.AddConfigPath("./config") - viper.AddConfigPath("../config") - viper.AddConfigPath("../../config") + // 重新初始化 viper,避免之前的状态影响 + viper.Reset() - // 默认值 + // 第一步:设置默认值 viper.SetDefault("port", "8080") viper.SetDefault("jwt_secret", "your-secret-key-change-in-production") viper.SetDefault("python_service_url", "http://localhost:8081") viper.SetDefault("ai_core_service_addr", "localhost:50051") // 数据库默认配置 + viper.SetDefault("database_type", "mysql") viper.SetDefault("database_host", "localhost") viper.SetDefault("database_port", "3306") viper.SetDefault("database_user", "root") viper.SetDefault("database_password", "root") viper.SetDefault("database_name", "x_agents") + viper.SetDefault("sqlite_path", "./data/x_agents.db") // 文件上传默认配置 viper.SetDefault("upload_mode", "local") viper.SetDefault("upload_local_path", "resource/files") @@ -64,30 +82,84 @@ func Load() *Config { viper.SetDefault("minio_bucket", "x-agents") viper.SetDefault("minio_use_ssl", false) - if err := viper.ReadInConfig(); err != nil { - log.Printf("Using default config: %v", err) + // 第二步:读取 config.yaml(优先级低) + viper.SetConfigName("config") + viper.SetConfigType("yaml") + viper.AddConfigPath("./config") + viper.AddConfigPath("../config") + viper.AddConfigPath("../../config") + _ = viper.MergeInConfig() // 忽略错误,可能没有 config.yaml + + // 第三步:读取 .env 文件(优先级最高) + projectRoot := getProjectRoot() + log.Printf("Project root: %s", projectRoot) + + viper.SetConfigName(".env") + viper.SetConfigType("env") + viper.AddConfigPath(projectRoot) // 项目根目录 (X-Agents) + viper.AddConfigPath(".") // 当前目录 + viper.AddConfigPath("..") // 父目录 + viper.AddConfigPath("../..") // 上两级目录 + viper.SetEnvPrefix("GO") // 环境变量前缀 GO_xxx (仅对环境变量生效) + viper.AutomaticEnv() + _ = viper.MergeInConfig() // 忽略错误,可能没有 .env + + // 处理 .env 文件中的键名(去掉 GO_ 前缀映射) + envToConfig := map[string]string{ + "GO_PORT": "port", + "GO_DATABASE_TYPE": "database_type", + "GO_DATABASE_HOST": "database_host", + "GO_DATABASE_PORT": "database_port", + "GO_DATABASE_NAME": "database_name", + "GO_DATABASE_USER": "database_user", + "GO_DATABASE_PASSWORD": "database_password", + "GO_SQLITE_PATH": "sqlite_path", + } + for envKey, configKey := range envToConfig { + if val := viper.GetString(envKey); val != "" { + viper.Set(configKey, val) + } } - // 拼接数据库连接字符串 - dbHost := viper.GetString("database_host") - dbPort := viper.GetString("database_port") - dbUser := viper.GetString("database_user") - dbPassword := viper.GetString("database_password") - dbName := viper.GetString("database_name") - databaseURL := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", - dbUser, dbPassword, dbHost, dbPort, dbName) + log.Printf("Loaded config: database_type=%s, port=%s", + viper.GetString("database_type"), viper.GetString("port")) + + // 获取数据库类型 + dbType := viper.GetString("database_type") + var databaseURL string + + if dbType == "sqlite" { + sqlitePath := viper.GetString("sqlite_path") + // 确保 SQLite 数据目录存在 (跨平台处理) + dir := filepath.Dir(sqlitePath) + if dir != "." && dir != "" { + os.MkdirAll(dir, 0755) + } + databaseURL = sqlitePath + } else { + // MySQL 连接字符串 + dbHost := viper.GetString("database_host") + dbPort := viper.GetString("database_port") + dbUser := viper.GetString("database_user") + dbPassword := viper.GetString("database_password") + dbName := viper.GetString("database_name") + databaseURL = fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", + dbUser, dbPassword, dbHost, dbPort, dbName) + } return &Config{ Port: viper.GetString("port"), JWTSecret: viper.GetString("jwt_secret"), + DatabaseType: dbType, DatabaseURL: databaseURL, - DatabaseHost: dbHost, - DatabasePort: dbPort, - DatabaseUser: dbUser, - DatabasePassword: dbPassword, - DatabaseName: dbName, + DatabaseHost: viper.GetString("database_host"), + DatabasePort: viper.GetString("database_port"), + DatabaseUser: viper.GetString("database_user"), + DatabasePassword: viper.GetString("database_password"), + DatabaseName: viper.GetString("database_name"), + SQLitePath: viper.GetString("sqlite_path"), PythonServiceURL: viper.GetString("python_service_url"), - AICoreServiceAddr: viper.GetString("ai_core_service_addr"), + AICoreServiceAddr: viper.GetString("ai_core_service_addr"), // 文件上传配置 UploadMode: viper.GetString("upload_mode"), UploadLocalPath: viper.GetString("upload_local_path"), @@ -108,9 +180,23 @@ func InitDB(cfg *Config) (*gorm.DB, error) { return nil, fmt.Errorf("database URL is empty") } - db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ - Logger: logger.Default.LogMode(logger.Silent), - }) + var db *gorm.DB + var err error + + if cfg.DatabaseType == "sqlite" { + // SQLite 不需要创建目录逻辑,因为 Load 函数已经处理了 + db, err = gorm.Open(sqlite.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Silent), + }) + log.Printf("Using SQLite database: %s", dsn) + } else { + db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{ + Logger: logger.Default.LogMode(logger.Silent), + }) + log.Printf("Using MySQL database: %s:%s/%s", + cfg.DatabaseHost, cfg.DatabasePort, cfg.DatabaseName) + } + if err != nil { return nil, fmt.Errorf("failed to connect database: %w", err) } diff --git a/server/internal/handler/agent_handler.go b/server/internal/handler/agent_handler.go index 7ed9003..35050db 100644 --- a/server/internal/handler/agent_handler.go +++ b/server/internal/handler/agent_handler.go @@ -2,6 +2,7 @@ package handler import ( "net/http" + "strconv" "x-agents/server/internal/service" @@ -22,7 +23,7 @@ func NewAgentHandler(agentService *service.AgentService) *AgentHandler { // ChatRequest 对话请求 type ChatRequest struct { - AgentID int `json:"agent_id" binding:"required"` + AgentID string `json:"agent_id" binding:"required"` // 字符串类型 Message string `json:"message" binding:"required"` SessionID string `json:"session_id"` ModelID string `json:"model_id"` @@ -69,10 +70,14 @@ func (h *AgentHandler) Chat(c *gin.Context) { } // 获取用户 ID(从认证中间件获取) - userID := 1 // TODO: 从 c.Get("user_id") 获取 + userIDStr := "1" // TODO: 从 c.Get("user_id") 获取 + userID, _ := strconv.Atoi(userIDStr) + + // 将前端传来的字符串 agent_id 转换为 int + agentID, _ := strconv.Atoi(req.AgentID) pythonReq := service.AgentChatRequest{ - AgentID: req.AgentID, + AgentID: agentID, Message: req.Message, UserID: userID, SessionID: req.SessionID, @@ -122,7 +127,11 @@ func (h *AgentHandler) ChatStream(c *gin.Context) { } // 获取用户 ID - userID := 1 // TODO: 从 c.Get("user_id") 获取 + userIDStr := "1" // TODO: 从 c.Get("user_id") 获取 + userID, _ := strconv.Atoi(userIDStr) + + // 将前端传来的字符串 agent_id 转换为 int + agentID, _ := strconv.Atoi(req.AgentID) // 构建 SSE 流 c.Header("Content-Type", "text/event-stream") @@ -131,7 +140,7 @@ func (h *AgentHandler) ChatStream(c *gin.Context) { c.Header("Access-Control-Allow-Origin", "*") // 调用 Python 服务的流式端点 - err := h.agentService.ChatStream(c, req.AgentID, req.Message, req.SessionID, req.ModelID, userID) + err := h.agentService.ChatStream(c, agentID, req.Message, req.SessionID, req.ModelID, userID) if err != nil && !c.IsAborted() { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) } @@ -173,7 +182,8 @@ func (h *AgentHandler) TeamChat(c *gin.Context) { } // 获取用户 ID - userID := 1 // TODO: 从 c.Get("user_id") 获取 + userIDStr := "1" // TODO: 从 c.Get("user_id") 获取 + userID, _ := strconv.Atoi(userIDStr) pythonReq := service.TeamChatRequest{ SupervisorAgentID: req.SupervisorAgentID, diff --git a/server/internal/handler/chat_group_handler.go b/server/internal/handler/chat_group_handler.go index 0af15c2..cf8d745 100644 --- a/server/internal/handler/chat_group_handler.go +++ b/server/internal/handler/chat_group_handler.go @@ -1,6 +1,7 @@ package handler import ( + "log" "net/http" "strconv" @@ -140,10 +141,13 @@ func (h *ChatGroupHandler) GroupChat(c *gin.Context) { } response, err := h.groupService.GroupChat(userID, req.Message, agentIDs, req.SessionID) + log.Printf("[ChatGroupHandler] Got response, err: %v", err) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } + log.Printf("[ChatGroupHandler] Response subtask_results: %+v", response.SubtaskResults) + c.JSON(http.StatusOK, response) } diff --git a/server/internal/handler/chat_handler.go b/server/internal/handler/chat_handler.go deleted file mode 100644 index 9af5d02..0000000 --- a/server/internal/handler/chat_handler.go +++ /dev/null @@ -1,89 +0,0 @@ -package handler - -import ( - "net/http" - - "x-agents/server/internal/model" - "x-agents/server/internal/service" - - "github.com/gin-gonic/gin" -) - -type ChatHandler struct { - chatService *service.ChatService -} - -func NewChatHandler(chatService *service.ChatService) *ChatHandler { - return &ChatHandler{chatService: chatService} -} - -// Chat 处理聊天请求 -func (h *ChatHandler) Chat(c *gin.Context) { - var req model.AgentRequest - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // 从上下文获取用户ID(由中间件设置) - userID, exists := c.Get("user_id") - if !exists { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - resp, err := h.chatService.Chat(c.Request.Context(), userID.(string), req) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, resp) -} - -// ListAgents 获取 Agent 列表 -func (h *ChatHandler) ListAgents(c *gin.Context) { - userID, exists := c.Get("user_id") - if !exists { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - agents, err := h.chatService.ListAgents(userID.(string)) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - if agents == nil { - agents = []model.Agent{} - } - - c.JSON(http.StatusOK, gin.H{"agents": agents}) -} - -// CreateAgent 创建 Agent -func (h *ChatHandler) CreateAgent(c *gin.Context) { - userID, exists := c.Get("user_id") - if !exists { - c.JSON(http.StatusUnauthorized, gin.H{"error": "unauthorized"}) - return - } - - var req struct { - Name string `json:"name" binding:"required"` - Description string `json:"description"` - } - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - agent, err := h.chatService.CreateAgent(userID.(string), req.Name, req.Description) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusCreated, agent) -} diff --git a/server/internal/handler/tool_handler.go b/server/internal/handler/tool_handler.go index e102c81..824b5ee 100644 --- a/server/internal/handler/tool_handler.go +++ b/server/internal/handler/tool_handler.go @@ -164,3 +164,46 @@ func (h *ToolHandler) Delete(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "tool deleted"}) } + +// SyncFromPythonRequest 从Python同步工具请求 +type SyncFromPythonRequest struct { + Tools []PythonTool `json:"tools" binding:"required"` +} + +// PythonTool Python端工具结构 +type PythonTool struct { + Name string `json:"name"` + Description string `json:"description"` + Parameters string `json:"parameters"` + Category string `json:"category"` +} + +// SyncFromPython 从Python端同步工具 +// @Summary 从Python端同步工具 +// @Description 接收Python Agent同步过来的工具列表并存储到数据库 +// @Tags 工具管理 +// @Accept json +// @Produce json +// @Param tools body SyncFromPythonRequest true "工具列表" +// @Success 200 {object} map[string]interface{} +// @Router /tool/sync-from-python [post] +func (h *ToolHandler) SyncFromPython(c *gin.Context) { + var req struct { + Tools []map[string]interface{} `json:"tools" binding:"required"` + } + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + return + } + + count, err := h.toolService.SyncToolsFromPython(req.Tools) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{ + "message": "tools synced from python", + "synced_count": count, + }) +} diff --git a/server/internal/model/agent.go b/server/internal/model/agent.go index 0e585e3..6be3d10 100644 --- a/server/internal/model/agent.go +++ b/server/internal/model/agent.go @@ -63,12 +63,30 @@ type AgentMemory struct { AgentID string `json:"agent_id" gorm:"size:191;index"` UserID string `json:"user_id" gorm:"size:191;index"` Content string `json:"content" gorm:"type:text"` - MemoryType string `json:"memory_type" gorm:"size:20"` // experience/preference/conversation - Importance int `json:"importance" gorm:"default:5"` + MemoryType string `json:"memory_type" gorm:"size:20"` // experience/preference/conversation/fact + Category string `json:"category" gorm:"size:50;index"` // 记忆分类 + Tags string `json:"tags" gorm:"size:500"` // 标签,JSON数组格式 + Keywords string `json:"keywords" gorm:"size:500"` // 关键词,用于搜索 + Importance int `json:"importance" gorm:"default:5;index"` // 重要性等级 1-10 + IsPinned bool `json:"is_pinned" gorm:"default:false"` // 是否置顶 CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } +func (AgentMemory) TableName() string { + return "agent_memories" +} + +// ImportItem 导入记忆项 +type ImportItem struct { + Content string `json:"content"` + MemoryType string `json:"memory_type"` + Category string `json:"category"` + Tags string `json:"tags"` + Keywords string `json:"keywords"` + Importance int `json:"importance"` +} + // AgentTeam 多智能体协作配置 type AgentTeam struct { ID string `json:"id" gorm:"primaryKey"` diff --git a/server/internal/repository/agent_repo.go b/server/internal/repository/agent_repo.go index 3693142..fe1e366 100644 --- a/server/internal/repository/agent_repo.go +++ b/server/internal/repository/agent_repo.go @@ -39,6 +39,13 @@ func (r *AgentRepository) FindAll() ([]model.Agent, error) { return agents, err } +// FindByIDs 根据多个ID查询 +func (r *AgentRepository) FindByIDs(ids []string) ([]model.Agent, error) { + var agents []model.Agent + err := r.db.Where("id IN ?", ids).Find(&agents).Error + return agents, err +} + func (r *AgentRepository) Update(agent *model.Agent) error { return r.db.Save(agent).Error } @@ -101,6 +108,103 @@ func (r *AgentRepository) DeleteMemory(id string) error { return r.db.Delete(&model.AgentMemory{}, "id = ?", id).Error } +// FindMemories 通用查询记忆,支持分类和类型过滤 +func (r *AgentRepository) FindMemories(agentID, userID, category, memoryType string, limit, offset int) ([]model.AgentMemory, int64, error) { + var memories []model.AgentMemory + query := r.db.Model(&model.AgentMemory{}) + + if agentID != "" { + query = query.Where("agent_id = ?", agentID) + } + if userID != "" { + query = query.Where("user_id = ?", userID) + } + if category != "" { + query = query.Where("category = ?", category) + } + if memoryType != "" { + query = query.Where("memory_type = ?", memoryType) + } + + // 统计总数 + var total int64 + countQuery := query + if err := countQuery.Count(&total).Error; err != nil { + return nil, 0, err + } + + // 置顶的记忆优先,然后按重要性降序,最后按创建时间降序 + err := query.Order("is_pinned DESC, importance DESC, created_at DESC").Limit(limit).Offset(offset).Find(&memories).Error + return memories, total, err +} + +// SearchMemories 搜索记忆 +func (r *AgentRepository) SearchMemories(agentID, userID, keyword, tags, category, memoryType string, minScore, limit, offset int) ([]model.AgentMemory, int64, error) { + var memories []model.AgentMemory + query := r.db.Model(&model.AgentMemory{}) + + if agentID != "" { + query = query.Where("agent_id = ?", agentID) + } + if userID != "" { + query = query.Where("user_id = ?", userID) + } + if keyword != "" { + keyword = "%" + keyword + "%" + query = query.Where("content LIKE ? OR keywords LIKE ? OR tags LIKE ?", keyword, keyword, keyword) + } + if category != "" { + query = query.Where("category = ?", category) + } + if memoryType != "" { + query = query.Where("memory_type = ?", memoryType) + } + if minScore > 0 { + query = query.Where("importance >= ?", minScore) + } + + // 统计总数 + var total int64 + countQuery := query + if err := countQuery.Count(&total).Error; err != nil { + return nil, 0, err + } + + err := query.Order("is_pinned DESC, importance DESC, created_at DESC").Limit(limit).Offset(offset).Find(&memories).Error + return memories, total, err +} + +// FindMemoryByID 根据ID查询记忆 +func (r *AgentRepository) FindMemoryByID(id string) (*model.AgentMemory, error) { + var memory model.AgentMemory + err := r.db.Where("id = ?", id).First(&memory).Error + if err != nil { + return nil, err + } + return &memory, nil +} + +// UpdateMemory 更新记忆 +func (r *AgentRepository) UpdateMemory(memory *model.AgentMemory) error { + return r.db.Save(memory).Error +} + +// FindMemoryCategories 获取记忆分类列表 +func (r *AgentRepository) FindMemoryCategories(agentID, userID string) ([]string, error) { + var categories []string + query := r.db.Model(&model.AgentMemory{}).Distinct("category") + + if agentID != "" { + query = query.Where("agent_id = ?", agentID) + } + if userID != "" { + query = query.Where("user_id = ?", userID) + } + + err := query.Pluck("category", &categories).Error + return categories, err +} + // AgentTeam 相关方法 func (r *AgentRepository) CreateAgentTeam(team *model.AgentTeam) error { diff --git a/server/internal/repository/tool_repo.go b/server/internal/repository/tool_repo.go index eb48d80..19d80da 100644 --- a/server/internal/repository/tool_repo.go +++ b/server/internal/repository/tool_repo.go @@ -44,6 +44,15 @@ func (r *ToolRepository) FindByID(id string) (*model.Tool, error) { return &tool, nil } +func (r *ToolRepository) FindByName(name string) (*model.Tool, error) { + var tool model.Tool + err := r.db.First(&tool, "name = ?", name).Error + if err != nil { + return nil, err + } + return &tool, nil +} + func (r *ToolRepository) Update(tool *model.Tool) error { return r.db.Save(tool).Error } diff --git a/server/internal/service/agent_service.go b/server/internal/service/agent_service.go index 068298c..7d307ae 100644 --- a/server/internal/service/agent_service.go +++ b/server/internal/service/agent_service.go @@ -115,7 +115,7 @@ func (s *AgentService) Chat(req AgentChatRequest) (*AgentChatResponse, error) { log.Printf("[AgentService] Sending to Python: model_id=%s, api_key=%s, base_url=%s, provider=%s, model=%s", req.ModelID, apiKeyPreview, req.BaseURL, req.ModelProvider, req.ModelName) - url := fmt.Sprintf("%s/agent/chat", s.pythonURL) + url := fmt.Sprintf("%s/api/v1/agent/chat", s.pythonURL) jsonData, err := json.Marshal(req) if err != nil { @@ -153,7 +153,7 @@ func (s *AgentService) Chat(req AgentChatRequest) (*AgentChatResponse, error) { // TeamChat 多智能体群聊 func (s *AgentService) TeamChat(req TeamChatRequest) (*TeamChatResponse, error) { - url := fmt.Sprintf("%s/agent/team/chat", s.pythonURL) + url := fmt.Sprintf("%s/api/v1/agent/team/chat", s.pythonURL) // 设置默认策略 if req.Strategy == "" { @@ -228,7 +228,7 @@ func (s *AgentService) ChatStream(c interface{}, agentID int, message, sessionID log.Printf("[ChatStream] modelID is empty or modelRepo is nil: modelID=%s, modelRepo=%v", modelID, s.modelRepo != nil) } - streamURL := fmt.Sprintf("%s/agent/chat/stream", s.pythonURL) + streamURL := fmt.Sprintf("%s/api/v1/agent/chat/stream", s.pythonURL) jsonData, err := json.Marshal(reqBody) if err != nil { diff --git a/server/internal/service/chat_group_service.go b/server/internal/service/chat_group_service.go index 0260f09..4ec21a6 100644 --- a/server/internal/service/chat_group_service.go +++ b/server/internal/service/chat_group_service.go @@ -1,7 +1,17 @@ package service import ( + "bytes" + "encoding/json" "errors" + "fmt" + "io" + "log" + "net/http" + "strconv" + "strings" + "time" + "x-agents/server/internal/model" "x-agents/server/internal/repository" @@ -10,21 +20,27 @@ import ( // 错误定义 var ( - ErrNoAgents = errors.New("no agents provided") + ErrNoAgents = errors.New("no agents provided") ErrAgentNotFound = errors.New("agent not found") ) // ChatGroupService 群聊服务 type ChatGroupService struct { - groupRepo *repository.ChatGroupRepository - agentRepo *repository.AgentRepository + groupRepo *repository.ChatGroupRepository + agentRepo *repository.AgentRepository + pythonURL string + client *http.Client } // NewChatGroupService 创建群聊服务 -func NewChatGroupService(groupRepo *repository.ChatGroupRepository, agentRepo *repository.AgentRepository) *ChatGroupService { +func NewChatGroupService(groupRepo *repository.ChatGroupRepository, agentRepo *repository.AgentRepository, pythonURL string) *ChatGroupService { return &ChatGroupService{ groupRepo: groupRepo, agentRepo: agentRepo, + pythonURL: pythonURL, + client: &http.Client{ + Timeout: 120 * time.Second, + }, } } @@ -108,37 +124,122 @@ func (s *ChatGroupService) GroupChat(userID, message, agentIDs, sessionID string return nil, ErrAgentNotFound } - // 并行调用所有 Agent - results := make(chan model.SubtaskResult, len(agents)) - for _, agent := range agents { - go func(agentID, agentName string) { - // TODO: 调用实际的 Agent 对话逻辑 - // 这里暂时返回模拟结果 - result := model.SubtaskResult{ - AgentID: agentID, - AgentName: agentName, - Reply: "Agent response placeholder", - TokensUsed: 100, - DurationMs: 500, - } - results <- result - }(agent.ID, agent.Name) + // 解析 userID 为整数 + userIDInt, err := strconv.Atoi(userID) + if err != nil { + userIDInt = 1 // 默认值 } - // 收集结果 - subtaskResults := make([]model.SubtaskResult, 0, len(agents)) - for i := 0; i < len(agents); i++ { - subtaskResults = append(subtaskResults, <-results) + // 将 agent UUIDs 转换为整数 IDs + memberAgentIDs := make([]int, len(agents)) + for i := range agents { + // 使用索引+1 作为 agent ID(因为 Python 端使用整数 ID) + memberAgentIDs[i] = i + 1 + log.Printf("[ChatGroupService] Agent: %s (ID: %s)", agents[i].Name, agents[i].ID) + } + + // 调用 Python TeamAgent 进行群聊 + teamReq := TeamChatRequest{ + SupervisorAgentID: 0, // 没有 supervisor,使用并行策略 + MemberAgentIDs: memberAgentIDs, + Message: message, + UserID: userIDInt, + SessionID: sessionID, + Strategy: "parallel", + } + + url := fmt.Sprintf("%s/api/v1/agent/team/chat", s.pythonURL) + jsonData, err := json.Marshal(teamReq) + if err != nil { + return nil, fmt.Errorf("failed to marshal request: %w", err) + } + + httpReq, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) + if err != nil { + return nil, fmt.Errorf("failed to create request: %w", err) + } + httpReq.Header.Set("Content-Type", "application/json") + + resp, err := s.client.Do(httpReq) + if err != nil { + return nil, fmt.Errorf("failed to call python team agent: %w", err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("python team agent error: %s", string(body)) + } + + var teamResp TeamChatResponse + if err := json.Unmarshal(body, &teamResp); err != nil { + return nil, fmt.Errorf("failed to unmarshal response: %w", err) + } + + log.Printf("[ChatGroupService] Raw teamResp: %+v", teamResp) + log.Printf("[ChatGroupService] SubtaskResults count: %d", len(teamResp.SubtaskResults)) + + // 转换 SubtaskResults - Python 返回格式: agent_id, status, result + // 使用 agents 列表获取 agent 名称 + subtaskResults := make([]model.SubtaskResult, 0) + for i, sr := range teamResp.SubtaskResults { + srMap, ok := sr.(map[string]interface{}) + if !ok { + continue + } + + // 获取 agent 名称(从已查询的 agents 列表) + agentName := "" + if i < len(agents) { + agentName = agents[i].Name + } + + // 处理 agent_id (Python 返回 int,Go 需要 string) + agentIDVal := srMap["agent_id"] + var agentIDStr string + switch v := agentIDVal.(type) { + case float64: + agentIDStr = fmt.Sprintf("%d", int(v)) + case string: + agentIDStr = v + default: + agentIDStr = "0" + } + + // 如果没有从 agents 列表获取到名称,使用 agent_id + if agentName == "" { + agentName = agentIDStr + } + + // 获取 result 作为 reply + resultVal, _ := srMap["result"] + var reply string + switch v := resultVal.(type) { + case string: + reply = v + default: + reply = fmt.Sprintf("%v", resultVal) + } + + subtaskResults = append(subtaskResults, model.SubtaskResult{ + AgentID: agentIDStr, + AgentName: agentName, + Reply: reply, + TokensUsed: 0, // Python 暂时未返回 + DurationMs: 0, // Python 暂时未返回 + }) } - close(results) // 汇总结果 response := &model.GroupChatResponse{ SessionID: sessionID, - Reply: "Group chat completed", - DurationMs: 1000, - TokensUsed: 500, - Strategy: "parallel", + Reply: teamResp.Response, + DurationMs: teamResp.DurationMs, + Strategy: teamResp.Strategy, SubtaskResults: subtaskResults, } @@ -150,8 +251,15 @@ func parseAgentIDs(agentIDs string) []string { if agentIDs == "" { return []string{} } - // 简单解析,假设是 JSON 数组格式 - // 实际应该使用 json.Unmarshal - // 这里简化处理,直接返回 + // 尝试解析 JSON 数组格式 + var ids []string + if err := json.Unmarshal([]byte(agentIDs), &ids); err == nil { + return ids + } + // 如果解析失败,可能是逗号分隔的字符串 + if strings.Contains(agentIDs, ",") { + return strings.Split(agentIDs, ",") + } + // 简单处理,直接返回 return []string{agentIDs} } diff --git a/server/internal/service/tool_service.go b/server/internal/service/tool_service.go index 3ee755b..929b08c 100644 --- a/server/internal/service/tool_service.go +++ b/server/internal/service/tool_service.go @@ -71,6 +71,56 @@ func (s *ToolService) InitDefaultTools() error { return nil } +// SyncToolsFromPython 从Python端同步工具 +func (s *ToolService) SyncToolsFromPython(pythonTools []map[string]interface{}) (int, error) { + count := 0 + for _, pt := range pythonTools { + // 提取工具信息 + name, _ := pt["name"].(string) + description, _ := pt["description"].(string) + parameters, _ := pt["parameters"].(string) + category, _ := pt["category"].(string) + + if name == "" { + continue + } + + // 检查工具是否已存在 + existing, err := s.toolRepo.FindByName(name) + if err == nil && existing != nil { + // 更新现有工具 + existing.Description = description + existing.Parameters = parameters + if category != "" { + existing.Category = category + } + if err := s.toolRepo.Update(existing); err != nil { + log.Printf("[ToolService] Failed to update tool %s: %v", name, err) + continue + } + } else { + // 创建新工具 + tool := model.Tool{ + Name: name, + Description: description, + Parameters: parameters, + Category: category, + Provider: "python", + Status: "active", + SecurityLevel: "safe", + RequireApproval: false, + } + if err := s.toolRepo.Create(&tool); err != nil { + log.Printf("[ToolService] Failed to create tool %s: %v", name, err) + continue + } + } + count++ + } + log.Printf("[ToolService] Synced %d tools from Python", count) + return count, nil +} + // getDefaultTools 获取默认工具列表 func (s *ToolService) getDefaultTools() []model.Tool { return []model.Tool{ diff --git a/server/server.exe b/server/server.exe index c9ab2af..0276aac 100644 Binary files a/server/server.exe and b/server/server.exe differ