fix(agent): return conflict for duplicate agent names (#37686)

This commit is contained in:
zyssyz123 2026-06-20 20:25:08 +08:00 committed by GitHub
parent 517b27c2b4
commit b3e724dce1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 2 deletions

View File

@ -8,6 +8,7 @@ import sqlalchemy as sa
from flask_sqlalchemy.pagination import Pagination
from pydantic import BaseModel, Field
from sqlalchemy import ColumnElement, select
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session, scoped_session
from configs import dify_config
@ -27,6 +28,7 @@ from models import Account, AppStar
from models.agent import Agent, AgentIconType, AgentScope, AgentSource, AgentStatus
from models.model import App, AppMode, AppModelConfig, IconType, Site
from models.tools import ApiToolProvider
from services.agent.errors import AgentNameConflictError
from services.billing_service import BillingService
from services.enterprise import rbac_service as enterprise_rbac_service
from services.enterprise.enterprise_service import EnterpriseService
@ -593,6 +595,16 @@ class AppService:
if updated_at is not None:
agent.updated_at = updated_at
@staticmethod
def _commit_app_identity_update(app: App) -> None:
try:
db.session.commit()
except IntegrityError as exc:
db.session.rollback()
if app.mode == AppMode.AGENT:
raise AgentNameConflictError() from exc
raise
def update_app(self, app: App, args: ArgsDict) -> App:
"""
Update app
@ -629,7 +641,7 @@ class AppService:
account_id=current_user.id,
updated_at=app.updated_at,
)
db.session.commit()
self._commit_app_identity_update(app)
app_was_updated.send(app)
@ -652,7 +664,7 @@ class AppService:
account_id=current_user.id,
updated_at=app.updated_at,
)
db.session.commit()
self._commit_app_identity_update(app)
app_was_updated.send(app)

View File

@ -3,7 +3,11 @@ from __future__ import annotations
from types import SimpleNamespace
from unittest.mock import MagicMock, patch
import pytest
from sqlalchemy.exc import IntegrityError
from models.model import App
from services.agent.errors import AgentNameConflictError
from services.app_service import AppService
@ -317,6 +321,59 @@ class TestAgentAppType:
assert backing_agent.role == ""
def test_update_agent_app_duplicate_name_rolls_back_and_raises_conflict(self):
from models.agent import AgentIconType
from models.model import AppMode, IconType
from services.app_service import AppService
app = SimpleNamespace(
id="app-1",
tenant_id="tenant-1",
mode=AppMode.AGENT,
name="Old",
description="old",
role="draft",
icon_type=IconType.EMOJI,
icon="robot",
icon_background="#fff",
use_icon_as_answer_icon=False,
max_active_requests=None,
created_by="account-1",
)
backing_agent = SimpleNamespace(
name="Old",
description="old",
role="research assistant",
icon_type=AgentIconType.EMOJI,
icon="robot",
icon_background="#fff",
updated_by=None,
updated_at=None,
)
with (
patch("services.app_service.db") as mock_db,
patch("services.app_service.current_user", SimpleNamespace(id="account-2")),
):
mock_db.session.scalar.return_value = backing_agent
mock_db.session.commit.side_effect = IntegrityError("duplicate", None, None)
with pytest.raises(AgentNameConflictError):
AppService().update_app(
app, # type: ignore[arg-type]
{
"name": "Existing Agent",
"description": "agent app",
"role": "research assistant",
"icon_type": "emoji",
"icon": "robot",
"icon_background": "#fff",
"use_icon_as_answer_icon": False,
"max_active_requests": 0,
},
)
mock_db.session.rollback.assert_called_once()
def test_delete_agent_app_archives_backing_agent(self):
from models.agent import AgentStatus
from models.model import AppMode