From fff55e65eaf1cfa4037e83a2614b7b4f6fa97da0 Mon Sep 17 00:00:00 2001 From: fatelei Date: Tue, 28 Jul 2026 14:41:47 +0800 Subject: [PATCH] fix: fix model not change --- api/services/skill_management_service.py | 59 ++++++++++++--- .../services/test_skill_management_service.py | 72 +++++++++++++++++++ 2 files changed, 120 insertions(+), 11 deletions(-) diff --git a/api/services/skill_management_service.py b/api/services/skill_management_service.py index 5c3c0d1a675..f2a57b88afe 100644 --- a/api/services/skill_management_service.py +++ b/api/services/skill_management_service.py @@ -12,6 +12,7 @@ from __future__ import annotations import hashlib import io +import logging import mimetypes import posixpath import re @@ -45,6 +46,9 @@ from models.agent import ( AgentConfigRevisionOperation, AgentConfigSnapshot, AgentKind, + AgentRuntimeSession, + AgentRuntimeSessionOwnerType, + AgentRuntimeSessionStatus, AgentScope, AgentSource, AgentStatus, @@ -76,6 +80,8 @@ from models.tools import ToolFile from services.agent.agent_soul_state import agent_soul_has_model from services.agent.roster_service import AgentRosterService +logger = logging.getLogger(__name__) + _SKILL_MD = "SKILL.md" _MAX_FILE_BYTES = 512 * 1024 _MAX_SKILL_BYTES = 5 * 1024 * 1024 @@ -766,18 +772,27 @@ class SkillManagementService: assistant: Agent, model_config: AgentSoulModelConfig, ) -> None: - if not assistant.active_config_snapshot_id: - return + model_changed = False + cleaned_runtime_session_count = 0 + if assistant.active_config_snapshot_id: + snapshot = session.get(AgentConfigSnapshot, assistant.active_config_snapshot_id) + if snapshot is not None: + config = AgentSoulConfig.model_validate(snapshot.config_snapshot_dict) + model_changed = config.model != model_config + if config.model != model_config: + config.model = model_config + snapshot.config_snapshot = config + assistant.active_config_has_model = agent_soul_has_model(config) + else: + logger.warning( + "skill_assistant_active_snapshot_missing assistant_id=%s active_snapshot_id=%s", + assistant.id, + assistant.active_config_snapshot_id, + ) + else: + logger.warning("skill_assistant_active_snapshot_unset assistant_id=%s", assistant.id) + assistant.active_config_has_model = True - snapshot = session.get(AgentConfigSnapshot, assistant.active_config_snapshot_id) - if snapshot is None: - return - - config = AgentSoulConfig.model_validate(snapshot.config_snapshot_dict) - if config.model != model_config: - config.model = model_config - snapshot.config_snapshot = config - assistant.active_config_has_model = agent_soul_has_model(config) for draft in session.scalars( select(AgentConfigDraft).where( AgentConfigDraft.tenant_id == assistant.tenant_id, @@ -785,8 +800,30 @@ class SkillManagementService: ) ): draft_config = AgentSoulConfig.model_validate(draft.config_snapshot_dict) + if draft_config.model != model_config: + model_changed = True draft_config.model = model_config draft.config_snapshot = draft_config + if model_changed: + for runtime_session in session.scalars( + select(AgentRuntimeSession).where( + AgentRuntimeSession.owner_type == AgentRuntimeSessionOwnerType.CONVERSATION, + AgentRuntimeSession.tenant_id == assistant.tenant_id, + AgentRuntimeSession.app_id == assistant.backing_app_id, + AgentRuntimeSession.agent_id == assistant.id, + AgentRuntimeSession.status == AgentRuntimeSessionStatus.ACTIVE, + ) + ): + runtime_session.status = AgentRuntimeSessionStatus.CLEANED + runtime_session.cleaned_at = naive_utc_now() + cleaned_runtime_session_count += 1 + logger.info( + "skill_assistant_model_synced assistant_id=%s provider=%s model=%s cleaned_runtime_sessions=%s", + assistant.id, + model_config.model_provider, + model_config.model, + cleaned_runtime_session_count, + ) def update_metadata( self, diff --git a/api/tests/unit_tests/services/test_skill_management_service.py b/api/tests/unit_tests/services/test_skill_management_service.py index 221de5125a4..5a47a7e3a87 100644 --- a/api/tests/unit_tests/services/test_skill_management_service.py +++ b/api/tests/unit_tests/services/test_skill_management_service.py @@ -21,6 +21,9 @@ from models.agent import ( AgentConfigRevision, AgentConfigSnapshot, AgentKind, + AgentRuntimeSession, + AgentRuntimeSessionOwnerType, + AgentRuntimeSessionStatus, AgentScope, AgentSource, AgentStatus, @@ -91,6 +94,7 @@ def _tables() -> Generator[None, None, None]: AgentConfigSnapshot, AgentConfigDraft, AgentConfigRevision, + AgentRuntimeSession, ToolFile, Tag, TagBinding, @@ -323,6 +327,7 @@ def test_sync_assistant_model_config_updates_debugger_draft() -> None: scope=AgentScope.WORKFLOW_ONLY, source=AgentSource.WORKFLOW, status=AgentStatus.ACTIVE, + backing_app_id=str(uuid4()), created_by=USER, updated_by=USER, ) @@ -350,6 +355,17 @@ def test_sync_assistant_model_config_updates_debugger_draft() -> None: updated_by=USER, ) session.add(draft) + runtime_session = AgentRuntimeSession( + tenant_id=TENANT, + app_id=agent.backing_app_id, + owner_type=AgentRuntimeSessionOwnerType.CONVERSATION, + agent_id=agent.id, + agent_config_snapshot_id=draft.id, + conversation_id=str(uuid4()), + session_snapshot="{}", + status=AgentRuntimeSessionStatus.ACTIVE, + ) + session.add(runtime_session) session.flush() SkillManagementService._sync_assistant_model_config( @@ -363,6 +379,62 @@ def test_sync_assistant_model_config_updates_debugger_draft() -> None: assert updated_draft.model is not None assert updated_draft.model.model_provider == "langgenius/tongyi/tongyi" assert updated_draft.model.model == "qwen3.7-plus" + assert runtime_session.status == AgentRuntimeSessionStatus.CLEANED + + +def test_sync_assistant_model_config_updates_draft_without_active_snapshot() -> None: + openai_model = AgentSoulModelConfig( + plugin_id="langgenius/openai", + model_provider="langgenius/openai/openai", + model="gpt-4o-mini", + model_settings=AgentSoulModelSettings(temperature=0.2), + ) + tongyi_model = AgentSoulModelConfig( + plugin_id="langgenius/tongyi", + model_provider="langgenius/tongyi/tongyi", + model="qwen3.7-plus", + model_settings=AgentSoulModelSettings(temperature=0.2), + ) + + with session_factory.create_session() as session: + agent = Agent( + tenant_id=TENANT, + name="Skill Authoring Assistant", + role="__skill_authoring_assistant__", + agent_kind=AgentKind.DIFY_AGENT, + scope=AgentScope.WORKFLOW_ONLY, + source=AgentSource.WORKFLOW, + status=AgentStatus.ACTIVE, + backing_app_id=str(uuid4()), + created_by=USER, + updated_by=USER, + ) + session.add(agent) + session.flush() + draft = AgentConfigDraft( + tenant_id=TENANT, + agent_id=agent.id, + draft_type=AgentConfigDraftType.DRAFT, + account_id=None, + draft_owner_key="", + config_snapshot=AgentSoulConfig(model=openai_model), + created_by=USER, + updated_by=USER, + ) + session.add(draft) + session.flush() + + SkillManagementService._sync_assistant_model_config( + session, + assistant=agent, + model_config=tongyi_model, + ) + session.flush() + + updated_draft = AgentSoulConfig.model_validate(draft.config_snapshot_dict) + assert updated_draft.model is not None + assert updated_draft.model.model_provider == "langgenius/tongyi/tongyi" + assert agent.active_config_has_model is True def test_update_display_name_auto_syncs_name_for_unpublished_placeholder() -> None: