Merge pull request #522 from SuanmoSuanyangTechnology/fix/bug-patch

feat(workspace, app, agent): add duplicate name validation and restrict model/memory config on agent publish
This commit is contained in:
Mark
2026-03-10 11:31:54 +08:00
committed by GitHub
5 changed files with 233 additions and 160 deletions

View File

@@ -1,7 +1,6 @@
import json
import os import os
from pathlib import Path from pathlib import Path
from typing import Annotated, Any, Dict, Optional from typing import Annotated, Optional
from dotenv import load_dotenv from dotenv import load_dotenv
from pydantic import Field, TypeAdapter from pydantic import Field, TypeAdapter

View File

@@ -1,10 +1,11 @@
from sqlalchemy.orm import Session
from typing import List, Optional
import uuid import uuid
from typing import List
from app.models.app_model import App from sqlalchemy import select
from sqlalchemy.orm import Session
from app.core.logging_config import get_db_logger from app.core.logging_config import get_db_logger
from app.models.app_model import App
# 获取数据库专用日志器 # 获取数据库专用日志器
db_logger = get_db_logger() db_logger = get_db_logger()
@@ -35,11 +36,27 @@ class AppRepository:
except Exception as e: except Exception as e:
raise raise
def get_apps_by_name(self, app_name: str, app_type: str, workspace_id: uuid.UUID) -> List[App]:
try:
stmt = select(App).where(
App.name == app_name,
App.workspace_id == workspace_id,
App.type == app_type,
App.is_active.is_(True),
)
apps = self.db.execute(stmt).scalars().all()
return list(apps)
except Exception as e:
db_logger.error(f"查询名称 {app_name} 应用异常: {str(e)}")
raise
def get_apps_by_workspace_id(db: Session, workspace_id: uuid.UUID) -> List[App]: def get_apps_by_workspace_id(db: Session, workspace_id: uuid.UUID) -> List[App]:
"""根据工作空间ID查询应用""" """根据工作空间ID查询应用"""
repo = AppRepository(db) repo = AppRepository(db)
return repo.get_apps_by_workspace_id(workspace_id) return repo.get_apps_by_workspace_id(workspace_id)
def get_apps_by_id(db: Session, app_id: uuid.UUID) -> App: def get_apps_by_id(db: Session, app_id: uuid.UUID) -> App:
"""根据工作空间ID查询应用""" """根据工作空间ID查询应用"""
repo = AppRepository(db) repo = AppRepository(db)

View File

@@ -1,10 +1,13 @@
from sqlalchemy.orm import Session, joinedload
from app.models.user_model import User
from typing import List, Optional
import uuid import uuid
from app.models.workspace_model import Workspace, WorkspaceMember, WorkspaceRole from typing import List, Optional
from app.schemas.workspace_schema import WorkspaceCreate, WorkspaceUpdate
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import select
from app.core.logging_config import get_db_logger from app.core.logging_config import get_db_logger
from app.models.user_model import User
from app.models.workspace_model import Workspace, WorkspaceMember, WorkspaceRole
from app.schemas.workspace_schema import WorkspaceCreate
# 获取数据库专用日志器 # 获取数据库专用日志器
db_logger = get_db_logger() db_logger = get_db_logger()
@@ -34,7 +37,8 @@ class WorkspaceRepository:
) )
self.db.add(db_workspace) self.db.add(db_workspace)
self.db.flush() self.db.flush()
db_logger.info(f"工作空间记录创建成功: {workspace_data.name} (ID: {db_workspace.id}), storage_type: {workspace_data.storage_type}") db_logger.info(
f"工作空间记录创建成功: {workspace_data.name} (ID: {db_workspace.id}), storage_type: {workspace_data.storage_type}")
return db_workspace return db_workspace
except Exception as e: except Exception as e:
db_logger.error(f"创建工作空间记录失败: name={workspace_data.name} - {str(e)}") db_logger.error(f"创建工作空间记录失败: name={workspace_data.name} - {str(e)}")
@@ -144,7 +148,25 @@ class WorkspaceRepository:
db_logger.error(f"查询租户工作空间失败: tenant_id={tenant_id} - {str(e)}") db_logger.error(f"查询租户工作空间失败: tenant_id={tenant_id} - {str(e)}")
raise raise
def add_member(self, workspace_id: uuid.UUID, user_id: uuid.UUID, role: WorkspaceRole = WorkspaceRole.member) -> WorkspaceMember: def get_workspaces_by_name(self, tenant_id: uuid.UUID, workspace_name: str) -> List[Workspace]:
try:
stmt = (
select(Workspace)
.where(
Workspace.tenant_id == tenant_id,
Workspace.name == workspace_name,
Workspace.is_active.is_(True)
)
)
workspaces = self.db.execute(stmt).scalars().all()
return list(workspaces)
except Exception as e:
db_logger.error(f"查询工作空间失败: workspace_name={workspace_name} - {str(e)}")
raise
def add_member(self, workspace_id: uuid.UUID, user_id: uuid.UUID,
role: WorkspaceRole = WorkspaceRole.member) -> WorkspaceMember:
"""添加工作空间成员""" """添加工作空间成员"""
db_logger.debug(f"添加工作空间成员: user_id={user_id}, workspace_id={workspace_id}, role={role}") db_logger.debug(f"添加工作空间成员: user_id={user_id}, workspace_id={workspace_id}, role={role}")
@@ -173,7 +195,8 @@ class WorkspaceRepository:
WorkspaceMember.is_active.is_(True), WorkspaceMember.is_active.is_(True),
).first() ).first()
if member: if member:
db_logger.debug(f"工作空间成员查询成功: user_id={user_id}, workspace_id={workspace_id}, role={member.role}") db_logger.debug(
f"工作空间成员查询成功: user_id={user_id}, workspace_id={workspace_id}, role={member.role}")
else: else:
db_logger.debug(f"工作空间成员不存在: user_id={user_id}, workspace_id={workspace_id}") db_logger.debug(f"工作空间成员不存在: user_id={user_id}, workspace_id={workspace_id}")
return member return member
@@ -214,7 +237,8 @@ class WorkspaceRepository:
.first() .first()
) )
if member: if member:
db_logger.debug(f"成员查询成功: member_id={member_id}, workspace_id={member.workspace_id}, role={member.role}") db_logger.debug(
f"成员查询成功: member_id={member_id}, workspace_id={member.workspace_id}, role={member.role}")
else: else:
db_logger.debug(f"成员不存在: member_id={member_id}") db_logger.debug(f"成员不存在: member_id={member_id}")
return member return member
@@ -222,7 +246,8 @@ class WorkspaceRepository:
db_logger.error(f"查询成员列表失败: member_id={member_id} - {str(e)}") db_logger.error(f"查询成员列表失败: member_id={member_id} - {str(e)}")
raise raise
def update_member_role(self, workspace_id: uuid.UUID, user_id: uuid.UUID, role: WorkspaceRole) -> Optional[WorkspaceMember]: def update_member_role(self, workspace_id: uuid.UUID, user_id: uuid.UUID, role: WorkspaceRole) -> Optional[
WorkspaceMember]:
try: try:
member = self.db.query(WorkspaceMember).filter( member = self.db.query(WorkspaceMember).filter(
WorkspaceMember.workspace_id == workspace_id, WorkspaceMember.workspace_id == workspace_id,
@@ -288,12 +313,18 @@ class WorkspaceRepository:
db_logger.error(f"更新成员角色失败: id={id} - {str(e)}") db_logger.error(f"更新成员角色失败: id={id} - {str(e)}")
raise raise
# 保持向后兼容的函数 # 保持向后兼容的函数
def get_workspace_by_id(db: Session, workspace_id: uuid.UUID) -> Workspace | None: def get_workspace_by_id(db: Session, workspace_id: uuid.UUID) -> Workspace | None:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.get_workspace_by_id(workspace_id) return repo.get_workspace_by_id(workspace_id)
def get_workspaces_by_name(db: Session, tenant_id: uuid.UUID, name: str) -> List[Workspace]:
repo = WorkspaceRepository(db)
return repo.get_workspaces_by_name(tenant_id, name)
def get_workspaces_by_user(db: Session, user_id: uuid.UUID) -> List[Workspace]: def get_workspaces_by_user(db: Session, user_id: uuid.UUID) -> List[Workspace]:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.get_workspaces_by_user(user_id) return repo.get_workspaces_by_user(user_id)
@@ -315,7 +346,7 @@ def create_workspace(db: Session, workspace: WorkspaceCreate, tenant_id: uuid.UU
def add_member_to_workspace( def add_member_to_workspace(
db: Session, user_id: uuid.UUID, workspace_id: uuid.UUID, role: WorkspaceRole db: Session, user_id: uuid.UUID, workspace_id: uuid.UUID, role: WorkspaceRole
) -> WorkspaceMember: ) -> WorkspaceMember:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.add_member(workspace_id, user_id, role) return repo.add_member(workspace_id, user_id, role)
@@ -325,39 +356,43 @@ def get_members_by_workspace(db: Session, workspace_id: uuid.UUID) -> List[Works
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.get_members_by_workspace(workspace_id) return repo.get_members_by_workspace(workspace_id)
def get_member_by_id(db: Session, member_id: uuid.UUID) -> WorkspaceMember | None: def get_member_by_id(db: Session, member_id: uuid.UUID) -> WorkspaceMember | None:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.get_member_by_id(member_id) return repo.get_member_by_id(member_id)
def update_member_role_in_workspace( def update_member_role_in_workspace(
db: Session, db: Session,
user_id: uuid.UUID, user_id: uuid.UUID,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
role: WorkspaceRole, role: WorkspaceRole,
) -> Optional[WorkspaceMember]: ) -> Optional[WorkspaceMember]:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.update_member_role(workspace_id, user_id, role) return repo.update_member_role(workspace_id, user_id, role)
def remove_member_from_workspace( def remove_member_from_workspace(
db: Session, db: Session,
user_id: uuid.UUID, user_id: uuid.UUID,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
) -> Optional[WorkspaceMember]: ) -> Optional[WorkspaceMember]:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.deactivate_member(workspace_id, user_id) return repo.deactivate_member(workspace_id, user_id)
def remove_member_from_workspace_by_id( def remove_member_from_workspace_by_id(
db: Session, db: Session,
member_id: uuid.UUID, member_id: uuid.UUID,
) -> Optional[WorkspaceMember]: ) -> Optional[WorkspaceMember]:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.delete_member_by_id(member_id) return repo.delete_member_by_id(member_id)
def update_member_role_by_id( def update_member_role_by_id(
db: Session, db: Session,
id: uuid.UUID, id: uuid.UUID,
role: WorkspaceRole, role: WorkspaceRole,
) -> Optional[WorkspaceMember]: ) -> Optional[WorkspaceMember]:
repo = WorkspaceRepository(db) repo = WorkspaceRepository(db)
return repo.update_member_role_by_id(id, role) return repo.update_member_role_by_id(id, role)

View File

@@ -33,7 +33,7 @@ from app.models import (
Workspace, Workspace,
) )
from app.models.app_model import AppStatus, AppType from app.models.app_model import AppStatus, AppType
from app.repositories.app_repository import get_apps_by_id from app.repositories.app_repository import get_apps_by_id, AppRepository
from app.repositories.workflow_repository import WorkflowConfigRepository from app.repositories.workflow_repository import WorkflowConfigRepository
from app.schemas import app_schema from app.schemas import app_schema
from app.schemas.workflow_schema import WorkflowConfigUpdate from app.schemas.workflow_schema import WorkflowConfigUpdate
@@ -59,6 +59,7 @@ class AppService:
db: 数据库会话 db: 数据库会话
""" """
self.db = db self.db = db
self.app_repo = AppRepository(self.db)
# ==================== 私有辅助方法 ==================== # ==================== 私有辅助方法 ====================
@@ -521,6 +522,9 @@ class AppService:
"创建应用", "创建应用",
extra={"app_name": data.name, "type": data.type, "workspace_id": str(workspace_id)} extra={"app_name": data.name, "type": data.type, "workspace_id": str(workspace_id)}
) )
apps = self.app_repo.get_apps_by_name(data.name, data.type, workspace_id)
if apps:
raise BusinessException(message="已存在同名应用", code=BizCode.RESOURCE_ALREADY_EXISTS)
try: try:
now = datetime.datetime.now() now = datetime.datetime.now()
@@ -1368,6 +1372,15 @@ class AppService:
if not agent_cfg: if not agent_cfg:
raise BusinessException("Agent 应用缺少配置,无法发布", BizCode.AGENT_CONFIG_MISSING) raise BusinessException("Agent 应用缺少配置,无法发布", BizCode.AGENT_CONFIG_MISSING)
miss_params = []
if agent_cfg.default_model_config_id is None:
miss_params.append("model config")
if agent_cfg.memory.get("enabled") and not agent_cfg.memory.get("memory_config_id"):
miss_params.append("memory config")
if miss_params:
raise BusinessException(f"{', '.join(miss_params)} is required")
config = { config = {
"system_prompt": agent_cfg.system_prompt, "system_prompt": agent_cfg.system_prompt,
"model_parameters": model_parameters_to_dict(agent_cfg.model_parameters), "model_parameters": model_parameters_to_dict(agent_cfg.model_parameters),

View File

@@ -2,11 +2,11 @@ import datetime
import hashlib import hashlib
import secrets import secrets
import uuid import uuid
from os import getenv
from typing import List, Optional from typing import List, Optional
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
from app.config.default_ontology_initializer import DefaultOntologyInitializer
from app.core.config import settings from app.core.config import settings
from app.core.error_codes import BizCode from app.core.error_codes import BizCode
from app.core.exceptions import BusinessException, PermissionDeniedException from app.core.exceptions import BusinessException, PermissionDeniedException
@@ -30,17 +30,15 @@ from app.schemas.workspace_schema import (
WorkspaceModelsUpdate, WorkspaceModelsUpdate,
WorkspaceUpdate, WorkspaceUpdate,
) )
from app.config.default_ontology_initializer import DefaultOntologyInitializer
# 获取业务逻辑专用日志器 # 获取业务逻辑专用日志器
business_logger = get_business_logger() business_logger = get_business_logger()
from dotenv import load_dotenv
load_dotenv()
def switch_workspace( def switch_workspace(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
user: User, user: User,
): ):
"""切换工作空间""" """切换工作空间"""
business_logger.debug(f"用户 {user.username} 请求切换工作空间为 {workspace_id}") business_logger.debug(f"用户 {user.username} 请求切换工作空间为 {workspace_id}")
@@ -60,31 +58,32 @@ def switch_workspace(
raise BusinessException(f"切换工作空间失败: {str(e)}", BizCode.INTERNAL_ERROR) raise BusinessException(f"切换工作空间失败: {str(e)}", BizCode.INTERNAL_ERROR)
def delete_workspace_member( def delete_workspace_member(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
member_id: uuid.UUID, member_id: uuid.UUID,
user: User, user: User,
): ):
"""删除工作空间成员""" """删除工作空间成员"""
business_logger.debug(f"用户 {user.username} 请求删除工作空间 {workspace_id} 的成员 {member_id}") business_logger.debug(f"用户 {user.username} 请求删除工作空间 {workspace_id} 的成员 {member_id}")
_check_workspace_admin_permission(db, workspace_id, user) _check_workspace_admin_permission(db, workspace_id, user)
workspace_member = workspace_repository.get_member_by_id(db=db, member_id=member_id) workspace_member = workspace_repository.get_member_by_id(db=db, member_id=member_id)
if not workspace_member: if not workspace_member:
raise BusinessException(f"工作空间成员 {member_id} 不存在", BizCode.WORKSPACE_NOT_FOUND) raise BusinessException(f"工作空间成员 {member_id} 不存在", BizCode.WORKSPACE_NOT_FOUND)
if workspace_member.workspace_id != workspace_id: if workspace_member.workspace_id != workspace_id:
raise BusinessException(f"工作空间成员 {member_id} 不存在于工作空间 {workspace_id}", BizCode.WORKSPACE_NOT_FOUND) raise BusinessException(f"工作空间成员 {member_id} 不存在于工作空间 {workspace_id}",
BizCode.WORKSPACE_NOT_FOUND)
try: try:
workspace_member.is_active = False workspace_member.is_active = False
workspace_member.user.current_workspace_id = None workspace_member.user.current_workspace_id = None
db.commit() db.commit()
business_logger.info(f"用户 {user.username} 成功删除工作空间 {workspace_id} 的成员 {member_id}") business_logger.info(f"用户 {user.username} 成功删除工作空间 {workspace_id} 的成员 {member_id}")
except Exception as e: except Exception as e:
db.rollback() db.rollback()
business_logger.error(f"删除工作空间成员失败 - 工作空间: {workspace_id}, 成员: {member_id}, 错误: {str(e)}") business_logger.error(f"删除工作空间成员失败 - 工作空间: {workspace_id}, 成员: {member_id}, 错误: {str(e)}")
raise BusinessException(f"删除工作空间成员失败: {str(e)}", BizCode.INTERNAL_ERROR) raise BusinessException(f"删除工作空间成员失败: {str(e)}", BizCode.INTERNAL_ERROR)
def get_user_workspaces(db: Session, user: User) -> List[Workspace]: def get_user_workspaces(db: Session, user: User) -> List[Workspace]:
@@ -114,7 +113,7 @@ def get_user_workspaces(db: Session, user: User) -> List[Workspace]:
def _create_workspace_only( def _create_workspace_only(
db: Session, workspace: WorkspaceCreate, owner: User db: Session, workspace: WorkspaceCreate, owner: User
) -> Workspace: ) -> Workspace:
business_logger.debug(f"创建工作空间: {workspace.name}, 创建者: {owner.username}") business_logger.debug(f"创建工作空间: {workspace.name}, 创建者: {owner.username}")
@@ -138,9 +137,14 @@ def create_workspace(
f"创建工作空间: {workspace.name}, 创建者: {user.username}, " f"创建工作空间: {workspace.name}, 创建者: {user.username}, "
f"storage_type: {workspace.storage_type}" f"storage_type: {workspace.storage_type}"
) )
llm=workspace.llm if workspace_repository.get_workspaces_by_name(db=db, name=workspace.name, tenant_id=user.tenant_id):
embedding=workspace.embedding raise BusinessException(
rerank=workspace.rerank message="同名工作空间已存在",
code=BizCode.RESOURCE_ALREADY_EXISTS
)
llm = workspace.llm
embedding = workspace.embedding
rerank = workspace.rerank
try: try:
# Create the workspace without adding any members # Create the workspace without adding any members
business_logger.debug(f"创建工作空间: {workspace.name}") business_logger.debug(f"创建工作空间: {workspace.name}")
@@ -165,7 +169,7 @@ def create_workspace(
f"为工作空间 {db_workspace.id} 创建默认本体场景成功 (language={language})" f"为工作空间 {db_workspace.id} 创建默认本体场景成功 (language={language})"
) )
# 获取默认场景ID优先使用"在线教育"场景,如果不存在则使用"情感陪伴"场景 # 获取默认场景ID优先使用"在线教育"场景,如果不存在则使用"情感陪伴"场景
from app.repositories.ontology_scene_repository import OntologySceneRepository from app.repositories.ontology_scene_repository import OntologySceneRepository
from app.config.default_ontology_config import ( from app.config.default_ontology_config import (
ONLINE_EDUCATION_SCENE, ONLINE_EDUCATION_SCENE,
@@ -256,10 +260,10 @@ def create_workspace(
avatar='', avatar='',
type=KnowledgeType.General, type=KnowledgeType.General,
permission_id=PermissionType.Memory, permission_id=PermissionType.Memory,
embedding_id=uuid.UUID(getenv('KB_embedding_id')) if None else embedding, embedding_id=embedding,
reranker_id=uuid.UUID(getenv('KB_reranker_id')) if None else rerank, reranker_id=rerank,
llm_id=uuid.UUID(getenv('KB_llm_id')) if None else llm, llm_id=llm,
image2text_id=uuid.UUID(getenv('KB_llm_id')) if None else llm, image2text_id=llm,
parser_config={ parser_config={
"layout_recognize": "DeepDOC", "layout_recognize": "DeepDOC",
"chunk_token_num": 256, "chunk_token_num": 256,
@@ -304,11 +308,11 @@ def create_workspace(
def update_workspace( def update_workspace(
db: Session, workspace_id: uuid.UUID, workspace_in: WorkspaceUpdate, user: User db: Session, workspace_id: uuid.UUID, workspace_in: WorkspaceUpdate, user: User
) -> Workspace: ) -> Workspace:
business_logger.info(f"更新工作空间: workspace_id={workspace_id}, 操作者: {user.username}") business_logger.info(f"更新工作空间: workspace_id={workspace_id}, 操作者: {user.username}")
db_workspace = _check_workspace_admin_permission(db,workspace_id,user) db_workspace = _check_workspace_admin_permission(db, workspace_id, user)
try: try:
# 更新工作空间 # 更新工作空间
business_logger.debug(f"执行工作空间更新: {db_workspace.name} (ID: {workspace_id})") business_logger.debug(f"执行工作空间更新: {db_workspace.name} (ID: {workspace_id})")
@@ -328,7 +332,7 @@ def update_workspace(
def get_workspace_members( def get_workspace_members(
db: Session, workspace_id: uuid.UUID, user: User db: Session, workspace_id: uuid.UUID, user: User
) -> List[WorkspaceMember]: ) -> List[WorkspaceMember]:
"""获取某工作空间的成员列表(关系序列化由模型关系支持)""" """获取某工作空间的成员列表(关系序列化由模型关系支持)"""
business_logger.info(f"获取工作空间成员: workspace_id={workspace_id}, 操作者: {user.username}") business_logger.info(f"获取工作空间成员: workspace_id={workspace_id}, 操作者: {user.username}")
@@ -372,7 +376,6 @@ def get_workspace_members(
return members return members
# ==================== 邀请相关服务方法 ==================== # ==================== 邀请相关服务方法 ====================
def _generate_invite_token() -> tuple[str, str]: def _generate_invite_token() -> tuple[str, str]:
@@ -465,13 +468,14 @@ def _check_workspace_admin_permission(db: Session, workspace_id: uuid.UUID, user
def create_workspace_invite( def create_workspace_invite(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
invite_data: WorkspaceInviteCreate, invite_data: WorkspaceInviteCreate,
user: User user: User
) -> WorkspaceInviteResponse: ) -> WorkspaceInviteResponse:
"""创建工作空间邀请""" """创建工作空间邀请"""
business_logger.info(f"创建工作空间邀请: workspace_id={workspace_id}, email={invite_data.email}, 创建者: {user.username}") business_logger.info(
f"创建工作空间邀请: workspace_id={workspace_id}, email={invite_data.email}, 创建者: {user.username}")
try: try:
# 检查权限 # 检查权限
@@ -534,17 +538,18 @@ def create_workspace_invite(
except Exception as e: except Exception as e:
db.rollback() db.rollback()
business_logger.error(f"创建工作空间邀请失败: workspace_id={workspace_id}, email={invite_data.email} - {str(e)}") business_logger.error(
f"创建工作空间邀请失败: workspace_id={workspace_id}, email={invite_data.email} - {str(e)}")
raise raise
def get_workspace_invites( def get_workspace_invites(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
user: User, user: User,
status: Optional[InviteStatus] = None, status: Optional[InviteStatus] = None,
limit: int = 50, limit: int = 50,
offset: int = 0 offset: int = 0
) -> List[WorkspaceInviteResponse]: ) -> List[WorkspaceInviteResponse]:
"""获取工作空间邀请列表""" """获取工作空间邀请列表"""
business_logger.info(f"获取工作空间邀请列表: workspace_id={workspace_id}, 操作者: {user.username}") business_logger.info(f"获取工作空间邀请列表: workspace_id={workspace_id}, 操作者: {user.username}")
@@ -605,9 +610,9 @@ def validate_invite_token(db: Session, token: str) -> InviteValidateResponse:
def accept_workspace_invite( def accept_workspace_invite(
db: Session, db: Session,
accept_request: InviteAcceptRequest, accept_request: InviteAcceptRequest,
user: User user: User
) -> dict: ) -> dict:
"""接受工作空间邀请""" """接受工作空间邀请"""
business_logger.info(f"接受工作空间邀请: 用户 {user.username}") business_logger.info(f"接受工作空间邀请: 用户 {user.username}")
@@ -695,7 +700,8 @@ def accept_workspace_invite(
# 获取工作空间信息 # 获取工作空间信息
workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=invite.workspace_id) workspace = workspace_repository.get_workspace_by_id(db=db, workspace_id=invite.workspace_id)
business_logger.info(f"用户成功加入工作空间: user={user.username}, workspace={workspace.name}, role={workspace_role}") business_logger.info(
f"用户成功加入工作空间: user={user.username}, workspace={workspace.name}, role={workspace_role}")
return { return {
"message": "Successfully joined the workspace", "message": "Successfully joined the workspace",
@@ -710,13 +716,14 @@ def accept_workspace_invite(
def revoke_workspace_invite( def revoke_workspace_invite(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
invite_id: uuid.UUID, invite_id: uuid.UUID,
user: User user: User
) -> dict: ) -> dict:
"""撤销工作空间邀请""" """撤销工作空间邀请"""
business_logger.info(f"撤销工作空间邀请: workspace_id={workspace_id}, invite_id={invite_id}, 操作者: {user.username}") business_logger.info(
f"撤销工作空间邀请: workspace_id={workspace_id}, invite_id={invite_id}, 操作者: {user.username}")
try: try:
# 检查权限 # 检查权限
@@ -745,13 +752,14 @@ def revoke_workspace_invite(
def update_workspace_member_roles( def update_workspace_member_roles(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
updates: List[WorkspaceMemberUpdate], updates: List[WorkspaceMemberUpdate],
user: User, user: User,
) -> List[WorkspaceMember]: ) -> List[WorkspaceMember]:
"""更新工作空间成员角色""" """更新工作空间成员角色"""
business_logger.info(f"更新工作空间成员角色: workspace_id={workspace_id}, 操作者: {user.username}, 更新数量: {len(updates)}") business_logger.info(
f"更新工作空间成员角色: workspace_id={workspace_id}, 操作者: {user.username}, 更新数量: {len(updates)}")
# 检查管理员权限 # 检查管理员权限
_check_workspace_admin_permission(db, workspace_id, user) _check_workspace_admin_permission(db, workspace_id, user)
@@ -765,7 +773,8 @@ def update_workspace_member_roles(
for upd in updates: for upd in updates:
# 检查成员是否存在 # 检查成员是否存在
if upd.id not in member_map: if upd.id not in member_map:
raise BusinessException(f"成员 {upd.id} 不存在于工作空间 {workspace_id}", BizCode.WORKSPACE_MEMBER_NOT_FOUND) raise BusinessException(f"成员 {upd.id} 不存在于工作空间 {workspace_id}",
BizCode.WORKSPACE_MEMBER_NOT_FOUND)
member = member_map[upd.id] member = member_map[upd.id]
@@ -917,10 +926,10 @@ def get_workspace_models_configs(
def update_workspace_models_configs( def update_workspace_models_configs(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
models_update: WorkspaceModelsUpdate, models_update: WorkspaceModelsUpdate,
user: User, user: User,
) -> Workspace: ) -> Workspace:
"""更新工作空间的模型配置llm, embedding, rerank """更新工作空间的模型配置llm, embedding, rerank
@@ -968,8 +977,8 @@ def update_workspace_models_configs(
def _fill_workspace_configs_model_defaults( def _fill_workspace_configs_model_defaults(
db: Session, db: Session,
workspace: Workspace workspace: Workspace
) -> None: ) -> None:
"""Fill empty model fields for all memory configs in a workspace. """Fill empty model fields for all memory configs in a workspace.
@@ -996,7 +1005,7 @@ def _fill_workspace_configs_model_defaults(
("embedding_id", "embedding"), ("embedding_id", "embedding"),
("rerank_id", "rerank"), ("rerank_id", "rerank"),
("reflection_model_id", "llm"), # reflection uses LLM ("reflection_model_id", "llm"), # reflection uses LLM
("emotion_model_id", "llm"), # emotion uses LLM ("emotion_model_id", "llm"), # emotion uses LLM
] ]
configs_updated = 0 configs_updated = 0
@@ -1032,14 +1041,14 @@ def _fill_workspace_configs_model_defaults(
def _create_default_memory_config( def _create_default_memory_config(
db: Session, db: Session,
workspace_id: uuid.UUID, workspace_id: uuid.UUID,
workspace_name: str, workspace_name: str,
llm_id: Optional[uuid.UUID] = None, llm_id: Optional[uuid.UUID] = None,
embedding_id: Optional[uuid.UUID] = None, embedding_id: Optional[uuid.UUID] = None,
rerank_id: Optional[uuid.UUID] = None, rerank_id: Optional[uuid.UUID] = None,
scene_id: Optional[uuid.UUID] = None, scene_id: Optional[uuid.UUID] = None,
pruning_scene_name: Optional[str] = None, pruning_scene_name: Optional[str] = None,
) -> None: ) -> None:
"""Create a default memory config for a newly created workspace. """Create a default memory config for a newly created workspace.
@@ -1084,6 +1093,7 @@ def _create_default_memory_config(
} }
) )
# ==================== 检查配置相关服务 ==================== # ==================== 检查配置相关服务 ====================
def _ensure_default_memory_config(db: Session, workspace: Workspace) -> None: def _ensure_default_memory_config(db: Session, workspace: Workspace) -> None:
@@ -1209,4 +1219,3 @@ def _ensure_default_ontology_scenes(db: Session, workspace: Workspace) -> None:
business_logger.error( business_logger.error(
f"为工作空间 {workspace.id} 补建默认本体场景异常: {str(e)}" f"为工作空间 {workspace.id} 补建默认本体场景异常: {str(e)}"
) )