From 5c4028d55769169a8512beeb76fb24c49cf2a39e Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Sat, 24 Jan 2026 11:25:51 +0900 Subject: [PATCH] refactor: port AppModelConfig (#30919) Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- api/models/model.py | 72 ++++++++++--------- api/services/app_dsl_service.py | 8 +-- api/services/app_service.py | 7 +- api/services/message_service.py | 3 +- .../services/test_agent_service.py | 6 +- .../services/test_app_dsl_service.py | 39 +++++----- .../services/test_workflow_service.py | 68 +++++++++--------- 7 files changed, 104 insertions(+), 99 deletions(-) diff --git a/api/models/model.py b/api/models/model.py index 2eda085c37..be0cfd58a7 100644 --- a/api/models/model.py +++ b/api/models/model.py @@ -315,40 +315,48 @@ class App(Base): return None -class AppModelConfig(Base): +class AppModelConfig(TypeBase): __tablename__ = "app_model_configs" __table_args__ = (sa.PrimaryKeyConstraint("id", name="app_model_config_pkey"), sa.Index("app_app_id_idx", "app_id")) - id = mapped_column(StringUUID, default=lambda: str(uuid4())) - app_id = mapped_column(StringUUID, nullable=False) - provider = mapped_column(String(255), nullable=True) - model_id = mapped_column(String(255), nullable=True) - configs = mapped_column(sa.JSON, nullable=True) - created_by = mapped_column(StringUUID, nullable=True) - created_at = mapped_column(sa.DateTime, nullable=False, server_default=func.current_timestamp()) - updated_by = mapped_column(StringUUID, nullable=True) - updated_at = mapped_column( - sa.DateTime, nullable=False, server_default=func.current_timestamp(), onupdate=func.current_timestamp() + id: Mapped[str] = mapped_column(StringUUID, default=lambda: str(uuid4()), init=False) + app_id: Mapped[str] = mapped_column(StringUUID, nullable=False) + provider: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None) + model_id: Mapped[str | None] = mapped_column(String(255), nullable=True, default=None) + configs: Mapped[Any | None] = mapped_column(sa.JSON, nullable=True, default=None) + created_by: Mapped[str | None] = mapped_column(StringUUID, nullable=True, default=None) + created_at: Mapped[datetime] = mapped_column( + sa.DateTime, nullable=False, server_default=func.current_timestamp(), init=False ) - opening_statement = mapped_column(LongText) - suggested_questions = mapped_column(LongText) - suggested_questions_after_answer = mapped_column(LongText) - speech_to_text = mapped_column(LongText) - text_to_speech = mapped_column(LongText) - more_like_this = mapped_column(LongText) - model = mapped_column(LongText) - user_input_form = mapped_column(LongText) - dataset_query_variable = mapped_column(String(255)) - pre_prompt = mapped_column(LongText) - agent_mode = mapped_column(LongText) - sensitive_word_avoidance = mapped_column(LongText) - retriever_resource = mapped_column(LongText) - prompt_type = mapped_column(String(255), nullable=False, server_default=sa.text("'simple'")) - chat_prompt_config = mapped_column(LongText) - completion_prompt_config = mapped_column(LongText) - dataset_configs = mapped_column(LongText) - external_data_tools = mapped_column(LongText) - file_upload = mapped_column(LongText) + updated_by: Mapped[str | None] = mapped_column(StringUUID, nullable=True, default=None) + updated_at: Mapped[datetime] = mapped_column( + sa.DateTime, + nullable=False, + server_default=func.current_timestamp(), + onupdate=func.current_timestamp(), + init=False, + ) + opening_statement: Mapped[str | None] = mapped_column(LongText, default=None) + suggested_questions: Mapped[str | None] = mapped_column(LongText, default=None) + suggested_questions_after_answer: Mapped[str | None] = mapped_column(LongText, default=None) + speech_to_text: Mapped[str | None] = mapped_column(LongText, default=None) + text_to_speech: Mapped[str | None] = mapped_column(LongText, default=None) + more_like_this: Mapped[str | None] = mapped_column(LongText, default=None) + model: Mapped[str | None] = mapped_column(LongText, default=None) + user_input_form: Mapped[str | None] = mapped_column(LongText, default=None) + dataset_query_variable: Mapped[str | None] = mapped_column(String(255), default=None) + pre_prompt: Mapped[str | None] = mapped_column(LongText, default=None) + agent_mode: Mapped[str | None] = mapped_column(LongText, default=None) + sensitive_word_avoidance: Mapped[str | None] = mapped_column(LongText, default=None) + retriever_resource: Mapped[str | None] = mapped_column(LongText, default=None) + prompt_type: Mapped[str] = mapped_column( + String(255), nullable=False, server_default=sa.text("'simple'"), default="simple" + ) + chat_prompt_config: Mapped[str | None] = mapped_column(LongText, default=None) + completion_prompt_config: Mapped[str | None] = mapped_column(LongText, default=None) + dataset_configs: Mapped[str | None] = mapped_column(LongText, default=None) + external_data_tools: Mapped[str | None] = mapped_column(LongText, default=None) + file_upload: Mapped[str | None] = mapped_column(LongText, default=None) @property def app(self) -> App | None: @@ -810,8 +818,8 @@ class Conversation(Base): override_model_configs = json.loads(self.override_model_configs) if "model" in override_model_configs: - app_model_config = AppModelConfig() - app_model_config = app_model_config.from_model_config_dict(override_model_configs) + # where is app_id? + app_model_config = AppModelConfig(app_id=self.app_id).from_model_config_dict(override_model_configs) model_config = app_model_config.to_dict() else: model_config["configs"] = override_model_configs diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py index acd2a25a86..da22464d39 100644 --- a/api/services/app_dsl_service.py +++ b/api/services/app_dsl_service.py @@ -521,12 +521,10 @@ class AppDslService: raise ValueError("Missing model_config for chat/agent-chat/completion app") # Initialize or update model config if not app.app_model_config: - app_model_config = AppModelConfig().from_model_config_dict(model_config) + app_model_config = AppModelConfig( + app_id=app.id, created_by=account.id, updated_by=account.id + ).from_model_config_dict(model_config) app_model_config.id = str(uuid4()) - app_model_config.app_id = app.id - app_model_config.created_by = account.id - app_model_config.updated_by = account.id - app.app_model_config_id = app_model_config.id self._session.add(app_model_config) diff --git a/api/services/app_service.py b/api/services/app_service.py index 02ebfbace0..af458ff618 100644 --- a/api/services/app_service.py +++ b/api/services/app_service.py @@ -150,10 +150,9 @@ class AppService: db.session.flush() if default_model_config: - app_model_config = AppModelConfig(**default_model_config) - app_model_config.app_id = app.id - app_model_config.created_by = account.id - app_model_config.updated_by = account.id + app_model_config = AppModelConfig( + **default_model_config, app_id=app.id, created_by=account.id, updated_by=account.id + ) db.session.add(app_model_config) db.session.flush() diff --git a/api/services/message_service.py b/api/services/message_service.py index e1a256e64d..a53ca8b22d 100644 --- a/api/services/message_service.py +++ b/api/services/message_service.py @@ -261,10 +261,9 @@ class MessageService: else: conversation_override_model_configs = json.loads(conversation.override_model_configs) app_model_config = AppModelConfig( - id=conversation.app_model_config_id, app_id=app_model.id, ) - + app_model_config.id = conversation.app_model_config_id app_model_config = app_model_config.from_model_config_dict(conversation_override_model_configs) if not app_model_config: raise ValueError("did not find app model config") diff --git a/api/tests/test_containers_integration_tests/services/test_agent_service.py b/api/tests/test_containers_integration_tests/services/test_agent_service.py index a22d6f8fbf..6eedbd6cfa 100644 --- a/api/tests/test_containers_integration_tests/services/test_agent_service.py +++ b/api/tests/test_containers_integration_tests/services/test_agent_service.py @@ -172,7 +172,6 @@ class TestAgentService: # Create app model config app_model_config = AppModelConfig( - id=fake.uuid4(), app_id=app.id, provider="openai", model_id="gpt-3.5-turbo", @@ -180,6 +179,7 @@ class TestAgentService: model="gpt-3.5-turbo", agent_mode=json.dumps({"enabled": True, "strategy": "react", "tools": []}), ) + app_model_config.id = fake.uuid4() db.session.add(app_model_config) db.session.commit() @@ -413,7 +413,6 @@ class TestAgentService: # Create app model config app_model_config = AppModelConfig( - id=fake.uuid4(), app_id=app.id, provider="openai", model_id="gpt-3.5-turbo", @@ -421,6 +420,7 @@ class TestAgentService: model="gpt-3.5-turbo", agent_mode=json.dumps({"enabled": True, "strategy": "react", "tools": []}), ) + app_model_config.id = fake.uuid4() db.session.add(app_model_config) db.session.commit() @@ -485,7 +485,6 @@ class TestAgentService: # Create app model config app_model_config = AppModelConfig( - id=fake.uuid4(), app_id=app.id, provider="openai", model_id="gpt-3.5-turbo", @@ -493,6 +492,7 @@ class TestAgentService: model="gpt-3.5-turbo", agent_mode=json.dumps({"enabled": True, "strategy": "react", "tools": []}), ) + app_model_config.id = fake.uuid4() db.session.add(app_model_config) db.session.commit() diff --git a/api/tests/test_containers_integration_tests/services/test_app_dsl_service.py b/api/tests/test_containers_integration_tests/services/test_app_dsl_service.py index 119f92d772..e2a450b90c 100644 --- a/api/tests/test_containers_integration_tests/services/test_app_dsl_service.py +++ b/api/tests/test_containers_integration_tests/services/test_app_dsl_service.py @@ -226,26 +226,27 @@ class TestAppDslService: app, account = self._create_test_app_and_account(db_session_with_containers, mock_external_service_dependencies) # Create model config for the app - model_config = AppModelConfig() - model_config.id = fake.uuid4() - model_config.app_id = app.id - model_config.provider = "openai" - model_config.model_id = "gpt-3.5-turbo" - model_config.model = json.dumps( - { - "provider": "openai", - "name": "gpt-3.5-turbo", - "mode": "chat", - "completion_params": { - "max_tokens": 1000, - "temperature": 0.7, - }, - } + model_config = AppModelConfig( + app_id=app.id, + provider="openai", + model_id="gpt-3.5-turbo", + model=json.dumps( + { + "provider": "openai", + "name": "gpt-3.5-turbo", + "mode": "chat", + "completion_params": { + "max_tokens": 1000, + "temperature": 0.7, + }, + } + ), + pre_prompt="You are a helpful assistant.", + prompt_type="simple", + created_by=account.id, + updated_by=account.id, ) - model_config.pre_prompt = "You are a helpful assistant." - model_config.prompt_type = "simple" - model_config.created_by = account.id - model_config.updated_by = account.id + model_config.id = fake.uuid4() # Set the app_model_config_id to link the config app.app_model_config_id = model_config.id diff --git a/api/tests/test_containers_integration_tests/services/test_workflow_service.py b/api/tests/test_containers_integration_tests/services/test_workflow_service.py index 88c6313f64..cb691d5c3d 100644 --- a/api/tests/test_containers_integration_tests/services/test_workflow_service.py +++ b/api/tests/test_containers_integration_tests/services/test_workflow_service.py @@ -925,24 +925,24 @@ class TestWorkflowService: # Create app model config (required for conversion) from models.model import AppModelConfig - app_model_config = AppModelConfig() - app_model_config.id = fake.uuid4() - app_model_config.app_id = app.id - app_model_config.tenant_id = app.tenant_id - app_model_config.provider = "openai" - app_model_config.model_id = "gpt-3.5-turbo" - # Set the model field directly - this is what model_dict property returns - app_model_config.model = json.dumps( - { - "provider": "openai", - "name": "gpt-3.5-turbo", - "completion_params": {"max_tokens": 1000, "temperature": 0.7}, - } + app_model_config = AppModelConfig( + app_id=app.id, + provider="openai", + model_id="gpt-3.5-turbo", + # Set the model field directly - this is what model_dict property returns + model=json.dumps( + { + "provider": "openai", + "name": "gpt-3.5-turbo", + "completion_params": {"max_tokens": 1000, "temperature": 0.7}, + } + ), + # Set pre_prompt for PromptTemplateConfigManager + pre_prompt="You are a helpful assistant.", + created_by=account.id, + updated_by=account.id, ) - # Set pre_prompt for PromptTemplateConfigManager - app_model_config.pre_prompt = "You are a helpful assistant." - app_model_config.created_by = account.id - app_model_config.updated_by = account.id + app_model_config.id = fake.uuid4() from extensions.ext_database import db @@ -987,24 +987,24 @@ class TestWorkflowService: # Create app model config (required for conversion) from models.model import AppModelConfig - app_model_config = AppModelConfig() - app_model_config.id = fake.uuid4() - app_model_config.app_id = app.id - app_model_config.tenant_id = app.tenant_id - app_model_config.provider = "openai" - app_model_config.model_id = "gpt-3.5-turbo" - # Set the model field directly - this is what model_dict property returns - app_model_config.model = json.dumps( - { - "provider": "openai", - "name": "gpt-3.5-turbo", - "completion_params": {"max_tokens": 1000, "temperature": 0.7}, - } + app_model_config = AppModelConfig( + app_id=app.id, + provider="openai", + model_id="gpt-3.5-turbo", + # Set the model field directly - this is what model_dict property returns + model=json.dumps( + { + "provider": "openai", + "name": "gpt-3.5-turbo", + "completion_params": {"max_tokens": 1000, "temperature": 0.7}, + } + ), + # Set pre_prompt for PromptTemplateConfigManager + pre_prompt="Complete the following text:", + created_by=account.id, + updated_by=account.id, ) - # Set pre_prompt for PromptTemplateConfigManager - app_model_config.pre_prompt = "Complete the following text:" - app_model_config.created_by = account.id - app_model_config.updated_by = account.id + app_model_config.id = fake.uuid4() from extensions.ext_database import db