From fd05c000f6524f3658cb4046ee9f412eda710b05 Mon Sep 17 00:00:00 2001 From: wxy Date: Fri, 10 Apr 2026 11:04:59 +0800 Subject: [PATCH 1/5] feat(api): Support specifying app version for chat --- .../controllers/service/app_api_controller.py | 26 +++++++++++++++++++ api/app/schemas/app_schema.py | 1 + 2 files changed, 27 insertions(+) diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index 93caa200..f52c9338 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -86,10 +86,36 @@ async def chat( app_service: Annotated[AppService, Depends(get_app_service)] = None, message: str = Body(..., description="聊天消息内容"), ): + """ + Agent/Workflow 聊天接口 + + - 不传 version:使用当前发布版本(current_release) + - 传 version=N:使用指定版本号的历史快照,例如 /v1/app/chat?version=2 + """ body = await request.json() payload = AppChatRequest(**body) app = app_service.get_app(api_key_auth.resource_id, api_key_auth.workspace_id) + + # 版本切换:指定 version 时查找对应历史快照 + if payload.version is not None: + from sqlalchemy import select as _select + from app.models.app_release_model import AppRelease as _AppRelease + release = db.scalars( + _select(_AppRelease).where( + _AppRelease.app_id == app.id, + _AppRelease.version == payload.version, + _AppRelease.is_active.is_(True), + ) + ).first() + if not release: + raise BusinessException( + f"版本 {payload.version} 不存在或已下线", + BizCode.AGENT_CONFIG_MISSING, + ) + # 临时替换 current_release,后续逻辑无需改动 + app.current_release = release + app.current_release_id = release.id other_id = payload.user_id workspace_id = api_key_auth.workspace_id end_user_repo = EndUserRepository(db) diff --git a/api/app/schemas/app_schema.py b/api/app/schemas/app_schema.py index 85cff671..130bff91 100644 --- a/api/app/schemas/app_schema.py +++ b/api/app/schemas/app_schema.py @@ -616,6 +616,7 @@ class AppChatRequest(BaseModel): stream: bool = Field(default=False, description="是否流式返回") thinking: bool = Field(default=False, description="是否启用深度思考(需Agent配置支持)") files: List[FileInput] = Field(default_factory=list, description="附件列表(支持多文件)") + version: Optional[int] = Field(default=None, description="指定发布版本号,不传则使用当前发布版本") class DraftRunRequest(BaseModel): From 90e8e9052861c58dd9e2b5906c08076c64eda559 Mon Sep 17 00:00:00 2001 From: wxy Date: Fri, 10 Apr 2026 11:11:39 +0800 Subject: [PATCH 2/5] feat(api): Support specifying app version for chat --- api/app/controllers/service/app_api_controller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index f52c9338..75c8798d 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -89,8 +89,8 @@ async def chat( """ Agent/Workflow 聊天接口 - - 不传 version:使用当前发布版本(current_release) - - 传 version=N:使用指定版本号的历史快照,例如 /v1/app/chat?version=2 + - 不传 version:使用当前生效版本(current_release,回滚后为回滚目标版本) + - 传 version=N:使用指定版本号的历史快照,例如 {"version": 2} """ body = await request.json() payload = AppChatRequest(**body) From 412183c3590507efc22c142f859b25385bf2fe49 Mon Sep 17 00:00:00 2001 From: wxy Date: Fri, 10 Apr 2026 11:44:50 +0800 Subject: [PATCH 3/5] feat(api): Support specifying app version for chat --- api/app/controllers/service/app_api_controller.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index 75c8798d..3130a888 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -111,7 +111,7 @@ async def chat( if not release: raise BusinessException( f"版本 {payload.version} 不存在或已下线", - BizCode.AGENT_CONFIG_MISSING, + BizCode.RELEASE_NOT_FOUND, ) # 临时替换 current_release,后续逻辑无需改动 app.current_release = release @@ -328,6 +328,4 @@ async def chat( msg="工作流任务执行成功" ) else: - from app.core.exceptions import BusinessException - from app.core.error_codes import BizCode raise BusinessException(f"不支持的应用类型: {app_type}", BizCode.APP_TYPE_NOT_SUPPORTED) From c253968aa8b516d1b904ad326082d0d995c63fd3 Mon Sep 17 00:00:00 2001 From: wxy Date: Fri, 10 Apr 2026 12:10:24 +0800 Subject: [PATCH 4/5] feat(api): Support specifying app version for chat --- .../controllers/service/app_api_controller.py | 52 ++++++------------- api/app/repositories/app_repository.py | 12 +++++ api/app/services/app_service.py | 22 ++++++++ 3 files changed, 50 insertions(+), 36 deletions(-) diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index 3130a888..b7cc6942 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -14,6 +14,7 @@ from app.core.response_utils import success from app.db import get_db from app.models.app_model import App from app.models.app_model import AppType +from app.models.app_release_model import AppRelease from app.repositories import knowledge_repository from app.repositories.end_user_repository import EndUserRepository from app.schemas import AppChatRequest, conversation_schema @@ -61,18 +62,11 @@ async def list_apps(): # return success(data={"received": True}, msg="消息已接收") -def _checkAppConfig(app: App): - if app.type == AppType.AGENT: - if not app.current_release.config: - raise BusinessException("Agent 应用未配置模型", BizCode.AGENT_CONFIG_MISSING) - elif app.type == AppType.MULTI_AGENT: - if not app.current_release.config: - raise BusinessException("Multi-Agent 应用未配置模型", BizCode.AGENT_CONFIG_MISSING) - elif app.type == AppType.WORKFLOW: - if not app.current_release.config: - raise BusinessException("工作流应用未配置模型", BizCode.AGENT_CONFIG_MISSING) - else: - raise BusinessException("不支持的应用类型", BizCode.AGENT_CONFIG_MISSING) +def _checkAppConfig(release: AppRelease): + if not release.config: + raise BusinessException("应用未配置,无法使用", BizCode.AGENT_CONFIG_MISSING) + if release.type not in (AppType.AGENT, AppType.MULTI_AGENT, AppType.WORKFLOW): + raise BusinessException("不支持的应用类型", BizCode.APP_TYPE_NOT_SUPPORTED) @router.post("/chat") @@ -97,25 +91,11 @@ async def chat( app = app_service.get_app(api_key_auth.resource_id, api_key_auth.workspace_id) - # 版本切换:指定 version 时查找对应历史快照 + # 版本切换:指定 version 时查找对应历史快照,否则使用当前激活版本 if payload.version is not None: - from sqlalchemy import select as _select - from app.models.app_release_model import AppRelease as _AppRelease - release = db.scalars( - _select(_AppRelease).where( - _AppRelease.app_id == app.id, - _AppRelease.version == payload.version, - _AppRelease.is_active.is_(True), - ) - ).first() - if not release: - raise BusinessException( - f"版本 {payload.version} 不存在或已下线", - BizCode.RELEASE_NOT_FOUND, - ) - # 临时替换 current_release,后续逻辑无需改动 - app.current_release = release - app.current_release_id = release.id + active_release = app_service.get_release_by_version(app.id, payload.version) + else: + active_release = app.current_release other_id = payload.user_id workspace_id = api_key_auth.workspace_id end_user_repo = EndUserRepository(db) @@ -153,7 +133,7 @@ async def chat( storage_type = 'neo4j' app_type = app.type # check app config - _checkAppConfig(app) + _checkAppConfig(active_release) # 获取或创建会话(提前验证) conversation = conversation_service.create_or_get_conversation( @@ -168,7 +148,7 @@ async def chat( # print("="*50) # print(app.current_release.default_model_config_id) - agent_config = agent_config_4_app_release(app.current_release) + agent_config = agent_config_4_app_release(active_release) # print(agent_config.default_model_config_id) # thinking 开关:仅当 agent 配置了 deep_thinking 且请求 thinking=True 时才启用 @@ -220,7 +200,7 @@ async def chat( return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json")) elif app_type == AppType.MULTI_AGENT: # 多 Agent 流式返回 - config = multi_agent_config_4_app_release(app.current_release) + config = multi_agent_config_4_app_release(active_release) if payload.stream: async def event_generator(): async for event in app_chat_service.multi_agent_chat_stream( @@ -263,7 +243,7 @@ async def chat( return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json")) elif app_type == AppType.WORKFLOW: # 多 Agent 流式返回 - config = workflow_config_4_app_release(app.current_release) + config = workflow_config_4_app_release(active_release) if payload.stream: async def event_generator(): async for event in app_chat_service.workflow_chat_stream( @@ -279,7 +259,7 @@ async def chat( user_rag_memory_id=user_rag_memory_id, app_id=app.id, workspace_id=workspace_id, - release_id=app.current_release.id, + release_id=active_release.id, public=True ): event_type = event.get("event", "message") @@ -314,7 +294,7 @@ async def chat( files=payload.files, app_id=app.id, workspace_id=workspace_id, - release_id=app.current_release.id + release_id=active_release.id ) logger.debug( "工作流试运行返回结果", diff --git a/api/app/repositories/app_repository.py b/api/app/repositories/app_repository.py index 75a91fd6..3eef99f8 100644 --- a/api/app/repositories/app_repository.py +++ b/api/app/repositories/app_repository.py @@ -61,3 +61,15 @@ def get_apps_by_id(db: Session, app_id: uuid.UUID) -> App: """根据工作空间ID查询应用""" repo = AppRepository(db) return repo.get_apps_by_id(app_id) + + +def get_release_by_version(db: Session, app_id: uuid.UUID, version: int): + """根据版本号查询发布快照(仅返回激活状态)""" + from app.models.app_release_model import AppRelease + return db.scalars( + select(AppRelease).where( + AppRelease.app_id == app_id, + AppRelease.version == version, + AppRelease.is_active.is_(True), + ) + ).first() diff --git a/api/app/services/app_service.py b/api/app/services/app_service.py index 5e26a629..b05e9621 100644 --- a/api/app/services/app_service.py +++ b/api/app/services/app_service.py @@ -619,6 +619,28 @@ class AppService: self._validate_app_accessible(app, workspace_id) return app + def get_release_by_version(self, app_id: uuid.UUID, version: int) -> AppRelease: + """按版本号获取发布快照 + + Args: + app_id: 应用ID + version: 版本号(整数,按应用内递增) + + Returns: + AppRelease: 发布快照 + + Raises: + BusinessException: 版本不存在或已下线 + """ + from app.repositories.app_repository import get_release_by_version + release = get_release_by_version(self.db, app_id, version) + if not release: + raise BusinessException( + f"版本 {version} 不存在或已下线", + BizCode.RELEASE_NOT_FOUND, + ) + return release + def create_app( self, *, From 72fe3962cf40e9562c5807786ea1580a967f2cec Mon Sep 17 00:00:00 2001 From: wxy Date: Fri, 10 Apr 2026 12:18:11 +0800 Subject: [PATCH 5/5] feat(api): Support specifying app version for chat --- api/app/controllers/service/app_api_controller.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/api/app/controllers/service/app_api_controller.py b/api/app/controllers/service/app_api_controller.py index b7cc6942..d9539a4d 100644 --- a/api/app/controllers/service/app_api_controller.py +++ b/api/app/controllers/service/app_api_controller.py @@ -63,9 +63,16 @@ async def list_apps(): def _checkAppConfig(release: AppRelease): - if not release.config: - raise BusinessException("应用未配置,无法使用", BizCode.AGENT_CONFIG_MISSING) - if release.type not in (AppType.AGENT, AppType.MULTI_AGENT, AppType.WORKFLOW): + if release.type == AppType.AGENT: + if not release.config: + raise BusinessException("Agent 应用未配置模型", BizCode.AGENT_CONFIG_MISSING) + elif release.type == AppType.MULTI_AGENT: + if not release.config: + raise BusinessException("Multi-Agent 应用未配置模型", BizCode.AGENT_CONFIG_MISSING) + elif release.type == AppType.WORKFLOW: + if not release.config: + raise BusinessException("工作流应用未配置模型", BizCode.AGENT_CONFIG_MISSING) + else: raise BusinessException("不支持的应用类型", BizCode.APP_TYPE_NOT_SUPPORTED)