From 139e7c390a3e38bf3bfb77771f5e1ebaac1e86ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?MSI-7950X=5C=E5=88=98=E6=B3=BD=E6=98=8E?= Date: Tue, 19 May 2026 09:42:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=AF=E5=8A=A8=E9=97=AE=E9=A2=98=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/database.py | 275 +++++- backend/dependencies.py | 2 +- backend/main.py | 2 - backend/models/__init__.py | 154 ++++ backend/modules/audit/router.py | 18 +- backend/modules/memory/manager.py | 2 +- .../src/components/layout/AdminLayout.vue | 1 - frontend/src/router/index.ts | 12 - frontend/src/views/dashboard/Dashboard.vue | 4 +- frontend/src/views/flow/FlowEditor.vue | 10 +- .../src/views/flow/node-configs/LlmConfig.vue | 110 ++- .../node-configs/TemplateTransformConfig.vue | 12 +- .../src/views/model/ModelProviderManager.vue | 858 +++++++++++++----- 13 files changed, 1165 insertions(+), 295 deletions(-) diff --git a/backend/database.py b/backend/database.py index ee205a1..bb182c2 100644 --- a/backend/database.py +++ b/backend/database.py @@ -37,14 +37,287 @@ async def init_db(): async def _run_migrations(): - """执行数据库增量迁移,在已有表上安全添加新字段。""" + """执行数据库增量迁移:创建缺失的表并安全添加新字段。""" async with async_engine.begin() as conn: + # --- 创建可能缺失的新表 --- + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS agent_configs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(200) NOT NULL, + description TEXT, + system_prompt TEXT, + model VARCHAR(100) DEFAULT '', + model_instance_id UUID, + embedding_model_id UUID, + temperature FLOAT DEFAULT 0.7, + tools JSONB DEFAULT '[]', + status VARCHAR(20) DEFAULT 'active', + creator_id UUID REFERENCES users(id), + created_at TIMESTAMP DEFAULT now(), + updated_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS model_providers ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(100) NOT NULL, + provider_type VARCHAR(50) NOT NULL, + base_url VARCHAR(500), + api_key VARCHAR(500), + extra_config JSONB DEFAULT '{}', + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS model_instances ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + provider_id UUID NOT NULL REFERENCES model_providers(id) ON DELETE CASCADE, + model_name VARCHAR(200) NOT NULL, + model_type VARCHAR(20) NOT NULL, + display_name VARCHAR(200), + capabilities JSONB DEFAULT '{}', + default_params JSONB DEFAULT '{}', + is_default BOOLEAN DEFAULT FALSE, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS custom_tools ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(100) UNIQUE NOT NULL, + description TEXT, + schema_json JSONB NOT NULL DEFAULT '{}', + endpoint_url VARCHAR(500) DEFAULT '', + method VARCHAR(10) DEFAULT 'GET', + path VARCHAR(500) DEFAULT '', + headers_json JSONB DEFAULT '{}', + auth_type VARCHAR(20) DEFAULT 'none', + auth_config JSONB DEFAULT '{}', + is_active BOOLEAN DEFAULT TRUE, + created_by UUID REFERENCES users(id), + created_at TIMESTAMP DEFAULT now(), + updated_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS mcp_services ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(100) NOT NULL, + endpoint_url VARCHAR(500) NOT NULL, + status VARCHAR(20) DEFAULT 'active', + config JSONB DEFAULT '{}', + last_heartbeat TIMESTAMP, + created_at TIMESTAMP DEFAULT now(), + updated_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS audit_logs ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + user_id UUID REFERENCES users(id), + action VARCHAR(50) NOT NULL, + resource_type VARCHAR(50) NOT NULL, + resource_id VARCHAR(100), + detail JSONB DEFAULT '{}', + ip_address VARCHAR(50), + user_agent VARCHAR(500), + created_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS notification_templates ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + name VARCHAR(100) UNIQUE NOT NULL, + channel VARCHAR(20) NOT NULL, + event_type VARCHAR(50) NOT NULL, + subject_template VARCHAR(500), + body_template TEXT, + is_active BOOLEAN DEFAULT TRUE, + created_at TIMESTAMP DEFAULT now(), + updated_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS system_metrics ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + metric_name VARCHAR(50) NOT NULL, + metric_value FLOAT, + tags JSONB DEFAULT '{}', + recorded_at TIMESTAMP DEFAULT now() + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS flow_executions ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + flow_id UUID NOT NULL REFERENCES flow_definitions(id), + session_id VARCHAR(100), + status VARCHAR(20) DEFAULT 'running', + input_data JSONB DEFAULT '{}', + output_data JSONB DEFAULT '{}', + error_message TEXT, + started_by UUID REFERENCES users(id), + started_at TIMESTAMP DEFAULT now(), + finished_at TIMESTAMP, + duration_ms INTEGER + ) + """)) + await conn.execute(text(""" + CREATE TABLE IF NOT EXISTS memory_messages ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + flow_execution_id UUID NOT NULL REFERENCES flow_executions(id) ON DELETE CASCADE, + node_id VARCHAR(100) NOT NULL, + role VARCHAR(20) NOT NULL, + content TEXT NOT NULL, + metadata JSONB DEFAULT '{}', + created_at TIMESTAMP DEFAULT now() + ) + """)) + + # --- 为已有表添加缺失列 --- await conn.execute(text( "ALTER TABLE flow_definitions ADD COLUMN IF NOT EXISTS published_version_id UUID REFERENCES flow_versions(id)" )) await conn.execute(text( "ALTER TABLE flow_definitions ADD COLUMN IF NOT EXISTS draft_definition_json JSONB" )) + await conn.execute(text( + "ALTER TABLE flow_definitions ADD COLUMN IF NOT EXISTS flow_mode VARCHAR(20) DEFAULT 'chatflow'" + )) + await conn.execute(text( + "ALTER TABLE flow_definitions ADD COLUMN IF NOT EXISTS published_to_wecom BOOLEAN DEFAULT FALSE" + )) + await conn.execute(text( + "ALTER TABLE flow_definitions ADD COLUMN IF NOT EXISTS published_to_web BOOLEAN DEFAULT FALSE" + )) + await conn.execute(text( + "ALTER TABLE agent_configs ADD COLUMN IF NOT EXISTS model_instance_id UUID" + )) + await conn.execute(text( + "ALTER TABLE agent_configs ADD COLUMN IF NOT EXISTS embedding_model_id UUID" + )) + # mcp_services 表可能存在旧版本,补齐所有缺失列 + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS name VARCHAR(100) NOT NULL DEFAULT ''" + )) + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS endpoint_url VARCHAR(500) NOT NULL DEFAULT ''" + )) + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS status VARCHAR(20) DEFAULT 'active'" + )) + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS config JSONB DEFAULT '{}'" + )) + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS last_heartbeat TIMESTAMP" + )) + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT now()" + )) + await conn.execute(text( + "ALTER TABLE mcp_services ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP DEFAULT now()" + )) + # --- 其他新表的列级迁移(防止旧版本表缺少字段) --- + # model_providers + for col_sql in [ + "name VARCHAR(100) NOT NULL DEFAULT ''", + "provider_type VARCHAR(50) NOT NULL DEFAULT 'openai_compatible'", + "base_url VARCHAR(500) DEFAULT ''", + "api_key VARCHAR(500) DEFAULT ''", + "extra_config JSONB DEFAULT '{}'", + "is_active BOOLEAN DEFAULT TRUE", + "created_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE model_providers ADD COLUMN IF NOT EXISTS {col_sql}")) + # model_instances + for col_sql in [ + "id UUID PRIMARY KEY DEFAULT gen_random_uuid()", + "provider_id UUID NOT NULL REFERENCES model_providers(id) ON DELETE CASCADE", + "model_name VARCHAR(200) NOT NULL DEFAULT ''", + "model_type VARCHAR(20) NOT NULL DEFAULT 'llm'", + "display_name VARCHAR(200) DEFAULT ''", + "capabilities JSONB DEFAULT '{}'", + "default_params JSONB DEFAULT '{}'", + "is_default BOOLEAN DEFAULT FALSE", + "is_active BOOLEAN DEFAULT TRUE", + "created_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE model_instances ADD COLUMN IF NOT EXISTS {col_sql}")) + # custom_tools + for col_sql in [ + "name VARCHAR(100) UNIQUE NOT NULL DEFAULT ''", + "description TEXT", + "schema_json JSONB NOT NULL DEFAULT '{}'", + "endpoint_url VARCHAR(500) DEFAULT ''", + "method VARCHAR(10) DEFAULT 'GET'", + "path VARCHAR(500) DEFAULT ''", + "headers_json JSONB DEFAULT '{}'", + "auth_type VARCHAR(20) DEFAULT 'none'", + "auth_config JSONB DEFAULT '{}'", + "is_active BOOLEAN DEFAULT TRUE", + "created_by UUID REFERENCES users(id)", + "created_at TIMESTAMP DEFAULT now()", + "updated_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE custom_tools ADD COLUMN IF NOT EXISTS {col_sql}")) + # audit_logs + for col_sql in [ + "user_id UUID REFERENCES users(id)", + "action VARCHAR(50) NOT NULL DEFAULT ''", + "resource_type VARCHAR(50) NOT NULL DEFAULT ''", + "resource_id VARCHAR(100)", + "detail JSONB DEFAULT '{}'", + "ip_address VARCHAR(50)", + "user_agent VARCHAR(500)", + "created_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE audit_logs ADD COLUMN IF NOT EXISTS {col_sql}")) + # notification_templates + for col_sql in [ + "name VARCHAR(100) UNIQUE NOT NULL DEFAULT ''", + "channel VARCHAR(20) NOT NULL DEFAULT ''", + "event_type VARCHAR(50) NOT NULL DEFAULT ''", + "subject_template VARCHAR(500)", + "body_template TEXT", + "is_active BOOLEAN DEFAULT TRUE", + "created_at TIMESTAMP DEFAULT now()", + "updated_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE notification_templates ADD COLUMN IF NOT EXISTS {col_sql}")) + # system_metrics + for col_sql in [ + "metric_name VARCHAR(50) NOT NULL DEFAULT ''", + "metric_value FLOAT", + "tags JSONB DEFAULT '{}'", + "recorded_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE system_metrics ADD COLUMN IF NOT EXISTS {col_sql}")) + # flow_executions + for col_sql in [ + "flow_id UUID NOT NULL REFERENCES flow_definitions(id)", + "session_id VARCHAR(100)", + "status VARCHAR(20) DEFAULT 'running'", + "input_data JSONB DEFAULT '{}'", + "output_data JSONB DEFAULT '{}'", + "error_message TEXT", + "started_by UUID REFERENCES users(id)", + "started_at TIMESTAMP DEFAULT now()", + "finished_at TIMESTAMP", + "duration_ms INTEGER", + ]: + await conn.execute(text(f"ALTER TABLE flow_executions ADD COLUMN IF NOT EXISTS {col_sql}")) + # memory_messages + for col_sql in [ + "flow_execution_id UUID NOT NULL REFERENCES flow_executions(id) ON DELETE CASCADE", + "node_id VARCHAR(100) NOT NULL DEFAULT ''", + "role VARCHAR(20) NOT NULL DEFAULT 'user'", + "content TEXT NOT NULL DEFAULT ''", + "metadata JSONB DEFAULT '{}'", + "created_at TIMESTAMP DEFAULT now()", + ]: + await conn.execute(text(f"ALTER TABLE memory_messages ADD COLUMN IF NOT EXISTS {col_sql}")) async def get_db(): diff --git a/backend/dependencies.py b/backend/dependencies.py index aeb2f9c..8b70c95 100644 --- a/backend/dependencies.py +++ b/backend/dependencies.py @@ -25,7 +25,7 @@ async def get_current_user( if credentials: try: payload = jwt.decode( - credentials=credentials.credentials, + credentials.credentials, settings.JWT_SECRET, algorithms=[settings.JWT_ALGORITHM], ) diff --git a/backend/main.py b/backend/main.py index c173981..4694ac4 100644 --- a/backend/main.py +++ b/backend/main.py @@ -5,7 +5,6 @@ from modules.auth.router import router as auth_router from modules.org.router import router as org_router from modules.rbac.router import router as rbac_router from modules.wecom.router import router as wecom_router -from modules.agent_manager.router import router as agent_manager_router from modules.task.router import router as task_router from modules.monitor.router import router as monitor_router from modules.mcp_registry.router import router as mcp_router @@ -61,7 +60,6 @@ app.include_router(auth_router) # 认证模块 app.include_router(org_router) # 组织架构模块 app.include_router(rbac_router) # 权限管理模块 app.include_router(wecom_router) # 企业微信模块 -app.include_router(agent_manager_router) # 智能体管理模块 app.include_router(task_router) # 任务管理模块 app.include_router(monitor_router) # 监控模块 app.include_router(mcp_router) # MCP 服务注册模块 diff --git a/backend/models/__init__.py b/backend/models/__init__.py index 15500c9..433b359 100644 --- a/backend/models/__init__.py +++ b/backend/models/__init__.py @@ -211,3 +211,157 @@ class FlowTemplate(Base): created_by = Column(UUID(as_uuid=True), ForeignKey("users.id")) # 创建者用户 ID created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 记录更新时间 + + +class AgentConfig(Base): + """智能体配置表 (agent_configs),存储 AI 智能体的配置参数。""" + __tablename__ = "agent_configs" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 配置唯一标识 UUID + name = Column(String(200), nullable=False) # 智能体名称 + description = Column(Text) # 智能体描述 + system_prompt = Column(Text) # 系统提示词 + model = Column(String(100), default="") # 默认模型名称 + model_instance_id = Column(UUID(as_uuid=True), nullable=True) # 关联的模型实例 ID + embedding_model_id = Column(UUID(as_uuid=True), nullable=True) # 关联的嵌入模型 ID + temperature = Column(Float, default=0.7) # 温度参数 + tools = Column(JSON, default=list) # 可用工具列表 + status = Column(String(20), default="active") # 状态:active/inactive + creator_id = Column(UUID(as_uuid=True), ForeignKey("users.id")) # 创建者用户 ID + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 + updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 记录更新时间 + + +class ModelProvider(Base): + """模型供应商表 (model_providers),存储 LLM/Embedding/Rerank 模型供应商的接入配置。""" + __tablename__ = "model_providers" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 供应商唯一标识 UUID + name = Column(String(100), nullable=False) # 供应商名称(如 OpenAI、智谱AI) + provider_type = Column(String(50), nullable=False) # 供应商类型:openai_compatible/openai/zhipu/ollama/deepseek + base_url = Column(String(500)) # API 基础地址 + api_key = Column(String(500)) # API 密钥(加密存储) + extra_config = Column(JSON, default=dict) # 额外配置(如 region、project 等) + is_active = Column(Boolean, default=True) # 是否启用 + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 + + +class ModelInstance(Base): + """模型实例表 (model_instances),存储供应商下的具体模型实例。支持 LLM/Embedding/Rerank 三种类型。""" + __tablename__ = "model_instances" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 实例唯一标识 UUID + provider_id = Column(UUID(as_uuid=True), ForeignKey("model_providers.id", ondelete="CASCADE"), nullable=False) # 所属供应商 ID + model_name = Column(String(200), nullable=False) # 模型标识名(如 gpt-4o、text-embedding-3-small、bge-reranker-v2-m3) + model_type = Column(String(20), nullable=False) # 模型类型:llm/embedding/rerank + display_name = Column(String(200)) # 显示名称(如 GPT-4o、Embedding-3-Small、BGE Reranker) + capabilities = Column(JSON, default=dict) # 能力配置(LLM: vision/function_calling; Embedding/Rerank: dimension/max_tokens) + default_params = Column(JSON, default=dict) # 默认参数(如 temperature、max_tokens、dimension) + is_default = Column(Boolean, default=False) # 是否为该类型下的默认模型 + is_active = Column(Boolean, default=True) # 是否启用 + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 + + +class CustomTool(Base): + """自定义工具表 (custom_tools),存储用户自定义的 HTTP 工具定义。""" + __tablename__ = "custom_tools" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 工具唯一标识 UUID + name = Column(String(100), unique=True, nullable=False) # 工具名称(唯一) + description = Column(Text) # 工具描述 + schema_json = Column(JSON, nullable=False, default=dict) # 参数 Schema 定义 JSON + endpoint_url = Column(String(500), default="") # API 端点 URL + method = Column(String(10), default="GET") # HTTP 方法 + path = Column(String(500), default="") # API 路径 + headers_json = Column(JSON, default=dict) # 自定义请求头 + auth_type = Column(String(20), default="none") # 认证类型:none/api_key/bearer + auth_config = Column(JSON, default=dict) # 认证配置信息 + is_active = Column(Boolean, default=True) # 是否启用(软删除标记) + created_by = Column(UUID(as_uuid=True), ForeignKey("users.id")) # 创建者用户 ID + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 + updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 记录更新时间 + + +class MCPService(Base): + """MCP 服务注册表 (mcp_services),存储 Model Context Protocol 服务的注册信息。""" + __tablename__ = "mcp_services" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 服务唯一标识 UUID + name = Column(String(100), nullable=False) # 服务名称 + endpoint_url = Column(String(500), nullable=False) # MCP 服务端点 URL + status = Column(String(20), default="active") # 服务状态:active/inactive/error + config = Column(JSON, default=dict) # 服务配置信息 + last_heartbeat = Column(DateTime) # 最后心跳时间 + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 + updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 记录更新时间 + + +class AuditLog(Base): + """审计日志表 (audit_logs),记录系统关键操作的审计追踪日志。""" + __tablename__ = "audit_logs" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 日志唯一标识 UUID + user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True) # 操作用户 ID + action = Column(String(50), nullable=False) # 操作类型(create/update/delete/login/export) + resource_type = Column(String(50), nullable=False) # 资源类型(user/agent/flow/document/task) + resource_id = Column(String(100)) # 资源 ID + detail = Column(JSON, default=dict) # 操作详情 JSON + ip_address = Column(String(50)) # 操作来源 IP + user_agent = Column(String(500)) # 客户端 User-Agent + created_at = Column(DateTime, default=datetime.utcnow) # 日志记录时间 + + +class NotificationTemplate(Base): + """通知模板表 (notification_templates),存储企业微信等渠道的消息通知模板。""" + __tablename__ = "notification_templates" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 模板唯一标识 UUID + name = Column(String(100), unique=True, nullable=False) # 模板名称(唯一) + channel = Column(String(20), nullable=False) # 通知渠道:wecom/email/webhook + event_type = Column(String(50), nullable=False) # 触发事件类型 + subject_template = Column(String(500)) # 消息标题模板 + body_template = Column(Text) # 消息正文模板 + is_active = Column(Boolean, default=True) # 是否启用 + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 + updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) # 记录更新时间 + + +class SystemMetric(Base): + """系统指标表 (system_metrics),存储系统运行时性能指标数据。""" + __tablename__ = "system_metrics" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 指标唯一标识 UUID + metric_name = Column(String(50), nullable=False) # 指标名称(cpu/memory/request_latency/active_users) + metric_value = Column(Float) # 指标数值 + tags = Column(JSON, default=dict) # 标签维度(如 instance、region) + recorded_at = Column(DateTime, default=datetime.utcnow, index=True) # 记录时间(索引) + + +class FlowExecution(Base): + """流程执行记录表 (flow_executions),存储工作流每次执行的详细记录。""" + __tablename__ = "flow_executions" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 执行记录唯一标识 UUID + flow_id = Column(UUID(as_uuid=True), ForeignKey("flow_definitions.id"), nullable=False) # 关联的流程定义 ID + session_id = Column(String(100)) # 关联的会话 ID + status = Column(String(20), default="running") # 执行状态:running/completed/failed/cancelled + input_data = Column(JSON, default=dict) # 输入数据 + output_data = Column(JSON, default=dict) # 输出数据 + error_message = Column(Text) # 错误信息(失败时记录) + started_by = Column(UUID(as_uuid=True), ForeignKey("users.id")) # 触发执行的用户 ID + started_at = Column(DateTime, default=datetime.utcnow) # 开始时间 + finished_at = Column(DateTime) # 结束时间 + duration_ms = Column(Integer) # 执行耗时(毫秒) + + +class MemoryMessage(Base): + """记忆消息表 (memory_messages),存储流程引擎中节点的中间记忆数据。""" + __tablename__ = "memory_messages" + + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) # 消息唯一标识 UUID + flow_execution_id = Column(UUID(as_uuid=True), ForeignKey("flow_executions.id", ondelete="CASCADE"), nullable=False) # 关联的流程执行 ID + node_id = Column(String(100), nullable=False) # 节点标识 + role = Column(String(20), nullable=False) # 消息角色:user/assistant/system/tool + content = Column(Text, nullable=False) # 消息内容 + metadata_ = Column("metadata", JSON, default=dict) # 元数据 + created_at = Column(DateTime, default=datetime.utcnow) # 记录创建时间 diff --git a/backend/modules/audit/router.py b/backend/modules/audit/router.py index 10d5065..abd9970 100644 --- a/backend/modules/audit/router.py +++ b/backend/modules/audit/router.py @@ -26,7 +26,7 @@ async def list_logs( page_size: int = Query(20, ge=1, le=100), action: str | None = Query(None), resource: str | None = Query(None), - operator_id: uuid.UUID | None = Query(None), + user_id: uuid.UUID | None = Query(None), date_from: datetime | None = Query(None), date_to: datetime | None = Query(None), db: AsyncSession = Depends(get_db), @@ -39,7 +39,7 @@ async def list_logs( page_size: 每页数量,最大 100。 action: 可选的操作类型筛选条件。 resource: 可选的资源类型筛选条件。 - operator_id: 可选的操作人 ID 筛选条件。 + user_id: 可选的操作人 ID 筛选条件。 date_from: 可选的起始时间筛选条件。 date_to: 可选的结束时间筛选条件。 db: 异步数据库会话。 @@ -51,9 +51,9 @@ async def list_logs( if action: conditions.append(AuditLog.action == action) if resource: - conditions.append(AuditLog.resource == resource) - if operator_id: - conditions.append(AuditLog.operator_id == operator_id) + conditions.append(AuditLog.resource_type == resource) + if user_id: + conditions.append(AuditLog.user_id == user_id) if date_from: conditions.append(AuditLog.created_at >= date_from) if date_to: @@ -135,8 +135,8 @@ async def audit_stats(request: Request, db: AsyncSession = Depends(get_db)): # 最常见的资源类型 TOP 10 top_resources = await db.execute( - select(AuditLog.resource, func.count(AuditLog.id)) - .group_by(AuditLog.resource) + select(AuditLog.resource_type, func.count(AuditLog.id)) + .group_by(AuditLog.resource_type) .order_by(func.count(AuditLog.id).desc()) .limit(10) ) @@ -191,9 +191,9 @@ async def export_logs( writer.writerow([ str(log.id), log.created_at.isoformat() if log.created_at else "", - str(log.operator_id) if log.operator_id else "", + str(log.user_id) if log.user_id else "", log.action, - log.resource or "", + log.resource_type or "", log.resource_id or "", str(log.detail)[:500] if log.detail else "", log.ip_address or "", diff --git a/backend/modules/memory/manager.py b/backend/modules/memory/manager.py index 71c7715..74e69cf 100644 --- a/backend/modules/memory/manager.py +++ b/backend/modules/memory/manager.py @@ -658,7 +658,7 @@ class MemoryManager: latest_scene = atoms_result.fetchone() if latest_scene: from datetime import timezone, timedelta - ago = datetime.now(timezone.utc) - latest_scene[0].replace(tzinfo=timezone=timezone.utc) + ago = datetime.now(timezone.utc) - latest_scene[0].replace(tzinfo=timezone.utc) if ago < timedelta(hours=12): return diff --git a/frontend/src/components/layout/AdminLayout.vue b/frontend/src/components/layout/AdminLayout.vue index 22f3cd5..4aa8eed 100644 --- a/frontend/src/components/layout/AdminLayout.vue +++ b/frontend/src/components/layout/AdminLayout.vue @@ -54,7 +54,6 @@ 模型供应商管理 知识库管理 - 智能体管理 企微机器人配置 diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index adfea0a..0a0b989 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -173,18 +173,6 @@ const router = createRouter({ component: () => import('@/views/model/ModelProviderManager.vue'), meta: { title: '模型供应商管理', perms: ['admin:access'] }, }, - { - path: 'agent/list', - name: 'AdminAgentList', - component: () => import('@/views/agent/AgentList.vue'), - meta: { title: '智能体管理', perms: ['admin:access'] }, - }, - { - path: 'agent/chat/:type', - name: 'AdminAgentChat', - component: () => import('@/views/agent/AgentChat.vue'), - meta: { title: '智能体对话', perms: ['admin:access'] }, - }, { path: 'monitor/employees', name: 'AdminMonitorEmployees', diff --git a/frontend/src/views/dashboard/Dashboard.vue b/frontend/src/views/dashboard/Dashboard.vue index 7227d07..6a41867 100644 --- a/frontend/src/views/dashboard/Dashboard.vue +++ b/frontend/src/views/dashboard/Dashboard.vue @@ -33,8 +33,8 @@
- - 智能体对话 + + 模型管理 创建任务 diff --git a/frontend/src/views/flow/FlowEditor.vue b/frontend/src/views/flow/FlowEditor.vue index 7710afa..91262f4 100644 --- a/frontend/src/views/flow/FlowEditor.vue +++ b/frontend/src/views/flow/FlowEditor.vue @@ -83,7 +83,7 @@ v-if="selectedNode?.data?.type" :is="getConfigComponent(selectedNode.data.type)" v-model="selectedNodeData.config" - :agent-list="agentList" + :model-list="modelList" :mcp-servers="mcpServers" @change="onConfigChange" /> @@ -163,7 +163,7 @@ const loadingVersions = ref(false) const selectedNodeId = ref('') const selectedNodeData = ref({}) const mcpServers = ref([]) -const agentList = ref([]) +const modelList = ref([]) const nodes = ref([]) const edges = ref([]) @@ -378,8 +378,8 @@ async function loadMcpServers() { try { const { mcpApi } = await import('@/api'); const res: any = await mcpApi.getServers(); mcpServers.value = Array.isArray(res) ? res : (res?.data || []) } catch {} } -async function loadAgents() { - try { const { agentApi } = await import('@/api'); const res: any = await agentApi.getList(); agentList.value = Array.isArray(res?.data) ? res.data : (Array.isArray(res) ? res : []) } catch {} +async function loadModels() { + try { const { modelProviderApi } = await import('@/api'); const res: any = await modelProviderApi.getAllModels(); modelList.value = Array.isArray(res?.data) ? res.data : (Array.isArray(res) ? res : []) } catch {} } async function saveFlow() { @@ -445,7 +445,7 @@ function formatTime(ts: string) { onMounted(async () => { try { if (isEdit.value) { await loadFlow() } - await Promise.allSettled([loadMcpServers(), loadAgents()]) + await Promise.allSettled([loadMcpServers(), loadModels()]) startAutoSave() } catch (e: any) { console.error('FlowEditor init error:', e) diff --git a/frontend/src/views/flow/node-configs/LlmConfig.vue b/frontend/src/views/flow/node-configs/LlmConfig.vue index 7f2b658..e93bc69 100644 --- a/frontend/src/views/flow/node-configs/LlmConfig.vue +++ b/frontend/src/views/flow/node-configs/LlmConfig.vue @@ -1,43 +1,60 @@ diff --git a/frontend/src/views/flow/node-configs/TemplateTransformConfig.vue b/frontend/src/views/flow/node-configs/TemplateTransformConfig.vue index a83f0d2..b0d4efc 100644 --- a/frontend/src/views/flow/node-configs/TemplateTransformConfig.vue +++ b/frontend/src/views/flow/node-configs/TemplateTransformConfig.vue @@ -30,13 +30,13 @@

常用模板:

-
+
请帮我处理:{"{{input}}"}
-
+
根据{"{{rag_node.output}}"},回答:{"{{input}}"}
-
+
{"{"}"query": "{"{{input}}"}", "context": "{"{{trigger.data}}"}"{"}"}
@@ -50,6 +50,12 @@ const props = defineProps<{ const emit = defineEmits(['change', 'update:modelValue']) +const templateExamples = { + simple: '请帮我处理:{{input}}', + rag: '根据{{rag_node.output}},回答:{{input}}', + json: '{"query": "{{input}}", "context": "{{trigger.data}}"}', +} + function update(key: string, val: any) { emit('change') emit('update:modelValue', { ...props.modelValue, [key]: val }) diff --git a/frontend/src/views/model/ModelProviderManager.vue b/frontend/src/views/model/ModelProviderManager.vue index ec7ee85..31d25c0 100644 --- a/frontend/src/views/model/ModelProviderManager.vue +++ b/frontend/src/views/model/ModelProviderManager.vue @@ -1,139 +1,339 @@