From ef33df5e22ab8a3cf867628a3cad5bcc5e892da7 Mon Sep 17 00:00:00 2001
From: yyh <92089059+lyzno1@users.noreply.github.com>
Date: Thu, 24 Sep 2026 08:53:49 +0000
Subject: [PATCH] refactor(api): tighten app detail response schema (#42876)
---
api/controllers/console/agent/roster.py | 7 +-
api/controllers/console/app/app.py | 12 +-
api/controllers/console/app/workflow.py | 4 +-
.../manager.py | 26 +-
.../features/text_to_speech/manager.py | 15 +
api/fields/app_fields.py | 168 +--
api/fields/app_model_config_response.py | 388 +++++++
api/models/agent_config_entities.py | 2 +-
api/models/model.py | 24 +-
api/openapi/markdown/console-openapi.md | 647 +++++++++--
api/openapi/markdown/openapi-openapi.md | 4 +-
api/services/app/console_service.py | 5 +-
api/services/app_dsl_service.py | 6 +
api/services/app_service.py | 76 +-
api/services/audio_service.py | 3 +-
api/services/entities/dsl_entities.py | 2 +-
.../app/test_app_detail_config_integrity.py | 86 ++
.../services/test_app_service.py | 49 -
.../commands/test_generate_swagger_specs.py | 8 +
.../console/agent/test_agent_controllers.py | 15 +-
.../console/app/test_app_response_models.py | 178 ++-
.../console/app/test_console_app_api.py | 32 +-
.../explore/test_trial_preview_details.py | 5 +-
.../test_additional_feature_managers.py | 14 +
.../unit_tests/models/test_app_models.py | 12 +
.../test_console_app_repository.py | 20 +-
.../services/app/test_console_service.py | 5 +-
.../services/test_app_dsl_service.py | 46 +
.../unit_tests/services/test_app_service.py | 88 +-
.../generated/api/console/agent/types.gen.ts | 657 ++++++++---
.../generated/api/console/agent/zod.gen.ts | 994 ++++++++++++----
.../generated/api/console/apps/types.gen.ts | 711 +++++++++---
.../generated/api/console/apps/zod.gen.ts | 1011 +++++++++++++----
.../api/console/snippets/types.gen.ts | 2 +-
.../generated/api/console/snippets/zod.gen.ts | 2 +-
.../generated/api/openapi/types.gen.ts | 4 +-
.../generated/api/openapi/zod.gen.ts | 4 +-
.../__tests__/use-app-info-actions.spec.ts | 6 +-
.../app-info/use-app-info-actions.ts | 5 +-
.../settings-modal/__tests__/index.spec.tsx | 9 +-
.../__tests__/use-configuration.spec.tsx | 20 +-
.../switch-app-modal/__tests__/index.spec.tsx | 2 +-
.../app-selector/app-inputs-panel.tsx | 4 +-
.../hooks/use-app-inputs-form-schema.ts | 3 +-
.../__tests__/navigation.spec.tsx | 34 +-
.../__tests__/access-surface-cards.spec.tsx | 98 +-
.../access/components/web-app-access-card.tsx | 33 +-
.../__tests__/publish-bar.browser.spec.tsx | 6 +-
.../__tests__/publish-bar.spec.tsx | 6 +-
web/service/console/client.spec.ts | 35 +-
web/test/fixtures/agent.ts | 2 +
web/test/fixtures/app.ts | 73 ++
52 files changed, 4295 insertions(+), 1373 deletions(-)
create mode 100644 api/fields/app_model_config_response.py
create mode 100644 api/tests/test_containers_integration_tests/controllers/console/app/test_app_detail_config_integrity.py
create mode 100644 web/test/fixtures/app.ts
diff --git a/api/controllers/console/agent/roster.py b/api/controllers/console/agent/roster.py
index 576b9be7987..348abb7568e 100644
--- a/api/controllers/console/agent/roster.py
+++ b/api/controllers/console/agent/roster.py
@@ -274,6 +274,7 @@ class AgentAppPartial(GenericAppPartial):
class AgentAppDetailWithSite(GenericAppDetailWithSite):
permission_keys: list[str]
+ bound_agent_id: str | None = None
app_id: str | None = None
backing_app_id: str | None = None
hidden_app_backed: bool = False
@@ -404,14 +405,14 @@ def _serialize_agent_app_detail(
roster persona fields without widening the shared /apps detail schema.
"""
- app_model = AppService().get_app(app_model, session=session)
+ access_mode = None
if SystemFeatureService.is_webapp_auth_enabled():
app_setting = EnterpriseService.WebAppAuth.get_app_access_mode_by_id(app_id=str(app_model.id))
- app_model.access_mode = app_setting.access_mode # type: ignore[attr-defined]
+ access_mode = app_setting.access_mode
roster_service = _agent_roster_service(session)
payload = GenericAppDetailWithSite.model_validate(
- AppResponseView(app_model, session=session),
+ AppResponseView(app_model, session=session, account=current_user, access_mode=access_mode),
from_attributes=True,
).model_dump(mode="json")
agent = (
diff --git a/api/controllers/console/app/app.py b/api/controllers/console/app/app.py
index 9d624b71ab0..58019cbdda1 100644
--- a/api/controllers/console/app/app.py
+++ b/api/controllers/console/app/app.py
@@ -1,4 +1,5 @@
import uuid
+from dataclasses import asdict
from http import HTTPStatus
from typing import Literal, Self, override
@@ -303,11 +304,12 @@ _ADMIN_ROLES = frozenset({TenantAccountRole.OWNER, TenantAccountRole.ADMIN})
def _app_detail_response(app: AppRecord) -> AppDetailWithSite:
"""Resolve transport URLs here so repositories work without a Flask request."""
- response = AppDetailWithSite.model_validate(app, from_attributes=True)
- response.api_base_url = normalize_api_base_url(dify_config.SERVICE_API_URL or request.host_url.rstrip("/"))
- if response.site is not None:
- response.site.app_base_url = dify_config.APP_WEB_URL or request.url_root.rstrip("/")
- return response
+ data = asdict(app)
+ data["api_base_url"] = normalize_api_base_url(dify_config.SERVICE_API_URL or request.host_url.rstrip("/"))
+ data["app_id"] = None
+ if data["site"] is not None:
+ data["site"]["app_base_url"] = dify_config.APP_WEB_URL or request.url_root.rstrip("/")
+ return AppDetailWithSite.model_validate(data)
class AppResource(Resource):
diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py
index c646589f126..9a2f85ff90a 100644
--- a/api/controllers/console/app/workflow.py
+++ b/api/controllers/console/app/workflow.py
@@ -2,7 +2,7 @@ import json
import logging
from collections.abc import Sequence
from datetime import datetime
-from typing import Any, NotRequired, Self, TypedDict
+from typing import Any, Literal, NotRequired, Self, TypedDict
from flask import abort, request
from flask_restx import Resource
@@ -216,7 +216,7 @@ class WorkflowSuggestedQuestionsAfterAnswerPayload(WorkflowFeatureTogglePayload)
class WorkflowTextToSpeechPayload(WorkflowFeatureTogglePayload):
language: str | None = None
voice: str | None = None
- autoPlay: str | None = None
+ autoPlay: Literal["enabled", "disabled"] | None = None
class WorkflowSensitiveWordAvoidancePayload(WorkflowFeatureTogglePayload):
diff --git a/api/core/app/app_config/features/suggested_questions_after_answer/manager.py b/api/core/app/app_config/features/suggested_questions_after_answer/manager.py
index 0c36992c777..6163b9345e9 100644
--- a/api/core/app/app_config/features/suggested_questions_after_answer/manager.py
+++ b/api/core/app/app_config/features/suggested_questions_after_answer/manager.py
@@ -4,6 +4,23 @@ CUSTOM_FOLLOW_UP_PROMPT_MAX_LENGTH = 1000
class SuggestedQuestionsAfterAnswerConfigManager:
+ @staticmethod
+ def validate_optional_fields(config: dict[str, Any]) -> None:
+ feature = config.get("suggested_questions_after_answer")
+ if feature is None:
+ return
+ if not isinstance(feature, dict):
+ raise ValueError("suggested_questions_after_answer must be of dict type")
+ if "prompt" in feature:
+ prompt = feature["prompt"]
+ if not isinstance(prompt, str):
+ raise ValueError("prompt in suggested_questions_after_answer must be of string type")
+ if len(prompt) > CUSTOM_FOLLOW_UP_PROMPT_MAX_LENGTH:
+ raise ValueError(
+ f"prompt in suggested_questions_after_answer must be less than or equal to "
+ f"{CUSTOM_FOLLOW_UP_PROMPT_MAX_LENGTH} characters"
+ )
+
@classmethod
def convert(cls, config: dict[str, Any]) -> bool:
"""
@@ -45,14 +62,7 @@ class SuggestedQuestionsAfterAnswerConfigManager:
if not isinstance(config["suggested_questions_after_answer"]["enabled"], bool):
raise ValueError("enabled in suggested_questions_after_answer must be of boolean type")
- prompt = config["suggested_questions_after_answer"].get("prompt")
- if prompt is not None and not isinstance(prompt, str):
- raise ValueError("prompt in suggested_questions_after_answer must be of string type")
- if isinstance(prompt, str) and len(prompt) > CUSTOM_FOLLOW_UP_PROMPT_MAX_LENGTH:
- raise ValueError(
- f"prompt in suggested_questions_after_answer must be less than or equal to "
- f"{CUSTOM_FOLLOW_UP_PROMPT_MAX_LENGTH} characters"
- )
+ cls.validate_optional_fields(config)
if "model" in config["suggested_questions_after_answer"]:
model_config = config["suggested_questions_after_answer"]["model"]
diff --git a/api/core/app/app_config/features/text_to_speech/manager.py b/api/core/app/app_config/features/text_to_speech/manager.py
index ca84ec9c3b5..810c0a80c2e 100644
--- a/api/core/app/app_config/features/text_to_speech/manager.py
+++ b/api/core/app/app_config/features/text_to_speech/manager.py
@@ -4,6 +4,19 @@ from core.app.app_config.entities import TextToSpeechEntity
class TextToSpeechConfigManager:
+ @staticmethod
+ def validate_optional_fields(config: dict[str, Any]) -> None:
+ feature = config.get("text_to_speech")
+ if feature is None:
+ return
+ if not isinstance(feature, dict):
+ raise ValueError("text_to_speech must be of dict type")
+ for key in ("voice", "language"):
+ if key in feature and not isinstance(feature[key], str):
+ raise ValueError(f"{key} in text_to_speech must be of string type")
+ if "autoPlay" in feature and feature["autoPlay"] not in ("enabled", "disabled"):
+ raise ValueError("autoPlay in text_to_speech must be enabled or disabled")
+
@classmethod
def convert(cls, config: dict[str, Any]):
"""
@@ -36,6 +49,8 @@ class TextToSpeechConfigManager:
if not isinstance(config["text_to_speech"], dict):
raise ValueError("text_to_speech must be of dict type")
+ cls.validate_optional_fields(config)
+
if "enabled" not in config["text_to_speech"] or not config["text_to_speech"]["enabled"]:
config["text_to_speech"]["enabled"] = False
config["text_to_speech"]["voice"] = ""
diff --git a/api/fields/app_fields.py b/api/fields/app_fields.py
index 9a446971274..92408bac755 100644
--- a/api/fields/app_fields.py
+++ b/api/fields/app_fields.py
@@ -1,13 +1,15 @@
"""Shared Console app response schemas for materialized application results."""
from datetime import datetime
-from typing import Any
from pydantic import AliasChoices, Field, computed_field, field_validator
+from enums import WebAppAccessMode
+from fields.app_model_config_response import AppModelConfigResponse, AppModelSelectionResponse
from fields.base import ResponseModel
from libs.helper import build_icon_url, to_timestamp
-from models.model import IconType
+from models.enums import CustomizeTokenStrategy
+from models.model import AppMode, IconType
from services.entities.app_entities import RecentAppMode
from services.entities.dsl_entities import DslImportWarning, ImportStatus
@@ -37,7 +39,7 @@ class WorkflowPartial(ResponseModel):
class ModelConfigPartial(ResponseModel):
- model: Any | None = Field(default=None, validation_alias=AliasChoices("model_dict", "model"))
+ model: AppModelSelectionResponse | None = Field(default=None, validation_alias=AliasChoices("model_dict", "model"))
pre_prompt: str | None = None
created_by: str | None = None
created_at: int | None = None
@@ -50,90 +52,31 @@ class ModelConfigPartial(ResponseModel):
return to_timestamp(value)
-class AppModelConfigResponse(ResponseModel):
- opening_statement: str | None = None
- suggested_questions: Any | None = Field(
- default=None, validation_alias=AliasChoices("suggested_questions_list", "suggested_questions")
- )
- suggested_questions_after_answer: Any | None = Field(
- default=None,
- validation_alias=AliasChoices("suggested_questions_after_answer_dict", "suggested_questions_after_answer"),
- )
- speech_to_text: Any | None = Field(
- default=None, validation_alias=AliasChoices("speech_to_text_dict", "speech_to_text")
- )
- text_to_speech: Any | None = Field(
- default=None, validation_alias=AliasChoices("text_to_speech_dict", "text_to_speech")
- )
- retriever_resource: Any | None = Field(
- default=None, validation_alias=AliasChoices("retriever_resource_dict", "retriever_resource")
- )
- annotation_reply: Any | None = Field(
- default=None, validation_alias=AliasChoices("annotation_reply_dict", "annotation_reply")
- )
- more_like_this: Any | None = Field(
- default=None, validation_alias=AliasChoices("more_like_this_dict", "more_like_this")
- )
- sensitive_word_avoidance: Any | None = Field(
- default=None, validation_alias=AliasChoices("sensitive_word_avoidance_dict", "sensitive_word_avoidance")
- )
- external_data_tools: Any | None = Field(
- default=None, validation_alias=AliasChoices("external_data_tools_list", "external_data_tools")
- )
- model: Any | None = Field(default=None, validation_alias=AliasChoices("model_dict", "model"))
- user_input_form: Any | None = Field(
- default=None, validation_alias=AliasChoices("user_input_form_list", "user_input_form")
- )
- dataset_query_variable: str | None = None
- pre_prompt: str | None = None
- agent_mode: Any | None = Field(default=None, validation_alias=AliasChoices("agent_mode_dict", "agent_mode"))
- prompt_type: str | None = None
- chat_prompt_config: Any | None = Field(
- default=None, validation_alias=AliasChoices("chat_prompt_config_dict", "chat_prompt_config")
- )
- completion_prompt_config: Any | None = Field(
- default=None, validation_alias=AliasChoices("completion_prompt_config_dict", "completion_prompt_config")
- )
- dataset_configs: Any | None = Field(
- default=None, validation_alias=AliasChoices("dataset_configs_dict", "dataset_configs")
- )
- file_upload: Any | None = Field(default=None, validation_alias=AliasChoices("file_upload_dict", "file_upload"))
- created_by: str | None = None
- created_at: int | None = None
- updated_by: str | None = None
- updated_at: int | None = None
-
- @field_validator("created_at", "updated_at", mode="before")
- @classmethod
- def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
- return to_timestamp(value)
-
-
class AppDetailSiteResponse(ResponseModel):
- access_token: str | None = Field(default=None, validation_alias="code")
- code: str | None = None
- title: str | None = None
- icon_type: str | IconType | None = None
- icon: str | None = None
- icon_background: str | None = None
- description: str | None = None
- default_language: str | None = None
- chat_color_theme: str | None = None
- chat_color_theme_inverted: bool | None = None
- customize_domain: str | None = None
- copyright: str | None = None
- privacy_policy: str | None = None
- input_placeholder: str | None = None
- custom_disclaimer: str | None = None
- customize_token_strategy: str | None = None
- prompt_public: bool | None = None
- app_base_url: str | None = None
- show_workflow_steps: bool | None = None
- use_icon_as_answer_icon: bool | None = None
- created_by: str | None = None
- created_at: int | None = None
- updated_by: str | None = None
- updated_at: int | None = None
+ access_token: str | None = Field(validation_alias="code")
+ code: str | None
+ title: str
+ icon_type: IconType | None
+ icon: str | None
+ icon_background: str | None
+ description: str | None
+ default_language: str
+ chat_color_theme: str | None
+ chat_color_theme_inverted: bool
+ customize_domain: str | None
+ copyright: str | None
+ privacy_policy: str | None
+ input_placeholder: str | None
+ custom_disclaimer: str
+ customize_token_strategy: CustomizeTokenStrategy
+ prompt_public: bool
+ app_base_url: str
+ show_workflow_steps: bool
+ use_icon_as_answer_icon: bool
+ created_by: str | None
+ created_at: int
+ updated_by: str | None
+ updated_at: int
@computed_field(return_type=str | None) # type: ignore
@property
@@ -164,8 +107,8 @@ class AppPartial(ResponseModel):
name: str
max_active_requests: int | None = None
description: str | None = Field(default=None, validation_alias=AliasChoices("desc_or_prompt", "description"))
- mode: str = Field(validation_alias="mode_compatible_with_agent")
- icon_type: str | None = None
+ mode: AppMode = Field(validation_alias="mode_compatible_with_agent")
+ icon_type: IconType | None = None
icon: str | None = None
icon_background: str | None = None
model_config_: ModelConfigPartial | None = Field(
@@ -180,7 +123,7 @@ class AppPartial(ResponseModel):
updated_by: str | None = None
updated_at: int | None = None
tags: list[Tag] = Field(default_factory=list)
- access_mode: str | None = None
+ access_mode: WebAppAccessMode | None = None
create_user_name: str | None = None
author_name: str | None = None
has_draft_trigger: bool | None = None
@@ -233,28 +176,27 @@ class RecentAppListResponse(ResponseModel):
class AppDetail(ResponseModel):
id: str
name: str
- description: str | None = None
- mode: str = Field(validation_alias="mode_compatible_with_agent")
- icon: str | None = None
- icon_background: str | None = None
+ description: str
+ mode: AppMode = Field(validation_alias="mode_compatible_with_agent")
+ icon: str | None
+ icon_background: str | None
enable_site: bool
enable_api: bool
model_config_: AppModelConfigResponse | None = Field(
- default=None,
validation_alias=AliasChoices("app_model_config", "model_config"),
alias="model_config",
)
- workflow: WorkflowPartial | None = None
- tracing: Any | None = None
- use_icon_as_answer_icon: bool | None = None
- created_by: str | None = None
- created_at: int | None = None
- updated_by: str | None = None
- updated_at: int | None = None
- access_mode: str | None = None
- tags: list[Tag] = Field(default_factory=list)
- permission_keys: list[str] = Field(default_factory=list)
- maintainer: str | None = None
+ workflow: WorkflowPartial | None
+ tracing: str | None
+ use_icon_as_answer_icon: bool
+ created_by: str | None
+ created_at: int
+ updated_by: str | None
+ updated_at: int
+ access_mode: WebAppAccessMode | None
+ tags: list[Tag]
+ permission_keys: list[str]
+ maintainer: str | None
@field_validator("created_at", "updated_at", mode="before")
@classmethod
@@ -263,15 +205,15 @@ class AppDetail(ResponseModel):
class AppDetailWithSite(AppDetail):
- icon_type: str | None = None
- api_base_url: str | None = None
- max_active_requests: int | None = None
- deleted_tools: list[DeletedTool] = Field(default_factory=list)
- site: AppDetailSiteResponse | None = None
+ icon_type: IconType | None
+ api_base_url: str
+ max_active_requests: int | None
+ deleted_tools: list[DeletedTool]
+ site: AppDetailSiteResponse | None
# For Agent App type: the roster Agent backing this app (None otherwise).
- bound_agent_id: str | None = None
+ bound_agent_id: str | None
# For Agent App responses exposed through /agent.
- app_id: str | None = None
+ app_id: str | None
@computed_field(return_type=str | None) # type: ignore
@property
@@ -295,7 +237,7 @@ class AppImportResponse(ResponseModel):
id: str
status: ImportStatus
app_id: str | None = None
- app_mode: str | None = None
+ app_mode: AppMode | None = None
current_dsl_version: str
imported_dsl_version: str = ""
error: str = ""
diff --git a/api/fields/app_model_config_response.py b/api/fields/app_model_config_response.py
new file mode 100644
index 00000000000..f8bf05a9dd6
--- /dev/null
+++ b/api/fields/app_model_config_response.py
@@ -0,0 +1,388 @@
+from datetime import datetime
+from typing import Literal, NotRequired, TypedDict
+
+from pydantic import AliasChoices, ConfigDict, Field, JsonValue, field_validator, with_config
+
+from core.entities.agent_entities import PlanningStrategy
+from core.rag.entities.metadata_entities import SupportedComparisonOperator
+from core.rag.rerank.rerank_type import RerankMode
+from core.tools.entities.tool_entities import ToolProviderType
+from fields.base import ResponseModel
+from graphon.file import FileTransferMethod, FileType
+from graphon.model_runtime.entities.llm_entities import LLMMode
+from libs.helper import to_timestamp
+from models.enums import PromptType
+
+
+class AppEnabledConfigResponse(TypedDict):
+ enabled: bool
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppModelSelectionResponse(TypedDict, total=False):
+ provider: str
+ name: str
+ mode: LLMMode | Literal[""]
+ completion_params: dict[str, JsonValue]
+
+
+class AppSuggestedQuestionsAfterAnswerResponse(TypedDict):
+ enabled: bool
+ model: NotRequired[AppModelSelectionResponse]
+ prompt: NotRequired[str]
+
+
+class AppTextToSpeechResponse(TypedDict):
+ enabled: bool
+ voice: NotRequired[str]
+ language: NotRequired[str]
+ autoPlay: NotRequired[Literal["enabled", "disabled"]]
+
+
+class AppEmbeddingModelResponse(TypedDict):
+ embedding_provider_name: str
+ embedding_model_name: str
+
+
+class AppAnnotationReplyDisabledResponse(TypedDict):
+ enabled: Literal[False]
+
+
+class AppAnnotationReplyEnabledResponse(TypedDict):
+ id: str
+ enabled: Literal[True]
+ score_threshold: float
+ embedding_model: AppEmbeddingModelResponse
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppSensitiveWordAvoidanceResponse(TypedDict):
+ enabled: bool
+ type: NotRequired[str]
+ config: NotRequired[dict[str, JsonValue]]
+ configs: NotRequired[list[JsonValue]]
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppEnabledExternalDataToolResponse(TypedDict):
+ enabled: Literal[True]
+ variable: str
+ type: str
+ config: dict[str, JsonValue]
+ label: NotRequired[str]
+ icon: NotRequired[str]
+ icon_background: NotRequired[str]
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppDisabledExternalDataToolResponse(TypedDict):
+ enabled: Literal[False]
+ variable: NotRequired[str]
+ type: NotRequired[str]
+ config: NotRequired[dict[str, JsonValue]]
+ label: NotRequired[str]
+ icon: NotRequired[str]
+ icon_background: NotRequired[str]
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppUserInputFormConfigResponse(TypedDict):
+ variable: str
+ label: str
+ description: NotRequired[str]
+ required: NotRequired[bool]
+ max_length: NotRequired[int | None]
+ options: NotRequired[list[str]]
+ default: NotRequired[JsonValue]
+ type: NotRequired[str]
+ hide: NotRequired[bool]
+ allowed_file_types: NotRequired[list[FileType]]
+ allowed_file_extensions: NotRequired[list[str]]
+ allowed_file_upload_methods: NotRequired[list[FileTransferMethod]]
+ json_schema: NotRequired[str | dict[str, JsonValue] | None]
+ config: NotRequired[dict[str, JsonValue]]
+ enabled: NotRequired[bool]
+ icon: NotRequired[str | None]
+ icon_background: NotRequired[str | None]
+
+
+AppTextInputFormResponse = TypedDict("AppTextInputFormResponse", {"text-input": AppUserInputFormConfigResponse})
+
+
+class AppSelectFormResponse(TypedDict):
+ select: AppUserInputFormConfigResponse
+
+
+class AppParagraphFormResponse(TypedDict):
+ paragraph: AppUserInputFormConfigResponse
+
+
+class AppNumberFormResponse(TypedDict):
+ number: AppUserInputFormConfigResponse
+
+
+class AppCheckboxFormResponse(TypedDict):
+ checkbox: AppUserInputFormConfigResponse
+
+
+class AppFileFormResponse(TypedDict):
+ file: AppUserInputFormConfigResponse
+
+
+AppFileListFormResponse = TypedDict("AppFileListFormResponse", {"file-list": AppUserInputFormConfigResponse})
+
+
+class AppExternalDataToolFormResponse(TypedDict):
+ external_data_tool: AppUserInputFormConfigResponse
+
+
+class AppJsonObjectFormResponse(TypedDict):
+ json_object: AppUserInputFormConfigResponse
+
+
+AppUserInputFormResponse = (
+ AppTextInputFormResponse
+ | AppSelectFormResponse
+ | AppParagraphFormResponse
+ | AppNumberFormResponse
+ | AppCheckboxFormResponse
+ | AppFileFormResponse
+ | AppFileListFormResponse
+ | AppExternalDataToolFormResponse
+ | AppJsonObjectFormResponse
+)
+
+
+class AppDatasetReferenceResponse(TypedDict, total=False):
+ id: str
+ enabled: bool
+
+
+class AppLegacySensitiveWordToolResponse(TypedDict):
+ enabled: bool
+ words: list[str]
+ canned_response: str
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppProviderAgentToolResponse(TypedDict):
+ provider_type: ToolProviderType
+ provider_id: str
+ tool_name: str
+ tool_parameters: dict[str, JsonValue]
+ provider_name: NotRequired[str]
+ tool_label: NotRequired[str]
+ plugin_unique_identifier: NotRequired[str | None]
+ credential_id: NotRequired[str | None]
+ enabled: NotRequired[bool]
+ isDeleted: NotRequired[bool]
+ notAuthor: NotRequired[bool]
+
+
+class AppLegacyDatasetToolResponse(TypedDict):
+ dataset: AppDatasetReferenceResponse
+
+
+class AppLegacyGoogleSearchToolResponse(TypedDict):
+ google_search: dict[str, JsonValue]
+
+
+class AppLegacyWebReaderToolResponse(TypedDict):
+ web_reader: dict[str, JsonValue]
+
+
+class AppLegacyWikipediaToolResponse(TypedDict):
+ wikipedia: dict[str, JsonValue]
+
+
+class AppLegacyCurrentDatetimeToolResponse(TypedDict):
+ current_datetime: dict[str, JsonValue]
+
+
+AppLegacySensitiveWordToolResponseItem = TypedDict(
+ "AppLegacySensitiveWordToolResponseItem",
+ {"sensitive-word-avoidance": AppLegacySensitiveWordToolResponse},
+)
+
+
+AppAgentToolResponse = (
+ AppProviderAgentToolResponse
+ | AppLegacyDatasetToolResponse
+ | AppLegacyGoogleSearchToolResponse
+ | AppLegacyWebReaderToolResponse
+ | AppLegacyWikipediaToolResponse
+ | AppLegacyCurrentDatetimeToolResponse
+ | AppLegacySensitiveWordToolResponseItem
+)
+
+
+class AppAgentPromptResponse(TypedDict, total=False):
+ first_prompt: str
+ next_iteration: str
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppAgentModeResponse(TypedDict):
+ enabled: bool
+ strategy: NotRequired[PlanningStrategy | Literal["cot", "function-calling"] | None]
+ tools: NotRequired[list[AppAgentToolResponse]]
+ prompt: NotRequired[AppAgentPromptResponse | str | None]
+ max_iteration: NotRequired[int]
+
+
+class AppChatPromptMessageResponse(TypedDict):
+ text: str
+ role: str
+
+
+class AppChatPromptConfigResponse(TypedDict, total=False):
+ prompt: list[AppChatPromptMessageResponse]
+
+
+class AppCompletionPromptTextResponse(TypedDict):
+ text: str
+
+
+class AppConversationHistoriesRoleResponse(TypedDict):
+ user_prefix: str
+ assistant_prefix: str
+
+
+class AppCompletionPromptConfigResponse(TypedDict, total=False):
+ prompt: AppCompletionPromptTextResponse
+ conversation_histories_role: AppConversationHistoriesRoleResponse
+
+
+class AppDatasetItemResponse(TypedDict):
+ dataset: AppDatasetReferenceResponse
+
+
+class AppDatasetListResponse(TypedDict):
+ datasets: list[AppDatasetItemResponse]
+ strategy: NotRequired[str]
+
+
+class AppRerankingModelResponse(TypedDict, total=False):
+ reranking_provider_name: str
+ reranking_model_name: str
+
+
+class AppVectorSettingResponse(TypedDict):
+ vector_weight: float
+ embedding_provider_name: str
+ embedding_model_name: str
+
+
+class AppKeywordSettingResponse(TypedDict):
+ keyword_weight: float
+
+
+class AppWeightsResponse(TypedDict):
+ vector_setting: AppVectorSettingResponse
+ keyword_setting: AppKeywordSettingResponse
+ weight_type: NotRequired[Literal["semantic_first", "keyword_first", "customized"]]
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppMetadataConditionResponse(TypedDict):
+ id: NotRequired[str]
+ metadata_id: NotRequired[str]
+ name: str
+ comparison_operator: SupportedComparisonOperator
+ value: NotRequired[str | list[str] | int | float | None]
+
+
+class AppMetadataFilteringConditionsResponse(TypedDict, total=False):
+ logical_operator: Literal["and", "or"] | None
+ conditions: list[AppMetadataConditionResponse] | None
+
+
+@with_config(ConfigDict(extra="allow"))
+class AppDatasetConfigsResponse(TypedDict):
+ retrieval_model: Literal["single", "multiple"]
+ datasets: NotRequired[AppDatasetListResponse]
+ top_k: NotRequired[int]
+ score_threshold: NotRequired[float | None]
+ score_threshold_enabled: NotRequired[bool]
+ reranking_model: NotRequired[AppRerankingModelResponse | None]
+ weights: NotRequired[AppWeightsResponse | None]
+ reranking_enabled: NotRequired[bool]
+ reranking_enable: NotRequired[bool]
+ reranking_mode: NotRequired[RerankMode]
+ metadata_filtering_mode: NotRequired[Literal["disabled", "automatic", "manual"]]
+ metadata_model_config: NotRequired[AppModelSelectionResponse | None]
+ metadata_filtering_conditions: NotRequired[AppMetadataFilteringConditionsResponse | None]
+
+
+class AppImageUploadResponse(TypedDict, total=False):
+ enabled: bool
+ number_limits: int
+ detail: Literal["low", "high"] | None
+ transfer_methods: list[FileTransferMethod]
+
+
+class AppFileUploadResponse(TypedDict, total=False):
+ image: AppImageUploadResponse
+ enabled: bool
+ allowed_file_types: list[FileType]
+ allowed_file_extensions: list[str]
+ allowed_file_upload_methods: list[FileTransferMethod]
+ number_limits: int
+
+
+class AppModelConfigResponse(ResponseModel):
+ opening_statement: str | None
+ suggested_questions: list[str] = Field(
+ validation_alias=AliasChoices("suggested_questions_list", "suggested_questions")
+ )
+ suggested_questions_after_answer: AppSuggestedQuestionsAfterAnswerResponse = Field(
+ validation_alias=AliasChoices("suggested_questions_after_answer_dict", "suggested_questions_after_answer"),
+ )
+ speech_to_text: AppEnabledConfigResponse = Field(
+ validation_alias=AliasChoices("speech_to_text_dict", "speech_to_text")
+ )
+ text_to_speech: AppTextToSpeechResponse = Field(
+ validation_alias=AliasChoices("text_to_speech_dict", "text_to_speech")
+ )
+ retriever_resource: AppEnabledConfigResponse = Field(
+ validation_alias=AliasChoices("retriever_resource_dict", "retriever_resource")
+ )
+ annotation_reply: AppAnnotationReplyEnabledResponse | AppAnnotationReplyDisabledResponse = Field(
+ validation_alias=AliasChoices("annotation_reply_dict", "annotation_reply")
+ )
+ more_like_this: AppEnabledConfigResponse = Field(
+ validation_alias=AliasChoices("more_like_this_dict", "more_like_this")
+ )
+ sensitive_word_avoidance: AppSensitiveWordAvoidanceResponse = Field(
+ validation_alias=AliasChoices("sensitive_word_avoidance_dict", "sensitive_word_avoidance")
+ )
+ external_data_tools: list[AppEnabledExternalDataToolResponse | AppDisabledExternalDataToolResponse] = Field(
+ validation_alias=AliasChoices("external_data_tools_list", "external_data_tools")
+ )
+ model: AppModelSelectionResponse = Field(validation_alias=AliasChoices("model_dict", "model"))
+ user_input_form: list[AppUserInputFormResponse] = Field(
+ validation_alias=AliasChoices("user_input_form_list", "user_input_form")
+ )
+ dataset_query_variable: str | None
+ pre_prompt: str | None
+ agent_mode: AppAgentModeResponse = Field(validation_alias=AliasChoices("agent_mode_dict", "agent_mode"))
+ prompt_type: PromptType
+ chat_prompt_config: AppChatPromptConfigResponse = Field(
+ validation_alias=AliasChoices("chat_prompt_config_dict", "chat_prompt_config")
+ )
+ completion_prompt_config: AppCompletionPromptConfigResponse = Field(
+ validation_alias=AliasChoices("completion_prompt_config_dict", "completion_prompt_config")
+ )
+ dataset_configs: AppDatasetConfigsResponse = Field(
+ validation_alias=AliasChoices("dataset_configs_dict", "dataset_configs")
+ )
+ file_upload: AppFileUploadResponse = Field(validation_alias=AliasChoices("file_upload_dict", "file_upload"))
+ created_by: str | None
+ created_at: int
+ updated_by: str | None
+ updated_at: int
+
+ @field_validator("created_at", "updated_at", mode="before")
+ @classmethod
+ def _normalize_timestamp(cls, value: datetime | int | None) -> int | None:
+ return to_timestamp(value)
diff --git a/api/models/agent_config_entities.py b/api/models/agent_config_entities.py
index 02479a3147b..d3900fa3e77 100644
--- a/api/models/agent_config_entities.py
+++ b/api/models/agent_config_entities.py
@@ -546,7 +546,7 @@ class AgentFeatureToggleConfig(AgentFlexibleConfig):
class AgentTextToSpeechFeatureConfig(AgentFeatureToggleConfig):
language: str | None = None
voice: str | None = None
- autoPlay: str | None = None
+ autoPlay: Literal["enabled", "disabled"] | None = None
class AgentSuggestedQuestionsAfterAnswerModelConfig(AgentFlexibleConfig):
diff --git a/api/models/model.py b/api/models/model.py
index 88785ee943e..6148ecab845 100644
--- a/api/models/model.py
+++ b/api/models/model.py
@@ -99,6 +99,13 @@ class EnabledConfig(TypedDict):
enabled: bool
+class TextToSpeechConfig(TypedDict):
+ enabled: bool
+ voice: NotRequired[str]
+ language: NotRequired[str]
+ autoPlay: NotRequired[Literal["enabled", "disabled"]]
+
+
class SuggestedQuestionsAfterAnswerModelConfig(TypedDict):
provider: str
name: str
@@ -148,7 +155,7 @@ class AgentToolConfig(TypedDict):
class AgentModeConfig(TypedDict):
enabled: bool
- strategy: str | None
+ strategy: NotRequired[str | None]
tools: list[AgentToolConfig | dict[str, Any]]
prompt: str | None
@@ -175,6 +182,9 @@ class ExternalDataToolConfig(TypedDict):
variable: str
type: str
config: dict[str, Any]
+ label: NotRequired[str]
+ icon: NotRequired[str]
+ icon_background: NotRequired[str]
class UserInputFormItemConfig(TypedDict):
@@ -187,6 +197,9 @@ class UserInputFormItemConfig(TypedDict):
default: NotRequired[str]
type: NotRequired[str]
config: NotRequired[dict[str, Any]]
+ enabled: NotRequired[bool]
+ icon: NotRequired[str]
+ icon_background: NotRequired[str]
# Each item is a single-key dict, e.g. {"text-input": UserInputFormItemConfig}
@@ -202,6 +215,7 @@ class DatasetConfigs(TypedDict):
reranking_model: NotRequired[dict[str, Any] | None]
weights: NotRequired[dict[str, Any] | None]
reranking_enabled: NotRequired[bool]
+ reranking_enable: NotRequired[bool]
reranking_mode: NotRequired[str]
metadata_filtering_mode: NotRequired[str]
metadata_model_config: NotRequired[dict[str, Any] | None]
@@ -243,7 +257,7 @@ class AppModelConfigDict(TypedDict):
suggested_questions: list[str]
suggested_questions_after_answer: SuggestedQuestionsAfterAnswerConfig
speech_to_text: EnabledConfig
- text_to_speech: EnabledConfig
+ text_to_speech: TextToSpeechConfig
retriever_resource: EnabledConfig
annotation_reply: AnnotationReplyConfig
more_like_this: EnabledConfig
@@ -786,8 +800,8 @@ class AppModelConfig(TypeBase):
return self._get_enabled_config(self.speech_to_text)
@property
- def text_to_speech_dict(self) -> EnabledConfig:
- return self._get_enabled_config(self.text_to_speech)
+ def text_to_speech_dict(self) -> TextToSpeechConfig:
+ return cast(TextToSpeechConfig, self._get_enabled_config(self.text_to_speech))
@property
def retriever_resource_dict(self) -> EnabledConfig:
@@ -843,7 +857,7 @@ class AppModelConfig(TypeBase):
if self.dataset_configs:
dataset_configs = json.loads(self.dataset_configs)
if "retrieval_model" not in dataset_configs:
- return {"retrieval_model": "single"}
+ return {**dataset_configs, "retrieval_model": "single"}
else:
return cast(DatasetConfigs, dataset_configs)
return {
diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md
index 5442befdf80..a082df42a83 100644
--- a/api/openapi/markdown/console-openapi.md
+++ b/api/openapi/markdown/console-openapi.md
@@ -13670,41 +13670,41 @@ Model class for AI model.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| access_mode | string | | No |
+| access_mode | [WebAppAccessMode](#webappaccessmode) | | Yes |
| access_ready | boolean | | No |
-| api_base_url | string | | No |
+| api_base_url | string | | Yes |
| app_id | string | | No |
| backing_app_id | string | | No |
| bound_agent_id | string | | No |
-| created_at | integer | | No |
-| created_by | string | | No |
+| created_at | integer | | Yes |
+| created_by | string | | Yes |
| debug_conversation_has_messages | boolean | | No |
| debug_conversation_id | string | | No |
| debug_conversation_message_count | integer | | No |
-| deleted_tools | [ [DeletedTool](#deletedtool) ] | | No |
-| description | string | | No |
+| deleted_tools | [ [DeletedTool](#deletedtool) ] | | Yes |
+| description | string | | Yes |
| enable_api | boolean | | Yes |
| enable_site | boolean | | Yes |
| hidden_app_backed | boolean | | No |
-| icon | string | | No |
-| icon_background | string | | No |
-| icon_type | string | | No |
+| icon | string | | Yes |
+| icon_background | string | | Yes |
+| icon_type | [IconType](#icontype) | | Yes |
| icon_url | string | | Yes |
| id | string | | Yes |
-| maintainer | string | | No |
-| max_active_requests | integer | | No |
-| mode | string | | Yes |
-| model_config | [AppModelConfigResponse](#appmodelconfigresponse) | | No |
+| maintainer | string | | Yes |
+| max_active_requests | integer | | Yes |
+| mode | [AppMode](#appmode) | | Yes |
+| model_config | [AppModelConfigResponse](#appmodelconfigresponse) | | Yes |
| name | string | | Yes |
| permission_keys | [ string ] | | Yes |
| role | string | | No |
-| site | [AppDetailSiteResponse](#appdetailsiteresponse) | | No |
-| tags | [ [Tag](#tag) ] | | No |
-| tracing | | | No |
-| updated_at | integer | | No |
-| updated_by | string | | No |
-| use_icon_as_answer_icon | boolean | | No |
-| workflow | [WorkflowPartial](#workflowpartial) | | No |
+| site | [AppDetailSiteResponse](#appdetailsiteresponse) | | Yes |
+| tags | [ [Tag](#tag) ] | | Yes |
+| tracing | string | | Yes |
+| updated_at | integer | | Yes |
+| updated_by | string | | Yes |
+| use_icon_as_answer_icon | boolean | | Yes |
+| workflow | [WorkflowPartial](#workflowpartial) | | Yes |
#### AgentAppFeaturesPayload
@@ -13752,7 +13752,7 @@ default (the config form sends the full desired feature state on save).
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| access_mode | string | | No |
+| access_mode | [WebAppAccessMode](#webappaccessmode) | | No |
| active_config_is_published | boolean | | No |
| app_id | string | | No |
| author_name | string | | No |
@@ -13767,13 +13767,13 @@ default (the config form sends the full desired feature state on save).
| hidden_app_backed | boolean | | No |
| icon | string | | No |
| icon_background | string | | No |
-| icon_type | string | | No |
+| icon_type | [IconType](#icontype) | | No |
| icon_url | string | | Yes |
| id | string | | Yes |
| is_starred | boolean | | No |
| maintainer | string | | No |
| max_active_requests | integer | | No |
-| mode | string | | Yes |
+| mode | [AppMode](#appmode) | | Yes |
| model_config | [ModelConfigPartial](#modelconfigpartial) | | No |
| name | string | | Yes |
| permission_keys | [ string ] | | Yes |
@@ -15357,7 +15357,7 @@ Legacy Chat App model config used only for follow-up question generation.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| autoPlay | string | | No |
+| autoPlay | string,
**Available values:** "disabled", "enabled" | | No |
| enabled | boolean | | No |
| language | string | | No |
| voice | string | | No |
@@ -15742,99 +15742,220 @@ This class is used to store the schema information of an api based tool.
| app_id | string | | No |
| items | [ [AccessMatrixItem](#accessmatrixitem) ] | | No |
+#### AppAgentModeResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| enabled | boolean | | Yes |
+| max_iteration | integer | | No |
+| prompt | [AppAgentPromptResponse](#appagentpromptresponse)
string | | No |
+| strategy | [PlanningStrategy](#planningstrategy)
string,
**Available values:** "cot", "function-calling" | | No |
+| tools | [ [AppProviderAgentToolResponse](#appprovideragenttoolresponse)
[AppLegacyDatasetToolResponse](#applegacydatasettoolresponse)
[AppLegacyGoogleSearchToolResponse](#applegacygooglesearchtoolresponse)
[AppLegacyWebReaderToolResponse](#applegacywebreadertoolresponse)
[AppLegacyWikipediaToolResponse](#applegacywikipediatoolresponse)
[AppLegacyCurrentDatetimeToolResponse](#applegacycurrentdatetimetoolresponse)
[AppLegacySensitiveWordToolResponseItem](#applegacysensitivewordtoolresponseitem) ] | | No |
+
+#### AppAgentPromptResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| first_prompt | string | | No |
+| next_iteration | string | | No |
+
+#### AppAnnotationReplyDisabledResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| enabled | boolean | | Yes |
+
+#### AppAnnotationReplyEnabledResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| embedding_model | [AppEmbeddingModelResponse](#appembeddingmodelresponse) | | Yes |
+| enabled | boolean | | Yes |
+| id | string | | Yes |
+| score_threshold | number | | Yes |
+
#### AppApiStatusPayload
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| enable_api | boolean | Enable or disable API | Yes |
+#### AppChatPromptConfigResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| prompt | [ [AppChatPromptMessageResponse](#appchatpromptmessageresponse) ] | | No |
+
+#### AppChatPromptMessageResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| role | string | | Yes |
+| text | string | | Yes |
+
+#### AppCheckboxFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| checkbox | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
+#### AppCompletionPromptConfigResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| conversation_histories_role | [AppConversationHistoriesRoleResponse](#appconversationhistoriesroleresponse) | | No |
+| prompt | [AppCompletionPromptTextResponse](#appcompletionprompttextresponse) | | No |
+
+#### AppCompletionPromptTextResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| text | string | | Yes |
+
+#### AppConversationHistoriesRoleResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| assistant_prefix | string | | Yes |
+| user_prefix | string | | Yes |
+
+#### AppDatasetConfigsResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| datasets | [AppDatasetListResponse](#appdatasetlistresponse) | | No |
+| metadata_filtering_conditions | [AppMetadataFilteringConditionsResponse](#appmetadatafilteringconditionsresponse) | | No |
+| metadata_filtering_mode | string,
**Available values:** "automatic", "disabled", "manual" | *Enum:* `"automatic"`, `"disabled"`, `"manual"` | No |
+| metadata_model_config | [AppModelSelectionResponse](#appmodelselectionresponse) | | No |
+| reranking_enable | boolean | | No |
+| reranking_enabled | boolean | | No |
+| reranking_mode | [RerankMode](#rerankmode) | | No |
+| reranking_model | [AppRerankingModelResponse](#apprerankingmodelresponse) | | No |
+| retrieval_model | string,
**Available values:** "multiple", "single" | *Enum:* `"multiple"`, `"single"` | Yes |
+| score_threshold | number | | No |
+| score_threshold_enabled | boolean | | No |
+| top_k | integer | | No |
+| weights | [AppWeightsResponse](#appweightsresponse) | | No |
+
+#### AppDatasetItemResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| dataset | [AppDatasetReferenceResponse](#appdatasetreferenceresponse) | | Yes |
+
+#### AppDatasetListResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| datasets | [ [AppDatasetItemResponse](#appdatasetitemresponse) ] | | Yes |
+| strategy | string | | No |
+
+#### AppDatasetReferenceResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| enabled | boolean | | No |
+| id | string | | No |
+
#### AppDetail
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| access_mode | string | | No |
-| created_at | integer | | No |
-| created_by | string | | No |
-| description | string | | No |
+| access_mode | [WebAppAccessMode](#webappaccessmode) | | Yes |
+| created_at | integer | | Yes |
+| created_by | string | | Yes |
+| description | string | | Yes |
| enable_api | boolean | | Yes |
| enable_site | boolean | | Yes |
-| icon | string | | No |
-| icon_background | string | | No |
+| icon | string | | Yes |
+| icon_background | string | | Yes |
| id | string | | Yes |
-| maintainer | string | | No |
-| mode | string | | Yes |
-| model_config | [AppModelConfigResponse](#appmodelconfigresponse) | | No |
+| maintainer | string | | Yes |
+| mode | [AppMode](#appmode) | | Yes |
+| model_config | [AppModelConfigResponse](#appmodelconfigresponse) | | Yes |
| name | string | | Yes |
-| permission_keys | [ string ] | | No |
-| tags | [ [Tag](#tag) ] | | No |
-| tracing | | | No |
-| updated_at | integer | | No |
-| updated_by | string | | No |
-| use_icon_as_answer_icon | boolean | | No |
-| workflow | [WorkflowPartial](#workflowpartial) | | No |
+| permission_keys | [ string ] | | Yes |
+| tags | [ [Tag](#tag) ] | | Yes |
+| tracing | string | | Yes |
+| updated_at | integer | | Yes |
+| updated_by | string | | Yes |
+| use_icon_as_answer_icon | boolean | | Yes |
+| workflow | [WorkflowPartial](#workflowpartial) | | Yes |
#### AppDetailSiteResponse
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| access_token | string | | No |
-| app_base_url | string | | No |
-| chat_color_theme | string | | No |
-| chat_color_theme_inverted | boolean | | No |
-| code | string | | No |
-| copyright | string | | No |
-| created_at | integer | | No |
-| created_by | string | | No |
-| custom_disclaimer | string | | No |
-| customize_domain | string | | No |
-| customize_token_strategy | string | | No |
-| default_language | string | | No |
-| description | string | | No |
-| icon | string | | No |
-| icon_background | string | | No |
-| icon_type | string
[IconType](#icontype) | | No |
+| access_token | string | | Yes |
+| app_base_url | string | | Yes |
+| chat_color_theme | string | | Yes |
+| chat_color_theme_inverted | boolean | | Yes |
+| code | string | | Yes |
+| copyright | string | | Yes |
+| created_at | integer | | Yes |
+| created_by | string | | Yes |
+| custom_disclaimer | string | | Yes |
+| customize_domain | string | | Yes |
+| customize_token_strategy | [CustomizeTokenStrategy](#customizetokenstrategy) | | Yes |
+| default_language | string | | Yes |
+| description | string | | Yes |
+| icon | string | | Yes |
+| icon_background | string | | Yes |
+| icon_type | [IconType](#icontype) | | Yes |
| icon_url | string | | Yes |
-| input_placeholder | string | | No |
-| privacy_policy | string | | No |
-| prompt_public | boolean | | No |
-| show_workflow_steps | boolean | | No |
-| title | string | | No |
-| updated_at | integer | | No |
-| updated_by | string | | No |
-| use_icon_as_answer_icon | boolean | | No |
+| input_placeholder | string | | Yes |
+| privacy_policy | string | | Yes |
+| prompt_public | boolean | | Yes |
+| show_workflow_steps | boolean | | Yes |
+| title | string | | Yes |
+| updated_at | integer | | Yes |
+| updated_by | string | | Yes |
+| use_icon_as_answer_icon | boolean | | Yes |
#### AppDetailWithSite
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| access_mode | string | | No |
-| api_base_url | string | | No |
-| app_id | string | | No |
-| bound_agent_id | string | | No |
-| created_at | integer | | No |
-| created_by | string | | No |
-| deleted_tools | [ [DeletedTool](#deletedtool) ] | | No |
-| description | string | | No |
+| access_mode | [WebAppAccessMode](#webappaccessmode) | | Yes |
+| api_base_url | string | | Yes |
+| app_id | string | | Yes |
+| bound_agent_id | string | | Yes |
+| created_at | integer | | Yes |
+| created_by | string | | Yes |
+| deleted_tools | [ [DeletedTool](#deletedtool) ] | | Yes |
+| description | string | | Yes |
| enable_api | boolean | | Yes |
| enable_site | boolean | | Yes |
-| icon | string | | No |
-| icon_background | string | | No |
-| icon_type | string | | No |
+| icon | string | | Yes |
+| icon_background | string | | Yes |
+| icon_type | [IconType](#icontype) | | Yes |
| icon_url | string | | Yes |
| id | string | | Yes |
-| maintainer | string | | No |
-| max_active_requests | integer | | No |
-| mode | string | | Yes |
-| model_config | [AppModelConfigResponse](#appmodelconfigresponse) | | No |
+| maintainer | string | | Yes |
+| max_active_requests | integer | | Yes |
+| mode | [AppMode](#appmode) | | Yes |
+| model_config | [AppModelConfigResponse](#appmodelconfigresponse) | | Yes |
| name | string | | Yes |
-| permission_keys | [ string ] | | No |
-| site | [AppDetailSiteResponse](#appdetailsiteresponse) | | No |
-| tags | [ [Tag](#tag) ] | | No |
-| tracing | | | No |
-| updated_at | integer | | No |
-| updated_by | string | | No |
-| use_icon_as_answer_icon | boolean | | No |
-| workflow | [WorkflowPartial](#workflowpartial) | | No |
+| permission_keys | [ string ] | | Yes |
+| site | [AppDetailSiteResponse](#appdetailsiteresponse) | | Yes |
+| tags | [ [Tag](#tag) ] | | Yes |
+| tracing | string | | Yes |
+| updated_at | integer | | Yes |
+| updated_by | string | | Yes |
+| use_icon_as_answer_icon | boolean | | Yes |
+| workflow | [WorkflowPartial](#workflowpartial) | | Yes |
+
+#### AppDisabledExternalDataToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| config | object | | No |
+| enabled | boolean | | Yes |
+| icon | string | | No |
+| icon_background | string | | No |
+| label | string | | No |
+| type | string | | No |
+| variable | string | | No |
#### AppDslVersionResponse
@@ -15842,6 +15963,31 @@ This class is used to store the schema information of an api based tool.
| ---- | ---- | ----------- | -------- |
| app_dsl_version | string | | Yes |
+#### AppEmbeddingModelResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| embedding_model_name | string | | Yes |
+| embedding_provider_name | string | | Yes |
+
+#### AppEnabledConfigResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| enabled | boolean | | Yes |
+
+#### AppEnabledExternalDataToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| config | object | | Yes |
+| enabled | boolean | | Yes |
+| icon | string | | No |
+| icon_background | string | | No |
+| label | string | | No |
+| type | string | | Yes |
+| variable | string | | Yes |
+
#### AppExportQuery
| Name | Type | Description | Required |
@@ -15857,6 +16003,35 @@ This class is used to store the schema information of an api based tool.
| ---- | ---- | ----------- | -------- |
| data | string | | Yes |
+#### AppExternalDataToolFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| external_data_tool | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
+#### AppFileFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| file | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
+#### AppFileListFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| file-list | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
+#### AppFileUploadResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| allowed_file_extensions | [ string ] | | No |
+| allowed_file_types | [ [FileType](#filetype) ] | | No |
+| allowed_file_upload_methods | [ [FileTransferMethod](#filetransfermethod) ] | | No |
+| enabled | boolean | | No |
+| image | [AppImageUploadResponse](#appimageuploadresponse) | | No |
+| number_limits | integer | | No |
+
#### AppIconPayload
| Name | Type | Description | Required |
@@ -15865,6 +16040,15 @@ This class is used to store the schema information of an api based tool.
| icon_background | string | Icon background color | No |
| icon_type | [IconType](#icontype) | Icon type | No |
+#### AppImageUploadResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| detail | string,
**Available values:** "high", "low" | | No |
+| enabled | boolean | | No |
+| number_limits | integer | | No |
+| transfer_methods | [ [FileTransferMethod](#filetransfermethod) ] | | No |
+
#### AppImportPayload
| Name | Type | Description | Required |
@@ -15884,7 +16068,7 @@ This class is used to store the schema information of an api based tool.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| app_id | string | | No |
-| app_mode | string | | No |
+| app_mode | [AppMode](#appmode) | | No |
| current_dsl_version | string | | Yes |
| error | string | | No |
| id | string | | Yes |
@@ -15892,6 +16076,62 @@ This class is used to store the schema information of an api based tool.
| status | [ImportStatus](#importstatus) | | Yes |
| warnings | [ [DslImportWarning](#dslimportwarning) ] | | No |
+#### AppJsonObjectFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| json_object | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
+#### AppKeywordSettingResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| keyword_weight | number | | Yes |
+
+#### AppLegacyCurrentDatetimeToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| current_datetime | object | | Yes |
+
+#### AppLegacyDatasetToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| dataset | [AppDatasetReferenceResponse](#appdatasetreferenceresponse) | | Yes |
+
+#### AppLegacyGoogleSearchToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| google_search | object | | Yes |
+
+#### AppLegacySensitiveWordToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| canned_response | string | | Yes |
+| enabled | boolean | | Yes |
+| words | [ string ] | | Yes |
+
+#### AppLegacySensitiveWordToolResponseItem
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| sensitive-word-avoidance | [AppLegacySensitiveWordToolResponse](#applegacysensitivewordtoolresponse) | | Yes |
+
+#### AppLegacyWebReaderToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| web_reader | object | | Yes |
+
+#### AppLegacyWikipediaToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| wikipedia | object | | Yes |
+
#### AppListQuery
| Name | Type | Description | Required |
@@ -15926,6 +16166,23 @@ AppMCPServer Status Enum
| ---- | ---- | ----------- | -------- |
| AppMCPServerStatus | string | AppMCPServer Status Enum | |
+#### AppMetadataConditionResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| comparison_operator | string,
**Available values:** "<", "=", ">", "after", "before", "contains", "empty", "end with", "in", "is", "is not", "not contains", "not empty", "not in", "start with", "≠", "≤", "≥" | *Enum:* `"<"`, `"="`, `">"`, `"after"`, `"before"`, `"contains"`, `"empty"`, `"end with"`, `"in"`, `"is"`, `"is not"`, `"not contains"`, `"not empty"`, `"not in"`, `"start with"`, `"≠"`, `"≤"`, `"≥"` | Yes |
+| id | string | | No |
+| metadata_id | string | | No |
+| name | string | | Yes |
+| value | string
[ string ]
integer
number | | No |
+
+#### AppMetadataFilteringConditionsResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| conditions | [ [AppMetadataConditionResponse](#appmetadataconditionresponse) ] | | No |
+| logical_operator | string,
**Available values:** "and", "or" | | No |
+
#### AppMode
| Name | Type | Description | Required |
@@ -15936,30 +16193,39 @@ AppMCPServer Status Enum
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| agent_mode | | | No |
-| annotation_reply | | | No |
-| chat_prompt_config | | | No |
-| completion_prompt_config | | | No |
-| created_at | integer | | No |
-| created_by | string | | No |
-| dataset_configs | | | No |
-| dataset_query_variable | string | | No |
-| external_data_tools | | | No |
-| file_upload | | | No |
-| model | | | No |
-| more_like_this | | | No |
-| opening_statement | string | | No |
-| pre_prompt | string | | No |
-| prompt_type | string | | No |
-| retriever_resource | | | No |
-| sensitive_word_avoidance | | | No |
-| speech_to_text | | | No |
-| suggested_questions | | | No |
-| suggested_questions_after_answer | | | No |
-| text_to_speech | | | No |
-| updated_at | integer | | No |
-| updated_by | string | | No |
-| user_input_form | | | No |
+| agent_mode | [AppAgentModeResponse](#appagentmoderesponse) | | Yes |
+| annotation_reply | [AppAnnotationReplyEnabledResponse](#appannotationreplyenabledresponse)
[AppAnnotationReplyDisabledResponse](#appannotationreplydisabledresponse) | | Yes |
+| chat_prompt_config | [AppChatPromptConfigResponse](#appchatpromptconfigresponse) | | Yes |
+| completion_prompt_config | [AppCompletionPromptConfigResponse](#appcompletionpromptconfigresponse) | | Yes |
+| created_at | integer | | Yes |
+| created_by | string | | Yes |
+| dataset_configs | [AppDatasetConfigsResponse](#appdatasetconfigsresponse) | | Yes |
+| dataset_query_variable | string | | Yes |
+| external_data_tools | [ [AppEnabledExternalDataToolResponse](#appenabledexternaldatatoolresponse)
[AppDisabledExternalDataToolResponse](#appdisabledexternaldatatoolresponse) ] | | Yes |
+| file_upload | [AppFileUploadResponse](#appfileuploadresponse) | | Yes |
+| model | [AppModelSelectionResponse](#appmodelselectionresponse) | | Yes |
+| more_like_this | [AppEnabledConfigResponse](#appenabledconfigresponse) | | Yes |
+| opening_statement | string | | Yes |
+| pre_prompt | string | | Yes |
+| prompt_type | [PromptType](#prompttype) | | Yes |
+| retriever_resource | [AppEnabledConfigResponse](#appenabledconfigresponse) | | Yes |
+| sensitive_word_avoidance | [AppSensitiveWordAvoidanceResponse](#appsensitivewordavoidanceresponse) | | Yes |
+| speech_to_text | [AppEnabledConfigResponse](#appenabledconfigresponse) | | Yes |
+| suggested_questions | [ string ] | | Yes |
+| suggested_questions_after_answer | [AppSuggestedQuestionsAfterAnswerResponse](#appsuggestedquestionsafteranswerresponse) | | Yes |
+| text_to_speech | [AppTextToSpeechResponse](#apptexttospeechresponse) | | Yes |
+| updated_at | integer | | Yes |
+| updated_by | string | | Yes |
+| user_input_form | [ [AppTextInputFormResponse](#apptextinputformresponse)
[AppSelectFormResponse](#appselectformresponse)
[AppParagraphFormResponse](#appparagraphformresponse)
[AppNumberFormResponse](#appnumberformresponse)
[AppCheckboxFormResponse](#appcheckboxformresponse)
[AppFileFormResponse](#appfileformresponse)
[AppFileListFormResponse](#appfilelistformresponse)
[AppExternalDataToolFormResponse](#appexternaldatatoolformresponse)
[AppJsonObjectFormResponse](#appjsonobjectformresponse) ] | | Yes |
+
+#### AppModelSelectionResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| completion_params | object | | No |
+| mode | [LLMMode](#llmmode)
string | | No |
+| name | string | | No |
+| provider | string | | No |
#### AppNamePayload
@@ -15967,6 +16233,12 @@ AppMCPServer Status Enum
| ---- | ---- | ----------- | -------- |
| name | string | Name to check | Yes |
+#### AppNumberFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| number | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
#### AppPagination
| Name | Type | Description | Required |
@@ -15977,11 +16249,17 @@ AppMCPServer Status Enum
| page | integer | | Yes |
| total | integer | | Yes |
+#### AppParagraphFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| paragraph | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
#### AppPartial
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| access_mode | string | | No |
+| access_mode | [WebAppAccessMode](#webappaccessmode) | | No |
| app_id | string | | No |
| author_name | string | | No |
| bound_agent_id | string | | No |
@@ -15992,13 +16270,13 @@ AppMCPServer Status Enum
| has_draft_trigger | boolean | | No |
| icon | string | | No |
| icon_background | string | | No |
-| icon_type | string | | No |
+| icon_type | [IconType](#icontype) | | No |
| icon_url | string | | Yes |
| id | string | | Yes |
| is_starred | boolean | | No |
| maintainer | string | | No |
| max_active_requests | integer | | No |
-| mode | string | | Yes |
+| mode | [AppMode](#appmode) | | Yes |
| model_config | [ModelConfigPartial](#modelconfigpartial) | | No |
| name | string | | Yes |
| permission_keys | [ string ] | | No |
@@ -16008,12 +16286,50 @@ AppMCPServer Status Enum
| use_icon_as_answer_icon | boolean | | No |
| workflow | [WorkflowPartial](#workflowpartial) | | No |
+#### AppProviderAgentToolResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| credential_id | string | | No |
+| enabled | boolean | | No |
+| isDeleted | boolean | | No |
+| notAuthor | boolean | | No |
+| plugin_unique_identifier | string | | No |
+| provider_id | string | | Yes |
+| provider_name | string | | No |
+| provider_type | [ToolProviderType](#toolprovidertype) | | Yes |
+| tool_label | string | | No |
+| tool_name | string | | Yes |
+| tool_parameters | object | | Yes |
+
+#### AppRerankingModelResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| reranking_model_name | string | | No |
+| reranking_provider_name | string | | No |
+
+#### AppSelectFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| select | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
#### AppSelectorScope
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| AppSelectorScope | string | | |
+#### AppSensitiveWordAvoidanceResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| config | object | | No |
+| configs | [ [JsonValue](#jsonvalue) ] | | No |
+| enabled | boolean | | Yes |
+| type | string | | No |
+
#### AppSiteResponse
| Name | Type | Description | Required |
@@ -16063,6 +16379,29 @@ AppMCPServer Status Enum
| title | string | | No |
| use_icon_as_answer_icon | boolean | | No |
+#### AppSuggestedQuestionsAfterAnswerResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| enabled | boolean | | Yes |
+| model | [AppModelSelectionResponse](#appmodelselectionresponse) | | No |
+| prompt | string | | No |
+
+#### AppTextInputFormResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| text-input | [AppUserInputFormConfigResponse](#appuserinputformconfigresponse) | | Yes |
+
+#### AppTextToSpeechResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| autoPlay | string,
**Available values:** "disabled", "enabled" | *Enum:* `"disabled"`, `"enabled"` | No |
+| enabled | boolean | | Yes |
+| language | string | | No |
+| voice | string | | No |
+
#### AppTracePayload
| Name | Type | Description | Required |
@@ -16077,6 +16416,28 @@ AppMCPServer Status Enum
| enabled | boolean | | No |
| tracing_provider | string | | No |
+#### AppUserInputFormConfigResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| allowed_file_extensions | [ string ] | | No |
+| allowed_file_types | [ [FileType](#filetype) ] | | No |
+| allowed_file_upload_methods | [ [FileTransferMethod](#filetransfermethod) ] | | No |
+| config | object | | No |
+| default | [JsonValue](#jsonvalue) | | No |
+| description | string | | No |
+| enabled | boolean | | No |
+| hide | boolean | | No |
+| icon | string | | No |
+| icon_background | string | | No |
+| json_schema | string
object | | No |
+| label | string | | Yes |
+| max_length | integer | | No |
+| options | [ string ] | | No |
+| required | boolean | | No |
+| type | string | | No |
+| variable | string | | Yes |
+
#### AppVariableConfig
| Name | Type | Description | Required |
@@ -16086,6 +16447,22 @@ AppMCPServer Status Enum
| required | boolean | | No |
| type | string | | Yes |
+#### AppVectorSettingResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| embedding_model_name | string | | Yes |
+| embedding_provider_name | string | | Yes |
+| vector_weight | number | | Yes |
+
+#### AppWeightsResponse
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| keyword_setting | [AppKeywordSettingResponse](#appkeywordsettingresponse) | | Yes |
+| vector_setting | [AppVectorSettingResponse](#appvectorsettingresponse) | | Yes |
+| weight_type | string,
**Available values:** "customized", "keyword_first", "semantic_first" | *Enum:* `"customized"`, `"keyword_first"`, `"semantic_first"` | No |
+
#### AudioBinaryResponse
| Name | Type | Description | Required |
@@ -16977,6 +17354,14 @@ Model class for provider custom model configuration.
| model_type | [ModelType](#modeltype) | | Yes |
| unadded_to_model_list | boolean | | No |
+#### CustomizeTokenStrategy
+
+Site token customization strategy
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| CustomizeTokenStrategy | string | Site token customization strategy | |
+
#### CustomizedPipelineTemplatePayload
| Name | Type | Description | Required |
@@ -19050,7 +19435,7 @@ How Dify forwards the end-user's identity to an MCP server.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| app_id | string | | No |
-| app_mode | string | | No |
+| app_mode | [AppMode](#appmode) | | No |
| current_dsl_version | string,
**Default:** 0.7.0 | | No |
| error | string | | No |
| id | string | | Yes |
@@ -19707,7 +20092,7 @@ Metadata operation data
| ---- | ---- | ----------- | -------- |
| created_at | integer | | No |
| created_by | string | | No |
-| model | | | No |
+| model | [AppModelSelectionResponse](#appmodelselectionresponse) | | No |
| pre_prompt | string | | No |
| updated_at | integer | | No |
| updated_by | string | | No |
@@ -20755,6 +21140,12 @@ Shared permission levels for resources (datasets, credentials, etc.)
| unit | string | | No |
| variable | string | | Yes |
+#### PlanningStrategy
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| PlanningStrategy | string | | |
+
#### PluginAutoUpgradeChangeResponse
| Name | Type | Description | Required |
@@ -21263,6 +21654,14 @@ Dataset Process Rule Mode
| mode | [ProcessRuleMode](#processrulemode) | | Yes |
| rules | [Rule](#rule) | | No |
+#### PromptType
+
+Prompt configuration type
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| PromptType | string | Prompt configuration type | |
+
#### ProviderConfig
Model class for common provider settings like credentials
@@ -21755,6 +22154,12 @@ Resource types understood by access policies.
| request | object | The request of the request log | Yes |
| response | object | The response of the request log | Yes |
+#### RerankMode
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| RerankMode | string | | |
+
#### RerankingModel
| Name | Type | Description | Required |
@@ -24022,6 +24427,12 @@ in form definition, or a variable while the workflow is running.
| is_valid | boolean | | Yes |
| token | string | | Yes |
+#### WebAppAccessMode
+
+| Name | Type | Description | Required |
+| ---- | ---- | ----------- | -------- |
+| WebAppAccessMode | string | | |
+
#### WebAppAuthModel
| Name | Type | Description | Required |
@@ -25112,7 +25523,7 @@ Query parameters for workflow runs.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
-| autoPlay | string | | No |
+| autoPlay | string,
**Available values:** "disabled", "enabled" | | No |
| enabled | boolean | | No |
| language | string | | No |
| voice | string | | No |
diff --git a/api/openapi/markdown/openapi-openapi.md b/api/openapi/markdown/openapi-openapi.md
index 385be3dc5dc..388e8e2c169 100644
--- a/api/openapi/markdown/openapi-openapi.md
+++ b/api/openapi/markdown/openapi-openapi.md
@@ -694,7 +694,7 @@ Request body for POST /workspaces//apps/imports.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| app_id | string | | No |
-| app_mode | string | | No |
+| app_mode | [AppMode](#appmode) | | No |
| current_dsl_version | string,
**Default:** 0.7.0 | | No |
| error | string | | No |
| hints | [ [Hint](#hint) ] | Next steps the caller can take | No |
@@ -971,7 +971,7 @@ A next step the caller can hand straight to `call --input `.
| Name | Type | Description | Required |
| ---- | ---- | ----------- | -------- |
| app_id | string | | No |
-| app_mode | string | | No |
+| app_mode | [AppMode](#appmode) | | No |
| current_dsl_version | string,
**Default:** 0.7.0 | | No |
| error | string | | No |
| id | string | | Yes |
diff --git a/api/services/app/console_service.py b/api/services/app/console_service.py
index b4929e78f9a..424f70b6bc3 100644
--- a/api/services/app/console_service.py
+++ b/api/services/app/console_service.py
@@ -8,6 +8,7 @@ from typing import BinaryIO, Literal, Protocol
from uuid import UUID, uuid4
from machinery.context import RequestContext
+from models.model import AppMode
from services.agent.errors import InvalidRosterAgentPackageError
from services.agent.roster_package_entities import RosterAgentPackageExport
from services.entities.app_entities import (
@@ -228,7 +229,7 @@ class ConsoleAppService:
id=str(uuid4()),
status=ImportStatus.COMPLETED_WITH_WARNINGS if result.warnings else ImportStatus.COMPLETED,
app_id=result.app_id,
- app_mode="agent",
+ app_mode=AppMode.AGENT,
warnings=result.warnings,
)
@@ -300,7 +301,7 @@ class ConsoleAppService:
def update(self, context: RequestContext, app_id: str, params: UpdateAppParams) -> AppRecord:
app = self._apps.update(context, app_id, params)
self._lifecycle.updated(context, app)
- return self._lifecycle.present(context, app)
+ return self.get(context, app_id)
def rename(self, context: RequestContext, app_id: str, name: str) -> AppRecord:
app = self._apps.rename(context, app_id, name)
diff --git a/api/services/app_dsl_service.py b/api/services/app_dsl_service.py
index 10be610f172..65e2622b3c9 100644
--- a/api/services/app_dsl_service.py
+++ b/api/services/app_dsl_service.py
@@ -17,6 +17,10 @@ from sqlalchemy.orm import Session
from configs import dify_config
from constants.dsl_version import CURRENT_APP_DSL_VERSION
+from core.app.app_config.features.suggested_questions_after_answer.manager import (
+ SuggestedQuestionsAfterAnswerConfigManager,
+)
+from core.app.app_config.features.text_to_speech.manager import TextToSpeechConfigManager
from core.file import remote_fetcher
from core.plugin.entities.plugin import PluginDependency
from core.rbac import RBACPermission, RBACResourceScope
@@ -694,6 +698,8 @@ class AppDslService:
model_config = data.get("model_config")
if not model_config or not isinstance(model_config, dict):
raise ValueError("Missing model_config for chat/agent-chat/completion app")
+ SuggestedQuestionsAfterAnswerConfigManager.validate_optional_fields(model_config)
+ TextToSpeechConfigManager.validate_optional_fields(model_config)
# Initialize or update model config
app_model_config = (
self._session.get(AppModelConfig, app.app_model_config_id) if app.app_model_config_id else None
diff --git a/api/services/app_service.py b/api/services/app_service.py
index 642e188f79a..7510d6b3e95 100644
--- a/api/services/app_service.py
+++ b/api/services/app_service.py
@@ -1,9 +1,10 @@
import json
import logging
from collections.abc import Callable, Mapping, Sequence
+from copy import deepcopy
from dataclasses import dataclass
from datetime import datetime
-from typing import Any, NotRequired, TypedDict, cast, override
+from typing import Any, NotRequired, TypedDict, cast
import sqlalchemy as sa
from pydantic import JsonValue
@@ -120,9 +121,13 @@ class AppModelConfigResponseView:
class AppResponseView:
"""Expose App response properties through one caller-owned database session."""
- def __init__(self, app: App, *, session: Session) -> None:
+ def __init__(
+ self, app: App, *, session: Session, account: Account | None = None, access_mode: str | None = None
+ ) -> None:
self._app = app
self._session = session
+ self._account = account
+ self._access_mode = access_mode
def __getattr__(self, name: str) -> Any:
return getattr(self._app, name) # guard-ignore: no-new-getattr -- delegates model fields
@@ -140,6 +145,19 @@ class AppResponseView:
app_model_config = self._app.app_model_config_with_session(session=self._session)
if app_model_config is None:
return None
+ if self._account is not None and (
+ self._app.mode == AppMode.AGENT_CHAT or self._app.is_agent_with_session(session=self._session)
+ ):
+ tenant_id = self._account.current_tenant_id
+ assert tenant_id is not None
+ masked_agent_mode = mask_agent_tool_parameters(
+ agent_mode=cast(Mapping[str, JsonValue], app_model_config.agent_mode_dict),
+ app_id=self._app.id,
+ tenant_id=tenant_id,
+ user_id=self._account.id,
+ )
+ app_model_config = deepcopy(app_model_config)
+ app_model_config.agent_mode = json.dumps(masked_agent_mode)
return AppModelConfigResponseView(app_model_config, session=self._session)
@property
@@ -154,6 +172,18 @@ class AppResponseView:
def mode_compatible_with_agent(self) -> str:
return self._app.mode_compatible_with_agent_with_session(session=self._session)
+ @property
+ def access_mode(self) -> str | None:
+ return self._access_mode
+
+ @property
+ def permission_keys(self) -> list[str]:
+ return []
+
+ @property
+ def app_id(self) -> str | None:
+ return None
+
@property
def deleted_tools(self) -> list[Any]:
return self._app.deleted_tools_with_session(session=self._session)
@@ -580,48 +610,6 @@ class AppService:
if dify_config.DEPLOYMENT_EDITION == DeploymentEdition.CLOUD:
BillingService.clean_billing_info_cache(app.tenant_id)
- def get_app(self, app: App, *, session: Session) -> App:
- """
- Get App
- """
- assert isinstance(current_user, Account)
- assert current_user.current_tenant_id is not None
- # get original app model config
- if app.mode == AppMode.AGENT_CHAT or app.is_agent_with_session(session=session):
- model_config = app.app_model_config_with_session(session=session)
- if not model_config:
- return app
- agent_mode = mask_agent_tool_parameters(
- agent_mode=cast(Mapping[str, JsonValue], model_config.agent_mode_dict),
- app_id=app.id,
- tenant_id=current_user.current_tenant_id,
- user_id=current_user.id,
- )
-
- # override agent mode
- if model_config:
- model_config.agent_mode = json.dumps(agent_mode)
-
- class ModifiedApp(App):
- """
- Modified App class
- """
-
- def __init__(self, app):
- self.__dict__.update(app.__dict__)
-
- @override
- def app_model_config_with_session(self, *, session: Session) -> AppModelConfig | None:
- # Hand back the in-memory config the masking pass above produced, and
- # deliberately ignore `session`: re-reading the row here would undo the
- # masking. Response paths resolve the config through this accessor
- # (`AppResponseView.app_model_config`), so the override has to sit here.
- return model_config
-
- app = ModifiedApp(app)
-
- return app
-
class ArgsDict(TypedDict):
name: str
description: str
diff --git a/api/services/audio_service.py b/api/services/audio_service.py
index bf33746296c..07fd904ccde 100644
--- a/api/services/audio_service.py
+++ b/api/services/audio_service.py
@@ -10,7 +10,6 @@ import logging
import uuid
from collections.abc import Iterable
from dataclasses import dataclass
-from typing import cast
from flask import Response, stream_with_context
from sqlalchemy import select
@@ -269,7 +268,7 @@ class AudioService:
if not text_to_speech_dict.get("enabled"):
raise ValueError("TTS is not enabled")
- voice = cast(str | None, text_to_speech_dict.get("voice"))
+ voice = text_to_speech_dict.get("voice")
return PreparedTextToAudio(text=text, voice=voice)
diff --git a/api/services/entities/dsl_entities.py b/api/services/entities/dsl_entities.py
index cf596114078..67272f1120a 100644
--- a/api/services/entities/dsl_entities.py
+++ b/api/services/entities/dsl_entities.py
@@ -82,7 +82,7 @@ class Import(BaseModel):
id: str
status: ImportStatus
app_id: str | None = None
- app_mode: str | None = None
+ app_mode: AppMode | None = None
permission_keys: list[str] = Field(default_factory=list)
current_dsl_version: str = CURRENT_APP_DSL_VERSION
imported_dsl_version: str = ""
diff --git a/api/tests/test_containers_integration_tests/controllers/console/app/test_app_detail_config_integrity.py b/api/tests/test_containers_integration_tests/controllers/console/app/test_app_detail_config_integrity.py
new file mode 100644
index 00000000000..7ce218bba19
--- /dev/null
+++ b/api/tests/test_containers_integration_tests/controllers/console/app/test_app_detail_config_integrity.py
@@ -0,0 +1,86 @@
+"""App detail responses must not write masked configuration back to storage."""
+
+import json
+
+from flask.testing import FlaskClient
+from sqlalchemy.orm import Session
+
+from models.model import AppMode, AppModelConfig
+from tests.test_containers_integration_tests.controllers.console.helpers import (
+ authenticate_console_client,
+ create_console_account_and_tenant,
+ create_console_app,
+)
+
+
+def test_put_app_detail_preserves_agent_tool_secret_after_commit(
+ db_session_with_containers: Session,
+ test_client_with_containers: FlaskClient,
+) -> None:
+ account, tenant = create_console_account_and_tenant(db_session_with_containers)
+ app = create_console_app(db_session_with_containers, tenant.id, account.id, AppMode.AGENT_CHAT)
+ agent_mode = {
+ "enabled": True,
+ "strategy": "react",
+ "tools": [
+ {
+ "provider_type": "api",
+ "provider_id": "00000000-0000-0000-0000-000000000001",
+ "tool_name": "private_tool",
+ "tool_parameters": {"api_key": "encrypted-secret"},
+ }
+ ],
+ }
+ config = AppModelConfig(app_id=app.id, agent_mode=json.dumps(agent_mode))
+ db_session_with_containers.add(config)
+ db_session_with_containers.flush()
+ app.app_model_config_id = config.id
+ db_session_with_containers.commit()
+
+ headers = authenticate_console_client(test_client_with_containers, account)
+ response = test_client_with_containers.put(
+ f"/console/api/apps/{app.id}",
+ headers=headers,
+ json={"name": "Updated App"},
+ )
+
+ assert response.status_code == 200
+ assert response.json is not None
+ assert response.json["model_config"]["agent_mode"]["tools"][0]["tool_parameters"] != {"api_key": "encrypted-secret"}
+ with Session(db_session_with_containers.get_bind()) as reread_session:
+ persisted = reread_session.get(AppModelConfig, config.id)
+ assert persisted is not None
+ assert persisted.agent_mode is not None
+ assert json.loads(persisted.agent_mode) == agent_mode
+
+
+def test_get_and_put_app_detail_preserve_historical_agent_mode_without_tools(
+ db_session_with_containers: Session,
+ test_client_with_containers: FlaskClient,
+) -> None:
+ account, tenant = create_console_account_and_tenant(db_session_with_containers)
+ app = create_console_app(db_session_with_containers, tenant.id, account.id, AppMode.AGENT_CHAT)
+ agent_mode = {"enabled": True, "max_iteration": 5, "strategy": "function_call"}
+ config = AppModelConfig(app_id=app.id, agent_mode=json.dumps(agent_mode))
+ db_session_with_containers.add(config)
+ db_session_with_containers.flush()
+ app.app_model_config_id = config.id
+ db_session_with_containers.commit()
+
+ headers = authenticate_console_client(test_client_with_containers, account)
+ get_response = test_client_with_containers.get(f"/console/api/apps/{app.id}", headers=headers)
+ assert get_response.status_code == 200
+ assert get_response.json is not None
+ assert get_response.json["model_config"]["agent_mode"] == agent_mode
+
+ put_response = test_client_with_containers.put(
+ f"/console/api/apps/{app.id}", headers=headers, json={"name": "Updated App"}
+ )
+ assert put_response.status_code == 200
+ assert put_response.json is not None
+ assert put_response.json["model_config"]["agent_mode"] == agent_mode
+
+ with Session(db_session_with_containers.get_bind()) as reread_session:
+ persisted = reread_session.get(AppModelConfig, config.id)
+ assert persisted is not None
+ assert persisted.agent_mode == json.dumps(agent_mode)
diff --git a/api/tests/test_containers_integration_tests/services/test_app_service.py b/api/tests/test_containers_integration_tests/services/test_app_service.py
index d0aff28dec4..a71371b95d8 100644
--- a/api/tests/test_containers_integration_tests/services/test_app_service.py
+++ b/api/tests/test_containers_integration_tests/services/test_app_service.py
@@ -151,55 +151,6 @@ class TestAppService:
assert app.tenant_id == tenant.id
assert app.created_by == account.id
- def test_get_app_success(self, db_session_with_containers: Session, mock_external_service_dependencies):
- """
- Test successful app retrieval.
- """
- fake = Faker()
-
- # Create account and tenant first
- account = AccountService.create_account(
- email=fake.email(),
- name=fake.name(),
- interface_language="en-US",
- password=generate_valid_password(fake),
- session=db_session_with_containers,
- )
- TenantService.create_owner_tenant_if_not_exist(account, name=fake.company(), session=db_session_with_containers)
- tenant = account.current_tenant
-
- # Create app first
- # Import here to avoid circular dependency
- from services.app_service import AppService, CreateAppParams
-
- app_params = CreateAppParams(
- name=fake.company(),
- description=fake.text(max_nb_chars=100),
- mode="chat",
- icon_type="emoji",
- icon="🎯",
- icon_background="#45B7D1",
- )
-
- app_service = AppService()
- created_app = app_service.create_app(tenant.id, app_params, account, session=db_session_with_containers)
-
- # Get app using the service - needs current_user mock
- mock_current_user = create_autospec(Account, instance=True)
- mock_current_user.id = account.id
- mock_current_user.current_tenant_id = account.current_tenant_id
-
- with patch("services.app_service.current_user", mock_current_user):
- retrieved_app = app_service.get_app(created_app, session=db_session_with_containers)
-
- # Verify retrieved app matches created app
- assert retrieved_app.id == created_app.id
- assert retrieved_app.name == created_app.name
- assert retrieved_app.description == created_app.description
- assert retrieved_app.mode == created_app.mode
- assert retrieved_app.tenant_id == created_app.tenant_id
- assert retrieved_app.created_by == created_app.created_by
-
def test_get_paginate_apps_success(self, db_session_with_containers: Session, mock_external_service_dependencies):
"""
Test successful paginated app list retrieval.
diff --git a/api/tests/unit_tests/commands/test_generate_swagger_specs.py b/api/tests/unit_tests/commands/test_generate_swagger_specs.py
index abbaa1be7ec..5f80554a5dd 100644
--- a/api/tests/unit_tests/commands/test_generate_swagger_specs.py
+++ b/api/tests/unit_tests/commands/test_generate_swagger_specs.py
@@ -812,6 +812,14 @@ def test_generate_specs_include_console_contract_shapes_for_schema_migration(tmp
)
assert {"enabled", "model", "prompt"} <= set(schemas["WorkflowSuggestedQuestionsAfterAnswerPayload"]["properties"])
assert {"enabled", "language", "voice", "autoPlay"} <= set(schemas["WorkflowTextToSpeechPayload"]["properties"])
+ assert schemas["WorkflowTextToSpeechPayload"]["properties"]["autoPlay"]["anyOf"][0]["enum"] == [
+ "disabled",
+ "enabled",
+ ]
+ assert schemas["AgentTextToSpeechFeatureConfig"]["properties"]["autoPlay"]["anyOf"][0]["enum"] == [
+ "disabled",
+ "enabled",
+ ]
assert {"enabled", "type", "config"} <= set(schemas["WorkflowSensitiveWordAvoidancePayload"]["properties"])
file_upload = schemas["WorkflowFileUploadPayload"]["properties"]
assert {"document", "audio", "video", "custom", "preview_config"} <= set(file_upload)
diff --git a/api/tests/unit_tests/controllers/console/agent/test_agent_controllers.py b/api/tests/unit_tests/controllers/console/agent/test_agent_controllers.py
index 17b8254c2db..bb6605dc382 100644
--- a/api/tests/unit_tests/controllers/console/agent/test_agent_controllers.py
+++ b/api/tests/unit_tests/controllers/console/agent/test_agent_controllers.py
@@ -216,9 +216,9 @@ def _app_detail_obj(**overrides) -> App:
"tracing": None,
"use_icon_as_answer_icon": False,
"created_by": "account-1",
- "created_at": None,
+ "created_at": datetime(2025, 1, 1),
"updated_by": "account-1",
- "updated_at": None,
+ "updated_at": datetime(2025, 1, 1),
"max_active_requests": 0,
}
overrides.pop("bound_agent_id", None)
@@ -369,9 +369,6 @@ def test_agent_app_list_and_create_use_agent_route(
apply_config_overrides(monkeypatch, RBAC_ENABLED=True)
class FakeAppService:
- def get_app(self, app_obj: object, *, session: object) -> object:
- return app_obj
-
def get_paginate_apps(self, user_id: str, tenant_id: str, params, session) -> object:
captured["list"] = {"user_id": user_id, "tenant_id": tenant_id, "params": params}
return SimpleNamespace(
@@ -649,10 +646,6 @@ def test_agent_app_detail_update_delete_resolve_app_from_agent_id(
)
class FakeAppService:
- def get_app(self, app_obj: object, *, session: object) -> object:
- captured["get_app"] = {"app": app_obj, "session": session}
- return app_obj
-
def update_app(self, app_obj: object, args: dict[str, object], *, session: object) -> object:
captured["update"] = {"app": app_obj, "args": args}
return _app_detail_obj(id=app_id, tenant_id=tenant_id, name=args["name"], bound_agent_id=agent_id)
@@ -674,7 +667,6 @@ def test_agent_app_detail_update_delete_resolve_app_from_agent_id(
assert detail["access_ready"] is False
assert "active_config_is_published" not in detail
assert "bound_agent_id" not in detail
- assert captured["get_app"] == {"app": app_model, "session": session}
with app.test_request_context(
"/console/api/agent/00000000-0000-0000-0000-000000000001",
json={"name": "Renamed", "description": "", "role": "Reviewer", "icon_type": "emoji", "icon": "R"},
@@ -1043,9 +1035,6 @@ def test_agent_app_update_allows_empty_role(
)
class FakeAppService:
- def get_app(self, app_obj: object, *, session: object) -> object:
- return app_obj
-
def update_app(self, app_obj: object, args: dict[str, object], *, session: object) -> object:
captured["update"] = {"app": app_obj, "args": args}
return _app_detail_obj(id="app-1", name=args["name"], bound_agent_id=agent_id)
diff --git a/api/tests/unit_tests/controllers/console/app/test_app_response_models.py b/api/tests/unit_tests/controllers/console/app/test_app_response_models.py
index ff51ca8dd05..ca1425f3947 100644
--- a/api/tests/unit_tests/controllers/console/app/test_app_response_models.py
+++ b/api/tests/unit_tests/controllers/console/app/test_app_response_models.py
@@ -3,8 +3,10 @@
import json
from dataclasses import replace
from datetime import datetime
+from pathlib import Path
import pytest
+import yaml
from flask import Flask
from pydantic import ValidationError
from sqlalchemy.orm import Session
@@ -12,6 +14,7 @@ from werkzeug.datastructures import MultiDict
from controllers.console.app import app as controller
from fields import app_fields
+from fields.app_model_config_response import AppModelConfigResponse
from libs.pagination import PaginatedResult
from models.account import Account
from models.enums import CustomizeTokenStrategy, TagType
@@ -308,7 +311,6 @@ def test_app_detail_with_site_includes_nested_serialization(
monkeypatch: pytest.MonkeyPatch,
sqlite_session: Session,
):
- AppDetailWithSite = app_models.AppDetailWithSite
app_obj = _persist_response_graph(sqlite_session)
app_obj.name = "Detailed App"
app_obj.description = "Desc"
@@ -323,16 +325,19 @@ def test_app_detail_with_site_includes_nested_serialization(
assert model_config is not None
model_config.opening_statement = "hi"
model_config.retriever_resource = json.dumps({"enabled": True})
- monkeypatch.setattr("repositories.app.response.load_annotation_reply_config", lambda _session, _app_id: {})
+ monkeypatch.setattr(
+ "repositories.app.response.load_annotation_reply_config", lambda _session, _app_id: {"enabled": False}
+ )
with app.test_request_context("/"):
- serialized = AppDetailWithSite.model_validate(
+ response = controller._app_detail_response(
replace(
app_record(app_obj, session=sqlite_session, projection="detail-with-site"),
permission_keys=app_obj.permission_keys,
),
- from_attributes=True,
- ).model_dump(mode="json")
+ )
+ assert isinstance(response, app_models.AppDetailWithSite)
+ serialized = response.model_dump(mode="json")
assert serialized["icon_url"] == "signed:detail-icon"
assert serialized["model_config"]["retriever_resource"] == {"enabled": True}
@@ -427,3 +432,166 @@ def test_app_pagination_aliases_per_page_and_has_next(app_models, sqlite_session
assert len(serialized["data"]) == 2
assert serialized["data"][0]["icon_url"] == "signed:first-icon"
assert serialized["data"][1]["icon_url"] is None
+
+
+@pytest.mark.parametrize("strategy", [None, "cot", "function-calling"])
+def test_app_detail_preserves_historical_agent_strategy(
+ app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session, strategy: str | None
+):
+ app_obj = _persist_response_graph(sqlite_session)
+ config = sqlite_session.get(AppModelConfig, CONFIG_ID)
+ assert config is not None
+ agent_mode = {"enabled": True, "tools": []}
+ if strategy is not None:
+ agent_mode["strategy"] = strategy
+ config.agent_mode = json.dumps(agent_mode)
+ sqlite_session.commit()
+ monkeypatch.setattr(
+ "repositories.app.response.load_annotation_reply_config", lambda _session, _app_id: {"enabled": False}
+ )
+
+ with app.test_request_context("/"):
+ response = controller._app_detail_response(
+ app_record(app_obj, session=sqlite_session, projection="detail-with-site")
+ ).model_dump(mode="json")
+
+ assert response["model_config"]["agent_mode"] == agent_mode
+
+
+def test_app_detail_preserves_historical_agent_mode_without_tools(
+ app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session
+):
+ app_obj = _persist_response_graph(sqlite_session)
+ app_obj.mode = AppMode.AGENT_CHAT
+ config = sqlite_session.get(AppModelConfig, CONFIG_ID)
+ assert config is not None
+ agent_mode = {"enabled": True, "max_iteration": 5, "strategy": "function_call"}
+ config.agent_mode = json.dumps(agent_mode)
+ sqlite_session.commit()
+ monkeypatch.setattr(
+ "repositories.app.response.load_annotation_reply_config", lambda _session, _app_id: {"enabled": False}
+ )
+
+ with app.test_request_context("/"):
+ response = controller._app_detail_response(
+ app_record(app_obj, session=sqlite_session, projection="detail-with-site")
+ ).model_dump(mode="json")
+
+ assert response["model_config"]["agent_mode"] == agent_mode
+
+
+def test_app_model_config_response_round_trips_persisted_dataset_and_external_tool_fields(
+ app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session
+):
+ app_obj = _persist_response_graph(sqlite_session)
+ config = sqlite_session.get(AppModelConfig, CONFIG_ID)
+ assert config is not None
+ dataset_configs = {
+ "retrieval_model": "multiple",
+ "reranking_enable": True,
+ "reranking_enabled": True,
+ "metadata_filtering_conditions": {
+ "logical_operator": "and",
+ "conditions": [
+ {
+ "id": "condition-1",
+ "metadata_id": "metadata-1",
+ "name": "category",
+ "comparison_operator": "is",
+ "value": "books",
+ }
+ ],
+ },
+ "extension_setting": {"value": 1},
+ }
+ external_form = {
+ "external_data_tool": {
+ "variable": "customer",
+ "label": "Customer",
+ "type": "api",
+ "enabled": True,
+ "icon": "icon-key",
+ "icon_background": "#fff",
+ "config": {"provider": "crm"},
+ "extension_setting": {"value": 2},
+ }
+ }
+ config.dataset_configs = json.dumps(dataset_configs)
+ config.user_input_form = json.dumps([external_form])
+ sqlite_session.commit()
+ monkeypatch.setattr(
+ "repositories.app.response.load_annotation_reply_config", lambda _session, _app_id: {"enabled": False}
+ )
+
+ with app.test_request_context("/"):
+ response = controller._app_detail_response(
+ app_record(app_obj, session=sqlite_session, projection="detail-with-site")
+ ).model_dump(mode="json")
+
+ model_config = response["model_config"]
+ assert model_config["dataset_configs"] == dataset_configs
+ assert model_config["user_input_form"] == [external_form]
+
+ reimported = AppModelConfig(app_id=APP_ID)
+ reimported.from_model_config_dict(model_config)
+ assert reimported.dataset_configs_dict == dataset_configs
+ assert reimported.user_input_form_list == [external_form]
+
+
+def test_recommended_app_model_configs_keep_all_published_fields():
+ catalog_path = Path(__file__).resolve().parents[5] / "constants" / "recommended_apps.json"
+ catalog = json.loads(catalog_path.read_text())
+
+ def assert_fields_preserved(source, serialized):
+ if isinstance(source, dict):
+ for key, value in source.items():
+ assert key in serialized
+ assert_fields_preserved(value, serialized[key])
+ elif isinstance(source, list):
+ assert len(source) == len(serialized)
+ for value, serialized_value in zip(source, serialized, strict=True):
+ assert_fields_preserved(value, serialized_value)
+ else:
+ assert serialized == source
+
+ for entry in catalog["app_details"].values():
+ source = yaml.safe_load(entry["export_data"]).get("model_config") or {}
+ if not source:
+ continue
+ payload = {**source, "created_by": None, "created_at": 1, "updated_by": None, "updated_at": 1}
+ response = AppModelConfigResponse.model_validate(payload).model_dump(mode="json")
+ assert_fields_preserved(source, response)
+
+
+def test_app_detail_rejects_invalid_known_configuration_fields(
+ app: Flask, monkeypatch: pytest.MonkeyPatch, sqlite_session: Session
+):
+ app_obj = _persist_response_graph(sqlite_session)
+ monkeypatch.setattr(
+ "repositories.app.response.load_annotation_reply_config", lambda _session, _app_id: {"enabled": False}
+ )
+ with app.test_request_context("/"):
+ detail = controller._app_detail_response(
+ app_record(app_obj, session=sqlite_session, projection="detail-with-site")
+ ).model_dump(mode="json")
+
+ for field in ("mode", "permission_keys", "site", "model_config"):
+ with pytest.raises(ValidationError):
+ app_fields.AppDetailWithSite.model_validate({key: value for key, value in detail.items() if key != field})
+
+ with pytest.raises(ValidationError):
+ app_fields.AppDetailWithSite.model_validate({**detail, "mode": "unsupported"})
+
+ config = detail["model_config"]
+ for invalid in (
+ {"speech_to_text": {"enabled": "not-a-boolean"}},
+ {"agent_mode": {"enabled": True, "strategy": "unsupported", "tools": []}},
+ {"agent_mode": {"enabled": True, "tools": "not-a-list"}},
+ {"agent_mode": {"enabled": True, "tools": [{"provider_id": "only-id"}]}},
+ {"dataset_configs": {"retrieval_model": "unsupported"}},
+ {"dataset_configs": {"retrieval_model": "multiple", "reranking_mode": "unsupported"}},
+ {"model": {"provider": "openai", "name": "gpt-4o", "mode": "unsupported"}},
+ {"user_input_form": [{"unsupported": {"label": "Name", "variable": "name"}}]},
+ ):
+ with pytest.raises(ValidationError):
+ app_fields.AppDetailWithSite.model_validate({**detail, "model_config": {**config, **invalid}})
diff --git a/api/tests/unit_tests/controllers/console/app/test_console_app_api.py b/api/tests/unit_tests/controllers/console/app/test_console_app_api.py
index a497bcd1fd0..f244d27d4da 100644
--- a/api/tests/unit_tests/controllers/console/app/test_console_app_api.py
+++ b/api/tests/unit_tests/controllers/console/app/test_console_app_api.py
@@ -3,6 +3,7 @@
import inspect
from collections.abc import Callable
from dataclasses import dataclass, field, replace
+from datetime import datetime
from io import BytesIO
from typing import cast
from uuid import UUID
@@ -18,6 +19,7 @@ from controllers.console.app.error import AppNotFoundError
from libs.login import AccountWithTenant
from machinery.context import RequestContext
from models.account import Account, TenantAccountRole
+from models.enums import CustomizeTokenStrategy
from services.agent.roster_package_entities import RosterAgentPackageExport
from services.app.console_service import (
AppExportPaidPlanRequiredError,
@@ -41,7 +43,33 @@ from tests.unit_tests.config_override import apply_config_overrides
APP_ID = UUID("11111111-1111-1111-1111-111111111111")
CONTEXT = RequestContext("request", "trace", "actor", "workspace")
-RECORD = AppRecord(str(APP_ID), "Example", "chat")
+RECORD = AppRecord(
+ str(APP_ID), "Example", "chat", description="", created_at=datetime(2024, 1, 1), updated_at=datetime(2024, 1, 1)
+)
+SITE = {
+ "code": "site",
+ "title": "Example",
+ "icon_type": None,
+ "icon": None,
+ "icon_background": None,
+ "description": None,
+ "default_language": "en-US",
+ "chat_color_theme": None,
+ "chat_color_theme_inverted": False,
+ "customize_domain": None,
+ "copyright": None,
+ "privacy_policy": None,
+ "input_placeholder": None,
+ "custom_disclaimer": "",
+ "customize_token_strategy": CustomizeTokenStrategy.NOT_ALLOW,
+ "prompt_public": False,
+ "show_workflow_steps": False,
+ "use_icon_as_answer_icon": False,
+ "created_by": None,
+ "created_at": datetime(2024, 1, 1),
+ "updated_by": None,
+ "updated_at": datetime(2024, 1, 1),
+}
@dataclass
@@ -133,7 +161,7 @@ def test_detail_resolves_urls_at_the_http_boundary(
SERVICE_API_URL="https://api.example.com" if configured else "",
APP_WEB_URL="https://apps.example.com" if configured else "",
)
- boundary.record = replace(RECORD, site={"code": "site", "title": "Example"})
+ boundary.record = replace(RECORD, site=SITE)
with app.test_request_context("/", base_url="https://console.example.com/"):
response = cast(dict[str, object], invoke(controller.AppApi, controller.AppApi.get, app_id=APP_ID))
assert response["api_base_url"] == (
diff --git a/api/tests/unit_tests/controllers/console/explore/test_trial_preview_details.py b/api/tests/unit_tests/controllers/console/explore/test_trial_preview_details.py
index 60fd3fbb24c..7e0f3297fd1 100644
--- a/api/tests/unit_tests/controllers/console/explore/test_trial_preview_details.py
+++ b/api/tests/unit_tests/controllers/console/explore/test_trial_preview_details.py
@@ -48,7 +48,7 @@ from repositories.app_preview_query_repository import AppPreviewQueryRepository
from repositories.trial_app_repository import TrialAppRepository
from services.app_preview_details_adapters import AppPreviewDetailsRuntime
from services.app_preview_query_service import AppPreviewQueryService
-from services.app_service import AppResponseView, AppService
+from services.app_service import AppResponseView
from services.recommended_app_query_service import (
RecommendedAppCatalogPage,
RecommendedAppDetailRecord,
@@ -204,9 +204,8 @@ class _Harness:
with self.app.test_request_context(f"/trial-apps/{self.target.id}"), self.factory() as session:
app = session.get(App, self.target.id)
assert app is not None
- app = AppService().get_app(app, session=session)
return trial_module.TrialAppDetailResponse.model_validate(
- AppResponseView(app, session=session), from_attributes=True
+ AppResponseView(app, session=session, account=self.viewer), from_attributes=True
).model_dump(mode="json")
diff --git a/api/tests/unit_tests/core/app/app_config/features/test_additional_feature_managers.py b/api/tests/unit_tests/core/app/app_config/features/test_additional_feature_managers.py
index 0a0ffe657c9..12a4a86d86d 100644
--- a/api/tests/unit_tests/core/app/app_config/features/test_additional_feature_managers.py
+++ b/api/tests/unit_tests/core/app/app_config/features/test_additional_feature_managers.py
@@ -81,6 +81,10 @@ class TestAdditionalFeatureManagers:
SuggestedQuestionsAfterAnswerConfigManager.validate_and_set_defaults(
{"suggested_questions_after_answer": {"enabled": True, "prompt": 123}}
)
+ with pytest.raises(ValueError, match="prompt in suggested_questions_after_answer must be of string type"):
+ SuggestedQuestionsAfterAnswerConfigManager.validate_and_set_defaults(
+ {"suggested_questions_after_answer": {"enabled": False, "prompt": None}}
+ )
with pytest.raises(ValueError, match="must be less than or equal to 1000 characters"):
SuggestedQuestionsAfterAnswerConfigManager.validate_and_set_defaults(
{"suggested_questions_after_answer": {"enabled": True, "prompt": "a" * 1001}}
@@ -128,6 +132,16 @@ class TestAdditionalFeatureManagers:
TextToSpeechConfigManager.validate_and_set_defaults({"text_to_speech": "bad"})
with pytest.raises(ValueError):
TextToSpeechConfigManager.validate_and_set_defaults({"text_to_speech": {"enabled": "yes"}})
+ for field, value in (("voice", None), ("language", 42), ("autoPlay", "auto"), ("autoPlay", None)):
+ with pytest.raises(ValueError, match=f"{field} in text_to_speech"):
+ TextToSpeechConfigManager.validate_and_set_defaults(
+ {"text_to_speech": {"enabled": False, field: value}}
+ )
+
+ valid, _ = TextToSpeechConfigManager.validate_and_set_defaults(
+ {"text_to_speech": {"enabled": True, "voice": "v", "language": "en", "autoPlay": "enabled"}}
+ )
+ assert valid["text_to_speech"]["autoPlay"] == "enabled"
result = TextToSpeechConfigManager.convert(
{"text_to_speech": {"enabled": True, "voice": "v", "language": "en"}}
diff --git a/api/tests/unit_tests/models/test_app_models.py b/api/tests/unit_tests/models/test_app_models.py
index f93aad88991..98f993a006c 100644
--- a/api/tests/unit_tests/models/test_app_models.py
+++ b/api/tests/unit_tests/models/test_app_models.py
@@ -427,6 +427,18 @@ class TestAppModelValidation:
class TestAppModelConfig:
"""Test suite for AppModelConfig model."""
+ def test_legacy_dataset_configs_default_retrieval_model_without_dropping_settings(self):
+ config = AppModelConfig(
+ app_id=str(uuid4()),
+ dataset_configs=json.dumps({"reranking_enable": True, "top_k": 8}),
+ )
+
+ assert config.dataset_configs_dict == {
+ "retrieval_model": "single",
+ "reranking_enable": True,
+ "top_k": 8,
+ }
+
def test_app_model_config_creation(self):
"""Test creating an AppModelConfig."""
# Arrange
diff --git a/api/tests/unit_tests/repositories/test_console_app_repository.py b/api/tests/unit_tests/repositories/test_console_app_repository.py
index 8cbaf54a5c7..e90243dd74c 100644
--- a/api/tests/unit_tests/repositories/test_console_app_repository.py
+++ b/api/tests/unit_tests/repositories/test_console_app_repository.py
@@ -9,7 +9,7 @@ from flask import has_request_context
from sqlalchemy import Engine, event, func, select, text
from sqlalchemy.orm import Session, sessionmaker
-from fields.app_fields import AppDetailWithSite, AppPagination
+from fields.app_fields import AppPagination
from machinery.context import RequestContext
from models.agent import Agent, AgentScope, AgentSource, AgentStatus
from models.enums import CustomizeTokenStrategy
@@ -101,13 +101,11 @@ def test_all_single_app_operations_preserve_visibility(
assert sqlite_session.scalar(select(func.count()).select_from(AppStar)) == 0
-def test_detail_is_serializable_after_repository_session_closes(
+def test_detail_is_materialized_after_repository_session_closes(
repository: ConsoleAppRepository,
sqlite_session: Session,
sqlite_engine: Engine,
- config_overrides: Callable[..., None],
) -> None:
- config_overrides(SERVICE_API_URL="", APP_WEB_URL="")
assert not has_request_context()
app = persist_app(sqlite_session)
config = AppModelConfig(app_id=app.id, model='{"provider":"openai","name":"example"}', pre_prompt="Prompt")
@@ -129,14 +127,16 @@ def test_detail_is_serializable_after_repository_session_closes(
event.listen(sqlite_engine, "before_cursor_execute", reject_queries)
try:
- data = AppDetailWithSite.model_validate(record, from_attributes=True).model_dump(mode="json")
+ model_config = record.app_model_config
+ site_data = record.site
+ description = record.description
finally:
event.remove(sqlite_engine, "before_cursor_execute", reject_queries)
- assert data["model_config"]["model"] == {"provider": "openai", "name": "example"}
- assert data["site"]["access_token"] == "site-code"
- assert data["description"] == ""
- assert data["api_base_url"] is None
- assert data["site"]["app_base_url"] is None
+ assert model_config is not None
+ assert model_config["model"] == {"provider": "openai", "name": "example"}
+ assert site_data is not None
+ assert site_data["code"] == "site-code"
+ assert description == ""
@pytest.mark.parametrize(
diff --git a/api/tests/unit_tests/services/app/test_console_service.py b/api/tests/unit_tests/services/app/test_console_service.py
index d65164357a0..20b181f197c 100644
--- a/api/tests/unit_tests/services/app/test_console_service.py
+++ b/api/tests/unit_tests/services/app/test_console_service.py
@@ -17,7 +17,6 @@ from core.plugin.impl.plugin import PluginInstaller
from core.tools.entities.tool_entities import ApiProviderSchemaType
from core.tools.tool_manager import ToolManager
from events.app_event import app_was_updated
-from fields.app_fields import AppDetailWithSite
from graphon.model_runtime.entities.model_entities import ModelType
from machinery.context import RequestContext
from models.account import Account, Tenant, TenantAccountJoin, TenantAccountRole
@@ -839,13 +838,11 @@ def test_detail_tool_enrichment_releases_database_before_plugin_io(
assert read.scalar(select(App.id).where(App.name == "Created")) is not None
else:
result = read_result()
- data = AppDetailWithSite.model_validate(result, from_attributes=True).model_dump(mode="json")
- assert data["deleted_tools"] == [
+ assert result.deleted_tools == [
{"type": "api", "provider_id": missing_api, "tool_name": "tool"},
{"type": "api", "provider_id": providers[1].id, "tool_name": "tool"},
{"type": "builtin", "provider_id": "vendor/missing/tool", "tool_name": "tool"},
]
- assert "tool_references" not in data
assert remote_calls == [["vendor/missing/tool", "vendor/installed/tool"]]
assert not checked_out
finally:
diff --git a/api/tests/unit_tests/services/test_app_dsl_service.py b/api/tests/unit_tests/services/test_app_dsl_service.py
index 60e10a36b85..544142e9d4b 100644
--- a/api/tests/unit_tests/services/test_app_dsl_service.py
+++ b/api/tests/unit_tests/services/test_app_dsl_service.py
@@ -515,6 +515,52 @@ def test_create_or_update_app_flushes_new_model_config_before_signal(
assert sqlite_session.in_transaction()
+@pytest.mark.parametrize(
+ ("feature", "field", "value"),
+ [
+ ("suggested_questions_after_answer", "prompt", None),
+ ("suggested_questions_after_answer", "prompt", 123),
+ ("text_to_speech", "voice", None),
+ ("text_to_speech", "language", 123),
+ ("text_to_speech", "autoPlay", "auto"),
+ ],
+)
+def test_chat_dsl_import_rejects_invalid_feature_fields(
+ sqlite_session: Session, feature: str, field: str, value: object
+) -> None:
+ app = _app()
+
+ with pytest.raises(ValueError, match=field):
+ AppDslService(session=sqlite_session)._create_or_update_app(
+ app=app,
+ data={"app": {"mode": AppMode.CHAT}, "model_config": {feature: {"enabled": True, field: value}}},
+ account=_account(),
+ )
+
+ assert app.app_model_config_id is None
+ assert list(sqlite_session.scalars(select(AppModelConfig))) == []
+
+
+def test_chat_dsl_import_preserves_valid_feature_fields(sqlite_session: Session) -> None:
+ app = _app()
+ model_config = {
+ "suggested_questions_after_answer": {"enabled": True, "prompt": "Follow up"},
+ "text_to_speech": {"enabled": True, "voice": "alloy", "language": "en", "autoPlay": "disabled"},
+ }
+
+ AppDslService(session=sqlite_session)._create_or_update_app(
+ app=app,
+ data={"app": {"mode": AppMode.CHAT}, "model_config": model_config},
+ account=_account(),
+ )
+
+ assert app.app_model_config_id is not None
+ persisted = sqlite_session.get(AppModelConfig, app.app_model_config_id)
+ assert persisted is not None
+ assert persisted.suggested_questions_after_answer_dict == model_config["suggested_questions_after_answer"]
+ assert persisted.text_to_speech_dict == model_config["text_to_speech"]
+
+
def test_create_or_update_app_removes_imported_workflow_viewport(monkeypatch: pytest.MonkeyPatch) -> None:
session = cast(Session, SimpleNamespace(add=Mock(), flush=Mock(), get=Mock()))
service = AppDslService(session=session)
diff --git a/api/tests/unit_tests/services/test_app_service.py b/api/tests/unit_tests/services/test_app_service.py
index 5ba1c505aaf..5e5a0350583 100644
--- a/api/tests/unit_tests/services/test_app_service.py
+++ b/api/tests/unit_tests/services/test_app_service.py
@@ -9,7 +9,7 @@ from uuid import uuid4
import pytest
from sqlalchemy import event, select
-from sqlalchemy.orm import Session
+from sqlalchemy.orm import Session, sessionmaker
from enums import DeploymentEdition
from graphon.model_runtime.entities.model_entities import ModelType
@@ -31,7 +31,7 @@ from models.provider import TenantDefaultModel
from models.workflow import Workflow, WorkflowType
from repositories.app.console_repository import ConsoleAppRepository
from services.agent.errors import AgentAccessNotReadyError, AgentNameConflictError
-from services.app_service import AppListParams, AppService, CreateAppParams
+from services.app_service import AppListParams, AppResponseView, AppService, CreateAppParams
from services.enterprise import rbac_service as enterprise_rbac_service
@@ -586,68 +586,40 @@ def test_get_recent_apps_uses_one_tenant_scoped_projection_query(sqlite_session:
assert "app_model_configs" not in select_statements[0].lower()
-class TestGetApp:
- def test_legacy_agent_detection_uses_caller_session(self, unbound_session: Session):
- app = App(
- mode=AppMode.CHAT,
- )
+class TestAppResponseViewAgentConfig:
+ def test_masking_persistent_agent_config_does_not_change_database(
+ self, sqlite_session: Session, sqlite_session_factory: sessionmaker[Session]
+ ):
+ tenant_id = str(uuid4())
+ app = _persist_app(sqlite_session, tenant_id=tenant_id)
+ app.mode = AppMode.AGENT_CHAT
+ original_agent_mode = {"enabled": True, "tools": [{"parameters": {"secret": "encrypted-value"}}]}
+ config = AppModelConfig(app_id=app.id, agent_mode=json.dumps(original_agent_mode))
+ sqlite_session.add(config)
+ sqlite_session.flush()
+ app.app_model_config_id = config.id
+ sqlite_session.commit()
+
account = Account(name="Test Account", email="test@example.com")
account._current_tenant = Tenant(name="Test Tenant")
- account._current_tenant.id = "tenant-1"
+ account._current_tenant.id = tenant_id
+ masked_agent_mode = {"enabled": True, "tools": [{"parameters": {"secret": "[masked]"}}]}
with (
- patch.object(App, "is_agent_with_session", return_value=False) as is_agent,
- patch.object(App, "app_model_config_with_session") as get_model_config,
- patch("services.app_service.current_user", account),
+ patch("services.app_service.mask_agent_tool_parameters", return_value=masked_agent_mode),
+ patch.object(sqlite_session, "refresh", side_effect=AssertionError("App refresh is unnecessary")),
):
- assert AppService().get_app(app, session=unbound_session) is app
+ response_config = AppResponseView(app, session=sqlite_session, account=account).app_model_config
+ assert response_config is not None
+ assert response_config.agent_mode_dict == masked_agent_mode
+ assert config.agent_mode_dict == original_agent_mode
+ assert not sqlite_session.is_modified(config)
+ sqlite_session.commit()
- is_agent.assert_called_once_with(session=unbound_session)
- get_model_config.assert_not_called()
-
- def test_agent_model_config_uses_caller_session(self, unbound_session: Session):
- app = App(
- mode=AppMode.AGENT_CHAT,
- )
- account = Account(name="Test Account", email="test@example.com")
- account._current_tenant = Tenant(name="Test Tenant")
- account._current_tenant.id = "tenant-1"
-
- with (
- patch.object(App, "is_agent_with_session") as is_agent,
- patch.object(App, "app_model_config_with_session", return_value=None) as get_model_config,
- patch("services.app_service.current_user", account),
- ):
- assert AppService().get_app(app, session=unbound_session) is app
-
- is_agent.assert_not_called()
- get_model_config.assert_called_once_with(session=unbound_session)
-
- def test_masked_agent_config_is_served_through_the_session_accessor(self, unbound_session: Session):
- """The masked config must be reachable via `app_model_config_with_session`.
-
- Every response path resolves an `App`'s model config through that accessor
- (`AppResponseView.app_model_config`), never through a raw attribute, so the
- masking `get_app` applies has to be observable there.
- """
- app = App(mode=AppMode.AGENT_CHAT)
- app.id = str(uuid4())
- masked_config = AppModelConfig(app_id=app.id, agent_mode=json.dumps({"enabled": True, "tools": []}))
- # A second, unmasked instance: what a fresh lookup would hand back if the
- # returned app ever fell through to the base accessor.
- refetched_config = AppModelConfig(app_id=app.id, agent_mode=json.dumps({"enabled": True, "tools": []}))
- account = Account(name="Test Account", email="test@example.com")
- account._current_tenant = Tenant(name="Test Tenant")
- account._current_tenant.id = "tenant-1"
-
- with (
- patch.object(App, "app_model_config_with_session", side_effect=[masked_config, refetched_config]),
- patch("services.app_service.current_user", account),
- ):
- result = AppService().get_app(app, session=unbound_session)
-
- assert result is not app
- assert result.app_model_config_with_session(session=unbound_session) is masked_config
+ with sqlite_session_factory() as read_session:
+ saved_config = read_session.get(AppModelConfig, config.id)
+ assert saved_config is not None
+ assert saved_config.agent_mode_dict == original_agent_mode
class TestAgentAppType:
diff --git a/packages/contracts/generated/api/console/agent/types.gen.ts b/packages/contracts/generated/api/console/agent/types.gen.ts
index 9f55a1e04cf..f2ef8cf1bb0 100644
--- a/packages/contracts/generated/api/console/agent/types.gen.ts
+++ b/packages/contracts/generated/api/console/agent/types.gen.ts
@@ -23,41 +23,41 @@ export type AgentAppCreatePayload = {
}
export type AgentAppDetailWithSite = {
- access_mode?: string | null
+ access_mode: WebAppAccessMode | null
access_ready?: boolean
- api_base_url?: string | null
+ api_base_url: string
app_id?: string | null
backing_app_id?: string | null
bound_agent_id?: string | null
- created_at?: number | null
- created_by?: string | null
+ created_at: number
+ created_by: string | null
debug_conversation_has_messages?: boolean
debug_conversation_id?: string | null
debug_conversation_message_count?: number
- deleted_tools?: Array
- description?: string | null
+ deleted_tools: Array
+ description: string
enable_api: boolean
enable_site: boolean
hidden_app_backed?: boolean
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
readonly icon_url: string | null
id: string
- maintainer?: string | null
- max_active_requests?: number | null
- mode: string
- model_config?: AppModelConfigResponse | null
+ maintainer: string | null
+ max_active_requests: number | null
+ mode: AppMode
+ model_config: AppModelConfigResponse | null
name: string
permission_keys: Array
role?: string | null
- site?: AppDetailSiteResponse | null
- tags?: Array
- tracing?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
- workflow?: WorkflowPartial | null
+ site: AppDetailSiteResponse | null
+ tags: Array
+ tracing: string | null
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
+ workflow: WorkflowPartial | null
}
export type AgentInviteOptionsResponse = {
@@ -443,7 +443,7 @@ export type AgentConfigSnapshotRestoreResponse = {
}
export type AgentAppPartial = {
- access_mode?: string | null
+ access_mode?: WebAppAccessMode | null
active_config_is_published?: boolean
app_id?: string | null
author_name?: string | null
@@ -458,13 +458,13 @@ export type AgentAppPartial = {
hidden_app_backed?: boolean
icon?: string | null
icon_background?: string | null
- icon_type?: string | null
+ icon_type?: IconType | null
readonly icon_url: string | null
id: string
is_starred?: boolean
maintainer?: string | null
max_active_requests?: number | null
- mode: string
+ mode: AppMode
model_config?: ModelConfigPartial | null
name: string
permission_keys: Array
@@ -486,65 +486,89 @@ export type AgentPublicationCountsResponse = {
export type IconType = 'emoji' | 'image' | 'link'
+export type WebAppAccessMode = 'private' | 'private_all' | 'public' | 'sso_verified'
+
export type DeletedTool = {
provider_id: string
tool_name: string
type: string
}
+export type AppMode =
+ | 'advanced-chat'
+ | 'agent'
+ | 'agent-chat'
+ | 'channel'
+ | 'chat'
+ | 'completion'
+ | 'rag-pipeline'
+ | 'workflow'
+
export type AppModelConfigResponse = {
- agent_mode?: unknown | null
- annotation_reply?: unknown | null
- chat_prompt_config?: unknown | null
- completion_prompt_config?: unknown | null
- created_at?: number | null
- created_by?: string | null
- dataset_configs?: unknown | null
- dataset_query_variable?: string | null
- external_data_tools?: unknown | null
- file_upload?: unknown | null
- model?: unknown | null
- more_like_this?: unknown | null
- opening_statement?: string | null
- pre_prompt?: string | null
- prompt_type?: string | null
- retriever_resource?: unknown | null
- sensitive_word_avoidance?: unknown | null
- speech_to_text?: unknown | null
- suggested_questions?: unknown | null
- suggested_questions_after_answer?: unknown | null
- text_to_speech?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- user_input_form?: unknown | null
+ agent_mode: AppAgentModeResponse
+ annotation_reply: AppAnnotationReplyEnabledResponse | AppAnnotationReplyDisabledResponse
+ chat_prompt_config: AppChatPromptConfigResponse
+ completion_prompt_config: AppCompletionPromptConfigResponse
+ created_at: number
+ created_by: string | null
+ dataset_configs: AppDatasetConfigsResponse
+ dataset_query_variable: string | null
+ external_data_tools: Array<
+ AppEnabledExternalDataToolResponse | AppDisabledExternalDataToolResponse
+ >
+ file_upload: AppFileUploadResponse
+ model: AppModelSelectionResponse
+ more_like_this: AppEnabledConfigResponse
+ opening_statement: string | null
+ pre_prompt: string | null
+ prompt_type: PromptType
+ retriever_resource: AppEnabledConfigResponse
+ sensitive_word_avoidance: AppSensitiveWordAvoidanceResponse
+ speech_to_text: AppEnabledConfigResponse
+ suggested_questions: Array
+ suggested_questions_after_answer: AppSuggestedQuestionsAfterAnswerResponse
+ text_to_speech: AppTextToSpeechResponse
+ updated_at: number
+ updated_by: string | null
+ user_input_form: Array<
+ | AppTextInputFormResponse
+ | AppSelectFormResponse
+ | AppParagraphFormResponse
+ | AppNumberFormResponse
+ | AppCheckboxFormResponse
+ | AppFileFormResponse
+ | AppFileListFormResponse
+ | AppExternalDataToolFormResponse
+ | AppJsonObjectFormResponse
+ >
}
export type AppDetailSiteResponse = {
- access_token?: string | null
- app_base_url?: string | null
- chat_color_theme?: string | null
- chat_color_theme_inverted?: boolean | null
- code?: string | null
- copyright?: string | null
- created_at?: number | null
- created_by?: string | null
- custom_disclaimer?: string | null
- customize_domain?: string | null
- customize_token_strategy?: string | null
- default_language?: string | null
- description?: string | null
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | IconType | null
+ access_token: string | null
+ app_base_url: string
+ chat_color_theme: string | null
+ chat_color_theme_inverted: boolean
+ code: string | null
+ copyright: string | null
+ created_at: number
+ created_by: string | null
+ custom_disclaimer: string
+ customize_domain: string | null
+ customize_token_strategy: CustomizeTokenStrategy
+ default_language: string
+ description: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
readonly icon_url: string | null
- input_placeholder?: string | null
- privacy_policy?: string | null
- prompt_public?: boolean | null
- show_workflow_steps?: boolean | null
- title?: string | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
+ input_placeholder: string | null
+ privacy_policy: string | null
+ prompt_public: boolean
+ show_workflow_steps: boolean
+ title: string
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
}
export type Tag = {
@@ -794,7 +818,7 @@ export type AgentSuggestedQuestionsAfterAnswerFeatureConfig = {
}
export type AgentTextToSpeechFeatureConfig = {
- autoPlay?: string | null
+ autoPlay?: 'disabled' | 'enabled' | null
enabled?: boolean
language?: string | null
voice?: string | null
@@ -989,7 +1013,7 @@ export type AgentConfigRevisionResponse = {
export type ModelConfigPartial = {
created_at?: number | null
created_by?: string | null
- model?: unknown | null
+ model?: AppModelSelectionResponse | null
pre_prompt?: string | null
updated_at?: number | null
updated_by?: string | null
@@ -1003,6 +1027,172 @@ export type AgentAppPublishedReferenceResponse = {
app_name: string
}
+export type AppAgentModeResponse = {
+ enabled: boolean
+ max_iteration?: number
+ prompt?: AppAgentPromptResponse | string | null
+ strategy?: PlanningStrategy | 'cot' | 'function-calling' | null
+ tools?: Array<
+ | AppProviderAgentToolResponse
+ | AppLegacyDatasetToolResponse
+ | AppLegacyGoogleSearchToolResponse
+ | AppLegacyWebReaderToolResponse
+ | AppLegacyWikipediaToolResponse
+ | AppLegacyCurrentDatetimeToolResponse
+ | AppLegacySensitiveWordToolResponseItem
+ >
+ [key: string]: unknown
+}
+
+export type AppAnnotationReplyEnabledResponse = {
+ embedding_model: AppEmbeddingModelResponse
+ enabled: true
+ id: string
+ score_threshold: number
+}
+
+export type AppAnnotationReplyDisabledResponse = {
+ enabled: false
+}
+
+export type AppChatPromptConfigResponse = {
+ prompt?: Array
+}
+
+export type AppCompletionPromptConfigResponse = {
+ conversation_histories_role?: AppConversationHistoriesRoleResponse
+ prompt?: AppCompletionPromptTextResponse
+}
+
+export type AppDatasetConfigsResponse = {
+ datasets?: AppDatasetListResponse
+ metadata_filtering_conditions?: AppMetadataFilteringConditionsResponse | null
+ metadata_filtering_mode?: 'automatic' | 'disabled' | 'manual'
+ metadata_model_config?: AppModelSelectionResponse | null
+ reranking_enable?: boolean
+ reranking_enabled?: boolean
+ reranking_mode?: RerankMode
+ reranking_model?: AppRerankingModelResponse | null
+ retrieval_model: 'multiple' | 'single'
+ score_threshold?: number | null
+ score_threshold_enabled?: boolean
+ top_k?: number
+ weights?: AppWeightsResponse | null
+ [key: string]: unknown
+}
+
+export type AppEnabledExternalDataToolResponse = {
+ config: {
+ [key: string]: JsonValue2
+ }
+ enabled: true
+ icon?: string
+ icon_background?: string
+ label?: string
+ type: string
+ variable: string
+ [key: string]: unknown
+}
+
+export type AppDisabledExternalDataToolResponse = {
+ config?: {
+ [key: string]: JsonValue2
+ }
+ enabled: false
+ icon?: string
+ icon_background?: string
+ label?: string
+ type?: string
+ variable?: string
+ [key: string]: unknown
+}
+
+export type AppFileUploadResponse = {
+ allowed_file_extensions?: Array
+ allowed_file_types?: Array
+ allowed_file_upload_methods?: Array
+ enabled?: boolean
+ image?: AppImageUploadResponse
+ number_limits?: number
+}
+
+export type AppModelSelectionResponse = {
+ completion_params?: {
+ [key: string]: JsonValue2
+ }
+ mode?: LlmMode | ''
+ name?: string
+ provider?: string
+ [key: string]: unknown
+}
+
+export type AppEnabledConfigResponse = {
+ enabled: boolean
+}
+
+export type PromptType = 'advanced' | 'simple'
+
+export type AppSensitiveWordAvoidanceResponse = {
+ config?: {
+ [key: string]: JsonValue2
+ }
+ configs?: Array
+ enabled: boolean
+ type?: string
+ [key: string]: unknown
+}
+
+export type AppSuggestedQuestionsAfterAnswerResponse = {
+ enabled: boolean
+ model?: AppModelSelectionResponse
+ prompt?: string
+}
+
+export type AppTextToSpeechResponse = {
+ autoPlay?: 'disabled' | 'enabled'
+ enabled: boolean
+ language?: string
+ voice?: string
+}
+
+export type AppTextInputFormResponse = {
+ 'text-input': AppUserInputFormConfigResponse
+}
+
+export type AppSelectFormResponse = {
+ select: AppUserInputFormConfigResponse
+}
+
+export type AppParagraphFormResponse = {
+ paragraph: AppUserInputFormConfigResponse
+}
+
+export type AppNumberFormResponse = {
+ number: AppUserInputFormConfigResponse
+}
+
+export type AppCheckboxFormResponse = {
+ checkbox: AppUserInputFormConfigResponse
+}
+
+export type AppFileFormResponse = {
+ file: AppUserInputFormConfigResponse
+}
+
+export type AppFileListFormResponse = {
+ 'file-list': AppUserInputFormConfigResponse
+}
+
+export type AppExternalDataToolFormResponse = {
+ external_data_tool: AppUserInputFormConfigResponse
+}
+
+export type AppJsonObjectFormResponse = {
+ json_object: AppUserInputFormConfigResponse
+}
+
+export type CustomizeTokenStrategy = 'allow' | 'must' | 'not_allow' | 'uuid'
+
export type AgentKind = 'dify_agent'
export type AgentPublishedReferenceResponse = {
@@ -1341,6 +1531,158 @@ export type AgentConfigRevisionOperation =
| 'save_new_version'
| 'save_to_roster'
+export type AppAgentPromptResponse = {
+ first_prompt?: string
+ next_iteration?: string
+ [key: string]: unknown
+}
+
+export type PlanningStrategy = 'function_call' | 'react' | 'react_router' | 'router'
+
+export type AppProviderAgentToolResponse = {
+ credential_id?: string | null
+ enabled?: boolean
+ isDeleted?: boolean
+ notAuthor?: boolean
+ plugin_unique_identifier?: string | null
+ provider_id: string
+ provider_name?: string
+ provider_type: ToolProviderType
+ tool_label?: string
+ tool_name: string
+ tool_parameters: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyDatasetToolResponse = {
+ dataset: AppDatasetReferenceResponse
+ [key: string]: unknown
+}
+
+export type AppLegacyGoogleSearchToolResponse = {
+ google_search: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyWebReaderToolResponse = {
+ web_reader: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyWikipediaToolResponse = {
+ wikipedia: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyCurrentDatetimeToolResponse = {
+ current_datetime: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacySensitiveWordToolResponseItem = {
+ 'sensitive-word-avoidance': AppLegacySensitiveWordToolResponse
+ [key: string]: unknown
+}
+
+export type AppEmbeddingModelResponse = {
+ embedding_model_name: string
+ embedding_provider_name: string
+}
+
+export type AppChatPromptMessageResponse = {
+ role: string
+ text: string
+}
+
+export type AppConversationHistoriesRoleResponse = {
+ assistant_prefix: string
+ user_prefix: string
+}
+
+export type AppCompletionPromptTextResponse = {
+ text: string
+}
+
+export type AppDatasetListResponse = {
+ datasets: Array
+ strategy?: string
+ [key: string]: unknown
+}
+
+export type AppMetadataFilteringConditionsResponse = {
+ conditions?: Array | null
+ logical_operator?: 'and' | 'or' | null
+ [key: string]: unknown
+}
+
+export type RerankMode = 'reranking_model' | 'weighted_score'
+
+export type AppRerankingModelResponse = {
+ reranking_model_name?: string
+ reranking_provider_name?: string
+ [key: string]: unknown
+}
+
+export type AppWeightsResponse = {
+ keyword_setting: AppKeywordSettingResponse
+ vector_setting: AppVectorSettingResponse
+ weight_type?: 'customized' | 'keyword_first' | 'semantic_first'
+ [key: string]: unknown
+}
+
+export type JsonValue2 = unknown
+
+export type FileType = 'audio' | 'custom' | 'document' | 'image' | 'video'
+
+export type FileTransferMethod = 'datasource_file' | 'local_file' | 'remote_url' | 'tool_file'
+
+export type AppImageUploadResponse = {
+ detail?: 'high' | 'low' | null
+ enabled?: boolean
+ number_limits?: number
+ transfer_methods?: Array
+}
+
+export type LlmMode = 'chat' | 'completion'
+
+export type AppUserInputFormConfigResponse = {
+ allowed_file_extensions?: Array
+ allowed_file_types?: Array
+ allowed_file_upload_methods?: Array
+ config?: {
+ [key: string]: JsonValue2
+ }
+ default?: JsonValue2
+ description?: string
+ enabled?: boolean
+ hide?: boolean
+ icon?: string | null
+ icon_background?: string | null
+ json_schema?:
+ | string
+ | {
+ [key: string]: JsonValue2
+ }
+ | null
+ label: string
+ max_length?: number | null
+ options?: Array
+ required?: boolean
+ type?: string
+ variable: string
+ [key: string]: unknown
+}
+
export type AgentFileUploadFeatureConfig = {
allowed_file_extensions?: Array
allowed_file_types?: Array
@@ -1592,11 +1934,71 @@ export type FormInputConfig =
type: 'file-list'
} & FileListInputConfig)
-export type JsonValue2 = unknown
+export type ToolProviderType =
+ | 'api'
+ | 'app'
+ | 'builtin'
+ | 'dataset-retrieval'
+ | 'mcp'
+ | 'plugin'
+ | 'workflow'
-export type FileType = 'audio' | 'custom' | 'document' | 'image' | 'video'
+export type AppDatasetReferenceResponse = {
+ enabled?: boolean
+ id?: string
+ [key: string]: unknown
+}
-export type FileTransferMethod = 'datasource_file' | 'local_file' | 'remote_url' | 'tool_file'
+export type AppLegacySensitiveWordToolResponse = {
+ canned_response: string
+ enabled: boolean
+ words: Array
+ [key: string]: unknown
+}
+
+export type AppDatasetItemResponse = {
+ dataset: AppDatasetReferenceResponse
+ [key: string]: unknown
+}
+
+export type AppMetadataConditionResponse = {
+ comparison_operator:
+ | '<'
+ | '='
+ | '>'
+ | 'after'
+ | 'before'
+ | 'contains'
+ | 'empty'
+ | 'end with'
+ | 'in'
+ | 'is'
+ | 'is not'
+ | 'not contains'
+ | 'not empty'
+ | 'not in'
+ | 'start with'
+ | '≠'
+ | '≤'
+ | '≥'
+ id?: string
+ metadata_id?: string
+ name: string
+ value?: string | Array | number | number | null
+ [key: string]: unknown
+}
+
+export type AppKeywordSettingResponse = {
+ keyword_weight: number
+ [key: string]: unknown
+}
+
+export type AppVectorSettingResponse = {
+ embedding_model_name: string
+ embedding_provider_name: string
+ vector_weight: number
+ [key: string]: unknown
+}
export type AgentFileUploadImageFeatureConfig = {
enabled?: boolean
@@ -1642,15 +2044,6 @@ export type AgentSoulDifyToolCredentialRef = {
type?: 'provider' | 'tool'
}
-export type ToolProviderType =
- | 'api'
- | 'app'
- | 'builtin'
- | 'dataset-retrieval'
- | 'mcp'
- | 'plugin'
- | 'workflow'
-
export type OutputErrorStrategy = 'default_value' | 'fail_branch' | 'stop'
export type DeclaredOutputRetryConfig = {
@@ -1772,44 +2165,44 @@ export type AgentAppPaginationWritable = {
}
export type AgentAppDetailWithSiteWritable = {
- access_mode?: string | null
+ access_mode: WebAppAccessMode | null
access_ready?: boolean
- api_base_url?: string | null
+ api_base_url: string
app_id?: string | null
backing_app_id?: string | null
bound_agent_id?: string | null
- created_at?: number | null
- created_by?: string | null
+ created_at: number
+ created_by: string | null
debug_conversation_has_messages?: boolean
debug_conversation_id?: string | null
debug_conversation_message_count?: number
- deleted_tools?: Array
- description?: string | null
+ deleted_tools: Array
+ description: string
enable_api: boolean
enable_site: boolean
hidden_app_backed?: boolean
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
id: string
- maintainer?: string | null
- max_active_requests?: number | null
- mode: string
- model_config?: AppModelConfigResponse | null
+ maintainer: string | null
+ max_active_requests: number | null
+ mode: AppMode
+ model_config: AppModelConfigResponse | null
name: string
permission_keys: Array
role?: string | null
- site?: AppDetailSiteResponseWritable | null
- tags?: Array
- tracing?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
- workflow?: WorkflowPartial | null
+ site: AppDetailSiteResponseWritable | null
+ tags: Array
+ tracing: string | null
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
+ workflow: WorkflowPartial | null
}
export type AgentAppPartialWritable = {
- access_mode?: string | null
+ access_mode?: WebAppAccessMode | null
active_config_is_published?: boolean
app_id?: string | null
author_name?: string | null
@@ -1824,12 +2217,12 @@ export type AgentAppPartialWritable = {
hidden_app_backed?: boolean
icon?: string | null
icon_background?: string | null
- icon_type?: string | null
+ icon_type?: IconType | null
id: string
is_starred?: boolean
maintainer?: string | null
max_active_requests?: number | null
- mode: string
+ mode: AppMode
model_config?: ModelConfigPartial | null
name: string
permission_keys: Array
@@ -1845,30 +2238,30 @@ export type AgentAppPartialWritable = {
}
export type AppDetailSiteResponseWritable = {
- access_token?: string | null
- app_base_url?: string | null
- chat_color_theme?: string | null
- chat_color_theme_inverted?: boolean | null
- code?: string | null
- copyright?: string | null
- created_at?: number | null
- created_by?: string | null
- custom_disclaimer?: string | null
- customize_domain?: string | null
- customize_token_strategy?: string | null
- default_language?: string | null
- description?: string | null
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | IconType | null
- input_placeholder?: string | null
- privacy_policy?: string | null
- prompt_public?: boolean | null
- show_workflow_steps?: boolean | null
- title?: string | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
+ access_token: string | null
+ app_base_url: string
+ chat_color_theme: string | null
+ chat_color_theme_inverted: boolean
+ code: string | null
+ copyright: string | null
+ created_at: number
+ created_by: string | null
+ custom_disclaimer: string
+ customize_domain: string | null
+ customize_token_strategy: CustomizeTokenStrategy
+ default_language: string
+ description: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
+ input_placeholder: string | null
+ privacy_policy: string | null
+ prompt_public: boolean
+ show_workflow_steps: boolean
+ title: string
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
}
export type GetAgentData = {
diff --git a/packages/contracts/generated/api/console/agent/zod.gen.ts b/packages/contracts/generated/api/console/agent/zod.gen.ts
index 4377a36429e..a596469f1f5 100644
--- a/packages/contracts/generated/api/console/agent/zod.gen.ts
+++ b/packages/contracts/generated/api/console/agent/zod.gen.ts
@@ -266,6 +266,11 @@ export const zAgentAppCopyPayload = z.object({
role: z.string().max(255).nullish(),
})
+/**
+ * WebAppAccessMode
+ */
+export const zWebAppAccessMode = z.enum(['private', 'private_all', 'public', 'sso_verified'])
+
/**
* DeletedTool
*/
@@ -276,65 +281,18 @@ export const zDeletedTool = z.object({
})
/**
- * AppModelConfigResponse
+ * AppMode
*/
-export const zAppModelConfigResponse = z.object({
- agent_mode: z.unknown().nullish(),
- annotation_reply: z.unknown().nullish(),
- chat_prompt_config: z.unknown().nullish(),
- completion_prompt_config: z.unknown().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- dataset_configs: z.unknown().nullish(),
- dataset_query_variable: z.string().nullish(),
- external_data_tools: z.unknown().nullish(),
- file_upload: z.unknown().nullish(),
- model: z.unknown().nullish(),
- more_like_this: z.unknown().nullish(),
- opening_statement: z.string().nullish(),
- pre_prompt: z.string().nullish(),
- prompt_type: z.string().nullish(),
- retriever_resource: z.unknown().nullish(),
- sensitive_word_avoidance: z.unknown().nullish(),
- speech_to_text: z.unknown().nullish(),
- suggested_questions: z.unknown().nullish(),
- suggested_questions_after_answer: z.unknown().nullish(),
- text_to_speech: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- user_input_form: z.unknown().nullish(),
-})
-
-/**
- * AppDetailSiteResponse
- */
-export const zAppDetailSiteResponse = z.object({
- access_token: z.string().nullish(),
- app_base_url: z.string().nullish(),
- chat_color_theme: z.string().nullish(),
- chat_color_theme_inverted: z.boolean().nullish(),
- code: z.string().nullish(),
- copyright: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- custom_disclaimer: z.string().nullish(),
- customize_domain: z.string().nullish(),
- customize_token_strategy: z.string().nullish(),
- default_language: z.string().nullish(),
- description: z.string().nullish(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.union([z.string(), zIconType]).nullish(),
- icon_url: z.string().nullable(),
- input_placeholder: z.string().nullish(),
- privacy_policy: z.string().nullish(),
- prompt_public: z.boolean().nullish(),
- show_workflow_steps: z.boolean().nullish(),
- title: z.string().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
-})
+export const zAppMode = z.enum([
+ 'advanced-chat',
+ 'agent',
+ 'agent-chat',
+ 'channel',
+ 'chat',
+ 'completion',
+ 'rag-pipeline',
+ 'workflow',
+])
/**
* Tag
@@ -356,47 +314,6 @@ export const zWorkflowPartial = z.object({
updated_by: z.string().nullish(),
})
-/**
- * AgentAppDetailWithSite
- */
-export const zAgentAppDetailWithSite = z.object({
- access_mode: z.string().nullish(),
- access_ready: z.boolean().optional().default(false),
- api_base_url: z.string().nullish(),
- app_id: z.string().nullish(),
- backing_app_id: z.string().nullish(),
- bound_agent_id: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- debug_conversation_has_messages: z.boolean().optional().default(false),
- debug_conversation_id: z.string().nullish(),
- debug_conversation_message_count: z.int().optional().default(0),
- deleted_tools: z.array(zDeletedTool).optional(),
- description: z.string().nullish(),
- enable_api: z.boolean(),
- enable_site: z.boolean(),
- hidden_app_backed: z.boolean().optional().default(false),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
- icon_url: z.string().nullable(),
- id: z.string(),
- maintainer: z.string().nullish(),
- max_active_requests: z.int().nullish(),
- mode: z.string(),
- model_config: zAppModelConfigResponse.nullish(),
- name: z.string(),
- permission_keys: z.array(z.string()),
- role: z.string().nullish(),
- site: zAppDetailSiteResponse.nullish(),
- tags: z.array(zTag).optional(),
- tracing: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
-})
-
/**
* ComposerBindingPayload
*/
@@ -649,7 +566,7 @@ export const zAgentFeatureToggleConfig = z.object({
* AgentTextToSpeechFeatureConfig
*/
export const zAgentTextToSpeechFeatureConfig = z.object({
- autoPlay: z.string().nullish(),
+ autoPlay: z.enum(['disabled', 'enabled']).nullish(),
enabled: z.boolean().optional().default(false),
language: z.string().nullish(),
voice: z.string().nullish(),
@@ -834,18 +751,6 @@ export const zTextToSpeechVoiceResponse = z.object({
*/
export const zTextToSpeechVoiceListResponse = z.array(zTextToSpeechVoiceResponse)
-/**
- * ModelConfigPartial
- */
-export const zModelConfigPartial = z.object({
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- model: z.unknown().nullish(),
- pre_prompt: z.string().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
-})
-
/**
* AgentAppPublishedReferenceResponse
*/
@@ -858,55 +763,72 @@ export const zAgentAppPublishedReferenceResponse = z.object({
})
/**
- * AgentAppPartial
+ * AppAnnotationReplyDisabledResponse
*/
-export const zAgentAppPartial = z.object({
- access_mode: z.string().nullish(),
- active_config_is_published: z.boolean().optional().default(false),
- app_id: z.string().nullish(),
- author_name: z.string().nullish(),
- backing_app_id: z.string().nullish(),
- bound_agent_id: z.string().nullish(),
- create_user_name: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- debug_conversation_id: z.string().nullish(),
- description: z.string().nullish(),
- has_draft_trigger: z.boolean().nullish(),
- hidden_app_backed: z.boolean().optional().default(false),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
- icon_url: z.string().nullable(),
- id: z.string(),
- is_starred: z.boolean().optional().default(false),
- maintainer: z.string().nullish(),
- max_active_requests: z.int().nullish(),
- mode: z.string(),
- model_config: zModelConfigPartial.nullish(),
- name: z.string(),
- permission_keys: z.array(z.string()),
- published_reference_count: z.int().optional().default(0),
- published_references: z.array(zAgentAppPublishedReferenceResponse).optional(),
- reference_count: z.int().nullish(),
- role: z.string().nullish(),
- tags: z.array(zTag).optional(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
+export const zAppAnnotationReplyDisabledResponse = z.object({
+ enabled: z.literal(false),
})
/**
- * AgentAppPagination
+ * AppEnabledConfigResponse
*/
-export const zAgentAppPagination = z.object({
- data: z.array(zAgentAppPartial),
- has_more: z.boolean(),
- limit: z.int(),
- page: z.int(),
- publication_counts: zAgentPublicationCountsResponse,
- total: z.int(),
+export const zAppEnabledConfigResponse = z.object({
+ enabled: z.boolean(),
+})
+
+/**
+ * PromptType
+ *
+ * Prompt configuration type
+ */
+export const zPromptType = z.enum(['advanced', 'simple'])
+
+/**
+ * AppTextToSpeechResponse
+ */
+export const zAppTextToSpeechResponse = z.object({
+ autoPlay: z.enum(['disabled', 'enabled']).optional(),
+ enabled: z.boolean(),
+ language: z.string().optional(),
+ voice: z.string().optional(),
+})
+
+/**
+ * CustomizeTokenStrategy
+ *
+ * Site token customization strategy
+ */
+export const zCustomizeTokenStrategy = z.enum(['allow', 'must', 'not_allow', 'uuid'])
+
+/**
+ * AppDetailSiteResponse
+ */
+export const zAppDetailSiteResponse = z.object({
+ access_token: z.string().nullable(),
+ app_base_url: z.string(),
+ chat_color_theme: z.string().nullable(),
+ chat_color_theme_inverted: z.boolean(),
+ code: z.string().nullable(),
+ copyright: z.string().nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ custom_disclaimer: z.string(),
+ customize_domain: z.string().nullable(),
+ customize_token_strategy: zCustomizeTokenStrategy,
+ default_language: z.string(),
+ description: z.string().nullable(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
+ icon_url: z.string().nullable(),
+ input_placeholder: z.string().nullable(),
+ privacy_policy: z.string().nullable(),
+ prompt_public: z.boolean(),
+ show_workflow_steps: z.boolean(),
+ title: z.string(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
})
/**
@@ -1412,6 +1334,379 @@ export const zAgentConfigRevisionResponse = z.object({
version_note: z.string().nullish(),
})
+/**
+ * AppAgentPromptResponse
+ */
+export const zAppAgentPromptResponse = z.object({
+ first_prompt: z.string().optional(),
+ next_iteration: z.string().optional(),
+})
+
+/**
+ * PlanningStrategy
+ */
+export const zPlanningStrategy = z.enum(['function_call', 'react', 'react_router', 'router'])
+
+/**
+ * AppEmbeddingModelResponse
+ */
+export const zAppEmbeddingModelResponse = z.object({
+ embedding_model_name: z.string(),
+ embedding_provider_name: z.string(),
+})
+
+/**
+ * AppAnnotationReplyEnabledResponse
+ */
+export const zAppAnnotationReplyEnabledResponse = z.object({
+ embedding_model: zAppEmbeddingModelResponse,
+ enabled: z.literal(true),
+ id: z.string(),
+ score_threshold: z.number(),
+})
+
+/**
+ * AppChatPromptMessageResponse
+ */
+export const zAppChatPromptMessageResponse = z.object({
+ role: z.string(),
+ text: z.string(),
+})
+
+/**
+ * AppChatPromptConfigResponse
+ */
+export const zAppChatPromptConfigResponse = z.object({
+ prompt: z.array(zAppChatPromptMessageResponse).optional(),
+})
+
+/**
+ * AppConversationHistoriesRoleResponse
+ */
+export const zAppConversationHistoriesRoleResponse = z.object({
+ assistant_prefix: z.string(),
+ user_prefix: z.string(),
+})
+
+/**
+ * AppCompletionPromptTextResponse
+ */
+export const zAppCompletionPromptTextResponse = z.object({
+ text: z.string(),
+})
+
+/**
+ * AppCompletionPromptConfigResponse
+ */
+export const zAppCompletionPromptConfigResponse = z.object({
+ conversation_histories_role: zAppConversationHistoriesRoleResponse.optional(),
+ prompt: zAppCompletionPromptTextResponse.optional(),
+})
+
+/**
+ * RerankMode
+ */
+export const zRerankMode = z.enum(['reranking_model', 'weighted_score'])
+
+/**
+ * AppRerankingModelResponse
+ */
+export const zAppRerankingModelResponse = z.object({
+ reranking_model_name: z.string().optional(),
+ reranking_provider_name: z.string().optional(),
+})
+
+export const zJsonValue2 = z.unknown()
+
+/**
+ * AppEnabledExternalDataToolResponse
+ */
+export const zAppEnabledExternalDataToolResponse = z.object({
+ config: z.record(z.string(), zJsonValue2),
+ enabled: z.literal(true),
+ icon: z.string().optional(),
+ icon_background: z.string().optional(),
+ label: z.string().optional(),
+ type: z.string(),
+ variable: z.string(),
+})
+
+/**
+ * AppDisabledExternalDataToolResponse
+ */
+export const zAppDisabledExternalDataToolResponse = z.object({
+ config: z.record(z.string(), zJsonValue2).optional(),
+ enabled: z.literal(false),
+ icon: z.string().optional(),
+ icon_background: z.string().optional(),
+ label: z.string().optional(),
+ type: z.string().optional(),
+ variable: z.string().optional(),
+})
+
+/**
+ * AppSensitiveWordAvoidanceResponse
+ */
+export const zAppSensitiveWordAvoidanceResponse = z.object({
+ config: z.record(z.string(), zJsonValue2).optional(),
+ configs: z.array(zJsonValue2).optional(),
+ enabled: z.boolean(),
+ type: z.string().optional(),
+})
+
+/**
+ * HumanInputFormSubmissionData
+ */
+export const zHumanInputFormSubmissionData = z.object({
+ action_id: z.string(),
+ action_text: z.string(),
+ node_id: z.string(),
+ node_title: z.string(),
+ rendered_content: z.string(),
+ submitted_data: z.record(z.string(), zJsonValue2).nullish(),
+})
+
+/**
+ * AppLegacyGoogleSearchToolResponse
+ */
+export const zAppLegacyGoogleSearchToolResponse = z.object({
+ google_search: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppLegacyWebReaderToolResponse
+ */
+export const zAppLegacyWebReaderToolResponse = z.object({
+ web_reader: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppLegacyWikipediaToolResponse
+ */
+export const zAppLegacyWikipediaToolResponse = z.object({
+ wikipedia: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppLegacyCurrentDatetimeToolResponse
+ */
+export const zAppLegacyCurrentDatetimeToolResponse = z.object({
+ current_datetime: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * FileType
+ */
+export const zFileType = z.enum(['audio', 'custom', 'document', 'image', 'video'])
+
+/**
+ * FileTransferMethod
+ */
+export const zFileTransferMethod = z.enum([
+ 'datasource_file',
+ 'local_file',
+ 'remote_url',
+ 'tool_file',
+])
+
+/**
+ * AppImageUploadResponse
+ */
+export const zAppImageUploadResponse = z.object({
+ detail: z.enum(['high', 'low']).nullish(),
+ enabled: z.boolean().optional(),
+ number_limits: z.int().optional(),
+ transfer_methods: z.array(zFileTransferMethod).optional(),
+})
+
+/**
+ * AppFileUploadResponse
+ */
+export const zAppFileUploadResponse = z.object({
+ allowed_file_extensions: z.array(z.string()).optional(),
+ allowed_file_types: z.array(zFileType).optional(),
+ allowed_file_upload_methods: z.array(zFileTransferMethod).optional(),
+ enabled: z.boolean().optional(),
+ image: zAppImageUploadResponse.optional(),
+ number_limits: z.int().optional(),
+})
+
+/**
+ * LLMMode
+ *
+ * Enum class for large language model mode.
+ */
+export const zLlmMode = z.enum(['chat', 'completion'])
+
+/**
+ * AppModelSelectionResponse
+ */
+export const zAppModelSelectionResponse = z.object({
+ completion_params: z.record(z.string(), zJsonValue2).optional(),
+ mode: z.union([zLlmMode, z.literal('')]).optional(),
+ name: z.string().optional(),
+ provider: z.string().optional(),
+})
+
+/**
+ * ModelConfigPartial
+ */
+export const zModelConfigPartial = z.object({
+ created_at: z.int().nullish(),
+ created_by: z.string().nullish(),
+ model: zAppModelSelectionResponse.nullish(),
+ pre_prompt: z.string().nullish(),
+ updated_at: z.int().nullish(),
+ updated_by: z.string().nullish(),
+})
+
+/**
+ * AgentAppPartial
+ */
+export const zAgentAppPartial = z.object({
+ access_mode: zWebAppAccessMode.nullish(),
+ active_config_is_published: z.boolean().optional().default(false),
+ app_id: z.string().nullish(),
+ author_name: z.string().nullish(),
+ backing_app_id: z.string().nullish(),
+ bound_agent_id: z.string().nullish(),
+ create_user_name: z.string().nullish(),
+ created_at: z.int().nullish(),
+ created_by: z.string().nullish(),
+ debug_conversation_id: z.string().nullish(),
+ description: z.string().nullish(),
+ has_draft_trigger: z.boolean().nullish(),
+ hidden_app_backed: z.boolean().optional().default(false),
+ icon: z.string().nullish(),
+ icon_background: z.string().nullish(),
+ icon_type: zIconType.nullish(),
+ icon_url: z.string().nullable(),
+ id: z.string(),
+ is_starred: z.boolean().optional().default(false),
+ maintainer: z.string().nullish(),
+ max_active_requests: z.int().nullish(),
+ mode: zAppMode,
+ model_config: zModelConfigPartial.nullish(),
+ name: z.string(),
+ permission_keys: z.array(z.string()),
+ published_reference_count: z.int().optional().default(0),
+ published_references: z.array(zAgentAppPublishedReferenceResponse).optional(),
+ reference_count: z.int().nullish(),
+ role: z.string().nullish(),
+ tags: z.array(zTag).optional(),
+ updated_at: z.int().nullish(),
+ updated_by: z.string().nullish(),
+ use_icon_as_answer_icon: z.boolean().nullish(),
+ workflow: zWorkflowPartial.nullish(),
+})
+
+/**
+ * AgentAppPagination
+ */
+export const zAgentAppPagination = z.object({
+ data: z.array(zAgentAppPartial),
+ has_more: z.boolean(),
+ limit: z.int(),
+ page: z.int(),
+ publication_counts: zAgentPublicationCountsResponse,
+ total: z.int(),
+})
+
+/**
+ * AppSuggestedQuestionsAfterAnswerResponse
+ */
+export const zAppSuggestedQuestionsAfterAnswerResponse = z.object({
+ enabled: z.boolean(),
+ model: zAppModelSelectionResponse.optional(),
+ prompt: z.string().optional(),
+})
+
+/**
+ * AppUserInputFormConfigResponse
+ */
+export const zAppUserInputFormConfigResponse = z.object({
+ allowed_file_extensions: z.array(z.string()).optional(),
+ allowed_file_types: z.array(zFileType).optional(),
+ allowed_file_upload_methods: z.array(zFileTransferMethod).optional(),
+ config: z.record(z.string(), zJsonValue2).optional(),
+ default: zJsonValue2.optional(),
+ description: z.string().optional(),
+ enabled: z.boolean().optional(),
+ hide: z.boolean().optional(),
+ icon: z.string().nullish(),
+ icon_background: z.string().nullish(),
+ json_schema: z.union([z.string(), z.record(z.string(), zJsonValue2)]).nullish(),
+ label: z.string(),
+ max_length: z.int().nullish(),
+ options: z.array(z.string()).optional(),
+ required: z.boolean().optional(),
+ type: z.string().optional(),
+ variable: z.string(),
+})
+
+/**
+ * AppTextInputFormResponse
+ */
+export const zAppTextInputFormResponse = z.object({
+ 'text-input': zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppSelectFormResponse
+ */
+export const zAppSelectFormResponse = z.object({
+ select: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppParagraphFormResponse
+ */
+export const zAppParagraphFormResponse = z.object({
+ paragraph: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppNumberFormResponse
+ */
+export const zAppNumberFormResponse = z.object({
+ number: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppCheckboxFormResponse
+ */
+export const zAppCheckboxFormResponse = z.object({
+ checkbox: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppFileFormResponse
+ */
+export const zAppFileFormResponse = z.object({
+ file: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppFileListFormResponse
+ */
+export const zAppFileListFormResponse = z.object({
+ 'file-list': zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppExternalDataToolFormResponse
+ */
+export const zAppExternalDataToolFormResponse = z.object({
+ external_data_tool: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppJsonObjectFormResponse
+ */
+export const zAppJsonObjectFormResponse = z.object({
+ json_object: zAppUserInputFormConfigResponse,
+})
+
/**
* AgentEnvVariableConfig
*/
@@ -1790,34 +2085,276 @@ export const zAgentAppFeaturesPayload = z.object({
text_to_speech: zAgentTextToSpeechFeatureConfig.nullish(),
})
-export const zJsonValue2 = z.unknown()
+/**
+ * ToolProviderType
+ *
+ * Enum class for tool provider
+ */
+export const zToolProviderType = z.enum([
+ 'api',
+ 'app',
+ 'builtin',
+ 'dataset-retrieval',
+ 'mcp',
+ 'plugin',
+ 'workflow',
+])
/**
- * HumanInputFormSubmissionData
+ * AppProviderAgentToolResponse
*/
-export const zHumanInputFormSubmissionData = z.object({
- action_id: z.string(),
- action_text: z.string(),
- node_id: z.string(),
- node_title: z.string(),
- rendered_content: z.string(),
- submitted_data: z.record(z.string(), zJsonValue2).nullish(),
+export const zAppProviderAgentToolResponse = z.object({
+ credential_id: z.string().nullish(),
+ enabled: z.boolean().optional(),
+ isDeleted: z.boolean().optional(),
+ notAuthor: z.boolean().optional(),
+ plugin_unique_identifier: z.string().nullish(),
+ provider_id: z.string(),
+ provider_name: z.string().optional(),
+ provider_type: zToolProviderType,
+ tool_label: z.string().optional(),
+ tool_name: z.string(),
+ tool_parameters: z.record(z.string(), zJsonValue2),
})
/**
- * FileType
+ * AppDatasetReferenceResponse
*/
-export const zFileType = z.enum(['audio', 'custom', 'document', 'image', 'video'])
+export const zAppDatasetReferenceResponse = z.object({
+ enabled: z.boolean().optional(),
+ id: z.string().optional(),
+})
/**
- * FileTransferMethod
+ * AppLegacyDatasetToolResponse
*/
-export const zFileTransferMethod = z.enum([
- 'datasource_file',
- 'local_file',
- 'remote_url',
- 'tool_file',
-])
+export const zAppLegacyDatasetToolResponse = z.object({
+ dataset: zAppDatasetReferenceResponse,
+})
+
+/**
+ * AppLegacySensitiveWordToolResponse
+ */
+export const zAppLegacySensitiveWordToolResponse = z.object({
+ canned_response: z.string(),
+ enabled: z.boolean(),
+ words: z.array(z.string()),
+})
+
+/**
+ * AppLegacySensitiveWordToolResponseItem
+ */
+export const zAppLegacySensitiveWordToolResponseItem = z.object({
+ 'sensitive-word-avoidance': zAppLegacySensitiveWordToolResponse,
+})
+
+/**
+ * AppAgentModeResponse
+ */
+export const zAppAgentModeResponse = z.object({
+ enabled: z.boolean(),
+ max_iteration: z.int().optional(),
+ prompt: z.union([zAppAgentPromptResponse, z.string()]).nullish(),
+ strategy: z.union([zPlanningStrategy, z.enum(['cot', 'function-calling'])]).nullish(),
+ tools: z
+ .array(
+ z.union([
+ zAppProviderAgentToolResponse,
+ zAppLegacyDatasetToolResponse,
+ zAppLegacyGoogleSearchToolResponse,
+ zAppLegacyWebReaderToolResponse,
+ zAppLegacyWikipediaToolResponse,
+ zAppLegacyCurrentDatetimeToolResponse,
+ zAppLegacySensitiveWordToolResponseItem,
+ ]),
+ )
+ .optional(),
+})
+
+/**
+ * AppDatasetItemResponse
+ */
+export const zAppDatasetItemResponse = z.object({
+ dataset: zAppDatasetReferenceResponse,
+})
+
+/**
+ * AppDatasetListResponse
+ */
+export const zAppDatasetListResponse = z.object({
+ datasets: z.array(zAppDatasetItemResponse),
+ strategy: z.string().optional(),
+})
+
+/**
+ * AppMetadataConditionResponse
+ */
+export const zAppMetadataConditionResponse = z.object({
+ comparison_operator: z.enum([
+ '<',
+ '=',
+ '>',
+ 'after',
+ 'before',
+ 'contains',
+ 'empty',
+ 'end with',
+ 'in',
+ 'is',
+ 'is not',
+ 'not contains',
+ 'not empty',
+ 'not in',
+ 'start with',
+ '≠',
+ '≤',
+ '≥',
+ ]),
+ id: z.string().optional(),
+ metadata_id: z.string().optional(),
+ name: z.string(),
+ value: z.union([z.string(), z.array(z.string()), z.int(), z.number()]).nullish(),
+})
+
+/**
+ * AppMetadataFilteringConditionsResponse
+ */
+export const zAppMetadataFilteringConditionsResponse = z.object({
+ conditions: z.array(zAppMetadataConditionResponse).nullish(),
+ logical_operator: z.enum(['and', 'or']).nullish(),
+})
+
+/**
+ * AppKeywordSettingResponse
+ */
+export const zAppKeywordSettingResponse = z.object({
+ keyword_weight: z.number(),
+})
+
+/**
+ * AppVectorSettingResponse
+ */
+export const zAppVectorSettingResponse = z.object({
+ embedding_model_name: z.string(),
+ embedding_provider_name: z.string(),
+ vector_weight: z.number(),
+})
+
+/**
+ * AppWeightsResponse
+ */
+export const zAppWeightsResponse = z.object({
+ keyword_setting: zAppKeywordSettingResponse,
+ vector_setting: zAppVectorSettingResponse,
+ weight_type: z.enum(['customized', 'keyword_first', 'semantic_first']).optional(),
+})
+
+/**
+ * AppDatasetConfigsResponse
+ */
+export const zAppDatasetConfigsResponse = z.object({
+ datasets: zAppDatasetListResponse.optional(),
+ metadata_filtering_conditions: zAppMetadataFilteringConditionsResponse.nullish(),
+ metadata_filtering_mode: z.enum(['automatic', 'disabled', 'manual']).optional(),
+ metadata_model_config: zAppModelSelectionResponse.nullish(),
+ reranking_enable: z.boolean().optional(),
+ reranking_enabled: z.boolean().optional(),
+ reranking_mode: zRerankMode.optional(),
+ reranking_model: zAppRerankingModelResponse.nullish(),
+ retrieval_model: z.enum(['multiple', 'single']),
+ score_threshold: z.number().nullish(),
+ score_threshold_enabled: z.boolean().optional(),
+ top_k: z.int().optional(),
+ weights: zAppWeightsResponse.nullish(),
+})
+
+/**
+ * AppModelConfigResponse
+ */
+export const zAppModelConfigResponse = z.object({
+ agent_mode: zAppAgentModeResponse,
+ annotation_reply: z.union([
+ zAppAnnotationReplyEnabledResponse,
+ zAppAnnotationReplyDisabledResponse,
+ ]),
+ chat_prompt_config: zAppChatPromptConfigResponse,
+ completion_prompt_config: zAppCompletionPromptConfigResponse,
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ dataset_configs: zAppDatasetConfigsResponse,
+ dataset_query_variable: z.string().nullable(),
+ external_data_tools: z.array(
+ z.union([zAppEnabledExternalDataToolResponse, zAppDisabledExternalDataToolResponse]),
+ ),
+ file_upload: zAppFileUploadResponse,
+ model: zAppModelSelectionResponse,
+ more_like_this: zAppEnabledConfigResponse,
+ opening_statement: z.string().nullable(),
+ pre_prompt: z.string().nullable(),
+ prompt_type: zPromptType,
+ retriever_resource: zAppEnabledConfigResponse,
+ sensitive_word_avoidance: zAppSensitiveWordAvoidanceResponse,
+ speech_to_text: zAppEnabledConfigResponse,
+ suggested_questions: z.array(z.string()),
+ suggested_questions_after_answer: zAppSuggestedQuestionsAfterAnswerResponse,
+ text_to_speech: zAppTextToSpeechResponse,
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ user_input_form: z.array(
+ z.union([
+ zAppTextInputFormResponse,
+ zAppSelectFormResponse,
+ zAppParagraphFormResponse,
+ zAppNumberFormResponse,
+ zAppCheckboxFormResponse,
+ zAppFileFormResponse,
+ zAppFileListFormResponse,
+ zAppExternalDataToolFormResponse,
+ zAppJsonObjectFormResponse,
+ ]),
+ ),
+})
+
+/**
+ * AgentAppDetailWithSite
+ */
+export const zAgentAppDetailWithSite = z.object({
+ access_mode: zWebAppAccessMode.nullable(),
+ access_ready: z.boolean().optional().default(false),
+ api_base_url: z.string(),
+ app_id: z.string().nullish(),
+ backing_app_id: z.string().nullish(),
+ bound_agent_id: z.string().nullish(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ debug_conversation_has_messages: z.boolean().optional().default(false),
+ debug_conversation_id: z.string().nullish(),
+ debug_conversation_message_count: z.int().optional().default(0),
+ deleted_tools: z.array(zDeletedTool),
+ description: z.string(),
+ enable_api: z.boolean(),
+ enable_site: z.boolean(),
+ hidden_app_backed: z.boolean().optional().default(false),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
+ icon_url: z.string().nullable(),
+ id: z.string(),
+ maintainer: z.string().nullable(),
+ max_active_requests: z.int().nullable(),
+ mode: zAppMode,
+ model_config: zAppModelConfigResponse.nullable(),
+ name: z.string(),
+ permission_keys: z.array(z.string()),
+ role: z.string().nullish(),
+ site: zAppDetailSiteResponse.nullable(),
+ tags: z.array(zTag),
+ tracing: z.string().nullable(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
+ workflow: zWorkflowPartial.nullable(),
+})
/**
* AgentFileUploadImageFeatureConfig
@@ -1930,21 +2467,6 @@ export const zAgentSoulDifyToolCredentialRef = z.object({
type: z.enum(['provider', 'tool']).optional().default('tool'),
})
-/**
- * ToolProviderType
- *
- * Enum class for tool provider
- */
-export const zToolProviderType = z.enum([
- 'api',
- 'app',
- 'builtin',
- 'dataset-retrieval',
- 'mcp',
- 'plugin',
- 'workflow',
-])
-
/**
* AgentSoulDifyToolConfig
*
@@ -2508,7 +3030,7 @@ export const zMessageInfiniteScrollPaginationResponse = z.object({
* AgentAppPartial
*/
export const zAgentAppPartialWritable = z.object({
- access_mode: z.string().nullish(),
+ access_mode: zWebAppAccessMode.nullish(),
active_config_is_published: z.boolean().optional().default(false),
app_id: z.string().nullish(),
author_name: z.string().nullish(),
@@ -2523,12 +3045,12 @@ export const zAgentAppPartialWritable = z.object({
hidden_app_backed: z.boolean().optional().default(false),
icon: z.string().nullish(),
icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
+ icon_type: zIconType.nullish(),
id: z.string(),
is_starred: z.boolean().optional().default(false),
maintainer: z.string().nullish(),
max_active_requests: z.int().nullish(),
- mode: z.string(),
+ mode: zAppMode,
model_config: zModelConfigPartial.nullish(),
name: z.string(),
permission_keys: z.array(z.string()),
@@ -2559,70 +3081,70 @@ export const zAgentAppPaginationWritable = z.object({
* AppDetailSiteResponse
*/
export const zAppDetailSiteResponseWritable = z.object({
- access_token: z.string().nullish(),
- app_base_url: z.string().nullish(),
- chat_color_theme: z.string().nullish(),
- chat_color_theme_inverted: z.boolean().nullish(),
- code: z.string().nullish(),
- copyright: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- custom_disclaimer: z.string().nullish(),
- customize_domain: z.string().nullish(),
- customize_token_strategy: z.string().nullish(),
- default_language: z.string().nullish(),
- description: z.string().nullish(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.union([z.string(), zIconType]).nullish(),
- input_placeholder: z.string().nullish(),
- privacy_policy: z.string().nullish(),
- prompt_public: z.boolean().nullish(),
- show_workflow_steps: z.boolean().nullish(),
- title: z.string().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
+ access_token: z.string().nullable(),
+ app_base_url: z.string(),
+ chat_color_theme: z.string().nullable(),
+ chat_color_theme_inverted: z.boolean(),
+ code: z.string().nullable(),
+ copyright: z.string().nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ custom_disclaimer: z.string(),
+ customize_domain: z.string().nullable(),
+ customize_token_strategy: zCustomizeTokenStrategy,
+ default_language: z.string(),
+ description: z.string().nullable(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
+ input_placeholder: z.string().nullable(),
+ privacy_policy: z.string().nullable(),
+ prompt_public: z.boolean(),
+ show_workflow_steps: z.boolean(),
+ title: z.string(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
})
/**
* AgentAppDetailWithSite
*/
export const zAgentAppDetailWithSiteWritable = z.object({
- access_mode: z.string().nullish(),
+ access_mode: zWebAppAccessMode.nullable(),
access_ready: z.boolean().optional().default(false),
- api_base_url: z.string().nullish(),
+ api_base_url: z.string(),
app_id: z.string().nullish(),
backing_app_id: z.string().nullish(),
bound_agent_id: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
debug_conversation_has_messages: z.boolean().optional().default(false),
debug_conversation_id: z.string().nullish(),
debug_conversation_message_count: z.int().optional().default(0),
- deleted_tools: z.array(zDeletedTool).optional(),
- description: z.string().nullish(),
+ deleted_tools: z.array(zDeletedTool),
+ description: z.string(),
enable_api: z.boolean(),
enable_site: z.boolean(),
hidden_app_backed: z.boolean().optional().default(false),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
id: z.string(),
- maintainer: z.string().nullish(),
- max_active_requests: z.int().nullish(),
- mode: z.string(),
- model_config: zAppModelConfigResponse.nullish(),
+ maintainer: z.string().nullable(),
+ max_active_requests: z.int().nullable(),
+ mode: zAppMode,
+ model_config: zAppModelConfigResponse.nullable(),
name: z.string(),
permission_keys: z.array(z.string()),
role: z.string().nullish(),
- site: zAppDetailSiteResponseWritable.nullish(),
- tags: z.array(zTag).optional(),
- tracing: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
+ site: zAppDetailSiteResponseWritable.nullable(),
+ tags: z.array(zTag),
+ tracing: z.string().nullable(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
+ workflow: zWorkflowPartial.nullable(),
})
export const zGetAgentQuery = z.object({
diff --git a/packages/contracts/generated/api/console/apps/types.gen.ts b/packages/contracts/generated/api/console/apps/types.gen.ts
index 76366c70c03..c2eac7080ea 100644
--- a/packages/contracts/generated/api/console/apps/types.gen.ts
+++ b/packages/contracts/generated/api/console/apps/types.gen.ts
@@ -22,34 +22,34 @@ export type CreateAppPayload = {
}
export type AppDetailWithSite = {
- access_mode?: string | null
- api_base_url?: string | null
- app_id?: string | null
- bound_agent_id?: string | null
- created_at?: number | null
- created_by?: string | null
- deleted_tools?: Array
- description?: string | null
+ access_mode: WebAppAccessMode | null
+ api_base_url: string
+ app_id: string | null
+ bound_agent_id: string | null
+ created_at: number
+ created_by: string | null
+ deleted_tools: Array
+ description: string
enable_api: boolean
enable_site: boolean
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
readonly icon_url: string | null
id: string
- maintainer?: string | null
- max_active_requests?: number | null
- mode: string
- model_config?: AppModelConfigResponse | null
+ maintainer: string | null
+ max_active_requests: number | null
+ mode: AppMode
+ model_config: AppModelConfigResponse | null
name: string
- permission_keys?: Array
- site?: AppDetailSiteResponse | null
- tags?: Array
- tracing?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
- workflow?: WorkflowPartial | null
+ permission_keys: Array
+ site: AppDetailSiteResponse | null
+ tags: Array
+ tracing: string | null
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
+ workflow: WorkflowPartial | null
}
export type AppImportPayload = {
@@ -66,7 +66,7 @@ export type AppImportPayload = {
export type Import = {
app_id?: string | null
- app_mode?: string | null
+ app_mode?: AppMode | null
current_dsl_version?: string
error?: string
id: string
@@ -362,26 +362,26 @@ export type AppApiStatusPayload = {
}
export type AppDetail = {
- access_mode?: string | null
- created_at?: number | null
- created_by?: string | null
- description?: string | null
+ access_mode: WebAppAccessMode | null
+ created_at: number
+ created_by: string | null
+ description: string
enable_api: boolean
enable_site: boolean
- icon?: string | null
- icon_background?: string | null
+ icon: string | null
+ icon_background: string | null
id: string
- maintainer?: string | null
- mode: string
- model_config?: AppModelConfigResponse | null
+ maintainer: string | null
+ mode: AppMode
+ model_config: AppModelConfigResponse | null
name: string
- permission_keys?: Array
- tags?: Array
- tracing?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
- workflow?: WorkflowPartial | null
+ permission_keys: Array
+ tags: Array
+ tracing: string | null
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
+ workflow: WorkflowPartial | null
}
export type AudioTranscriptResponse = {
@@ -488,7 +488,7 @@ export type CopyAppPayload = {
export type AppImportResponse = {
app_id?: string | null
- app_mode?: string | null
+ app_mode?: AppMode | null
current_dsl_version: string
error?: string
id: string
@@ -1199,7 +1199,7 @@ export type ApiKeyItem = {
}
export type AppPartial = {
- access_mode?: string | null
+ access_mode?: WebAppAccessMode | null
app_id?: string | null
author_name?: string | null
bound_agent_id?: string | null
@@ -1210,13 +1210,13 @@ export type AppPartial = {
has_draft_trigger?: boolean | null
icon?: string | null
icon_background?: string | null
- icon_type?: string | null
+ icon_type?: IconType | null
readonly icon_url: string | null
id: string
is_starred?: boolean
maintainer?: string | null
max_active_requests?: number | null
- mode: string
+ mode: AppMode
model_config?: ModelConfigPartial | null
name: string
permission_keys?: Array
@@ -1229,65 +1229,89 @@ export type AppPartial = {
export type IconType = 'emoji' | 'image' | 'link'
+export type WebAppAccessMode = 'private' | 'private_all' | 'public' | 'sso_verified'
+
export type DeletedTool = {
provider_id: string
tool_name: string
type: string
}
+export type AppMode =
+ | 'advanced-chat'
+ | 'agent'
+ | 'agent-chat'
+ | 'channel'
+ | 'chat'
+ | 'completion'
+ | 'rag-pipeline'
+ | 'workflow'
+
export type AppModelConfigResponse = {
- agent_mode?: unknown | null
- annotation_reply?: unknown | null
- chat_prompt_config?: unknown | null
- completion_prompt_config?: unknown | null
- created_at?: number | null
- created_by?: string | null
- dataset_configs?: unknown | null
- dataset_query_variable?: string | null
- external_data_tools?: unknown | null
- file_upload?: unknown | null
- model?: unknown | null
- more_like_this?: unknown | null
- opening_statement?: string | null
- pre_prompt?: string | null
- prompt_type?: string | null
- retriever_resource?: unknown | null
- sensitive_word_avoidance?: unknown | null
- speech_to_text?: unknown | null
- suggested_questions?: unknown | null
- suggested_questions_after_answer?: unknown | null
- text_to_speech?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- user_input_form?: unknown | null
+ agent_mode: AppAgentModeResponse
+ annotation_reply: AppAnnotationReplyEnabledResponse | AppAnnotationReplyDisabledResponse
+ chat_prompt_config: AppChatPromptConfigResponse
+ completion_prompt_config: AppCompletionPromptConfigResponse
+ created_at: number
+ created_by: string | null
+ dataset_configs: AppDatasetConfigsResponse
+ dataset_query_variable: string | null
+ external_data_tools: Array<
+ AppEnabledExternalDataToolResponse | AppDisabledExternalDataToolResponse
+ >
+ file_upload: AppFileUploadResponse
+ model: AppModelSelectionResponse
+ more_like_this: AppEnabledConfigResponse
+ opening_statement: string | null
+ pre_prompt: string | null
+ prompt_type: PromptType
+ retriever_resource: AppEnabledConfigResponse
+ sensitive_word_avoidance: AppSensitiveWordAvoidanceResponse
+ speech_to_text: AppEnabledConfigResponse
+ suggested_questions: Array
+ suggested_questions_after_answer: AppSuggestedQuestionsAfterAnswerResponse
+ text_to_speech: AppTextToSpeechResponse
+ updated_at: number
+ updated_by: string | null
+ user_input_form: Array<
+ | AppTextInputFormResponse
+ | AppSelectFormResponse
+ | AppParagraphFormResponse
+ | AppNumberFormResponse
+ | AppCheckboxFormResponse
+ | AppFileFormResponse
+ | AppFileListFormResponse
+ | AppExternalDataToolFormResponse
+ | AppJsonObjectFormResponse
+ >
}
export type AppDetailSiteResponse = {
- access_token?: string | null
- app_base_url?: string | null
- chat_color_theme?: string | null
- chat_color_theme_inverted?: boolean | null
- code?: string | null
- copyright?: string | null
- created_at?: number | null
- created_by?: string | null
- custom_disclaimer?: string | null
- customize_domain?: string | null
- customize_token_strategy?: string | null
- default_language?: string | null
- description?: string | null
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | IconType | null
+ access_token: string | null
+ app_base_url: string
+ chat_color_theme: string | null
+ chat_color_theme_inverted: boolean
+ code: string | null
+ copyright: string | null
+ created_at: number
+ created_by: string | null
+ custom_disclaimer: string
+ customize_domain: string | null
+ customize_token_strategy: CustomizeTokenStrategy
+ default_language: string
+ description: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
readonly icon_url: string | null
- input_placeholder?: string | null
- privacy_policy?: string | null
- prompt_public?: boolean | null
- show_workflow_steps?: boolean | null
- title?: string | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
+ input_placeholder: string | null
+ privacy_policy: string | null
+ prompt_public: boolean
+ show_workflow_steps: boolean
+ title: string
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
}
export type Tag = {
@@ -2088,12 +2112,178 @@ export type WorkflowDraftVariableFullContentResponse = {
export type ModelConfigPartial = {
created_at?: number | null
created_by?: string | null
- model?: unknown | null
+ model?: AppModelSelectionResponse | null
pre_prompt?: string | null
updated_at?: number | null
updated_by?: string | null
}
+export type AppAgentModeResponse = {
+ enabled: boolean
+ max_iteration?: number
+ prompt?: AppAgentPromptResponse | string | null
+ strategy?: PlanningStrategy | 'cot' | 'function-calling' | null
+ tools?: Array<
+ | AppProviderAgentToolResponse
+ | AppLegacyDatasetToolResponse
+ | AppLegacyGoogleSearchToolResponse
+ | AppLegacyWebReaderToolResponse
+ | AppLegacyWikipediaToolResponse
+ | AppLegacyCurrentDatetimeToolResponse
+ | AppLegacySensitiveWordToolResponseItem
+ >
+ [key: string]: unknown
+}
+
+export type AppAnnotationReplyEnabledResponse = {
+ embedding_model: AppEmbeddingModelResponse
+ enabled: true
+ id: string
+ score_threshold: number
+}
+
+export type AppAnnotationReplyDisabledResponse = {
+ enabled: false
+}
+
+export type AppChatPromptConfigResponse = {
+ prompt?: Array
+}
+
+export type AppCompletionPromptConfigResponse = {
+ conversation_histories_role?: AppConversationHistoriesRoleResponse
+ prompt?: AppCompletionPromptTextResponse
+}
+
+export type AppDatasetConfigsResponse = {
+ datasets?: AppDatasetListResponse
+ metadata_filtering_conditions?: AppMetadataFilteringConditionsResponse | null
+ metadata_filtering_mode?: 'automatic' | 'disabled' | 'manual'
+ metadata_model_config?: AppModelSelectionResponse | null
+ reranking_enable?: boolean
+ reranking_enabled?: boolean
+ reranking_mode?: RerankMode
+ reranking_model?: AppRerankingModelResponse | null
+ retrieval_model: 'multiple' | 'single'
+ score_threshold?: number | null
+ score_threshold_enabled?: boolean
+ top_k?: number
+ weights?: AppWeightsResponse | null
+ [key: string]: unknown
+}
+
+export type AppEnabledExternalDataToolResponse = {
+ config: {
+ [key: string]: JsonValue2
+ }
+ enabled: true
+ icon?: string
+ icon_background?: string
+ label?: string
+ type: string
+ variable: string
+ [key: string]: unknown
+}
+
+export type AppDisabledExternalDataToolResponse = {
+ config?: {
+ [key: string]: JsonValue2
+ }
+ enabled: false
+ icon?: string
+ icon_background?: string
+ label?: string
+ type?: string
+ variable?: string
+ [key: string]: unknown
+}
+
+export type AppFileUploadResponse = {
+ allowed_file_extensions?: Array
+ allowed_file_types?: Array
+ allowed_file_upload_methods?: Array
+ enabled?: boolean
+ image?: AppImageUploadResponse
+ number_limits?: number
+}
+
+export type AppModelSelectionResponse = {
+ completion_params?: {
+ [key: string]: JsonValue2
+ }
+ mode?: LlmMode | ''
+ name?: string
+ provider?: string
+ [key: string]: unknown
+}
+
+export type AppEnabledConfigResponse = {
+ enabled: boolean
+}
+
+export type PromptType = 'advanced' | 'simple'
+
+export type AppSensitiveWordAvoidanceResponse = {
+ config?: {
+ [key: string]: JsonValue2
+ }
+ configs?: Array
+ enabled: boolean
+ type?: string
+ [key: string]: unknown
+}
+
+export type AppSuggestedQuestionsAfterAnswerResponse = {
+ enabled: boolean
+ model?: AppModelSelectionResponse
+ prompt?: string
+}
+
+export type AppTextToSpeechResponse = {
+ autoPlay?: 'disabled' | 'enabled'
+ enabled: boolean
+ language?: string
+ voice?: string
+}
+
+export type AppTextInputFormResponse = {
+ 'text-input': AppUserInputFormConfigResponse
+}
+
+export type AppSelectFormResponse = {
+ select: AppUserInputFormConfigResponse
+}
+
+export type AppParagraphFormResponse = {
+ paragraph: AppUserInputFormConfigResponse
+}
+
+export type AppNumberFormResponse = {
+ number: AppUserInputFormConfigResponse
+}
+
+export type AppCheckboxFormResponse = {
+ checkbox: AppUserInputFormConfigResponse
+}
+
+export type AppFileFormResponse = {
+ file: AppUserInputFormConfigResponse
+}
+
+export type AppFileListFormResponse = {
+ 'file-list': AppUserInputFormConfigResponse
+}
+
+export type AppExternalDataToolFormResponse = {
+ external_data_tool: AppUserInputFormConfigResponse
+}
+
+export type AppJsonObjectFormResponse = {
+ json_object: AppUserInputFormConfigResponse
+}
+
+export type CustomizeTokenStrategy = 'allow' | 'must' | 'not_allow' | 'uuid'
+
export type PluginDependencyType = 'github' | 'marketplace' | 'package'
export type Github = {
@@ -2250,7 +2440,7 @@ export type WorkflowSuggestedQuestionsAfterAnswerPayload = {
}
export type WorkflowTextToSpeechPayload = {
- autoPlay?: string | null
+ autoPlay?: 'disabled' | 'enabled' | null
enabled?: boolean | null
language?: string | null
voice?: string | null
@@ -2484,6 +2674,156 @@ export type CheckResultView = {
reason?: string | null
}
+export type AppAgentPromptResponse = {
+ first_prompt?: string
+ next_iteration?: string
+ [key: string]: unknown
+}
+
+export type PlanningStrategy = 'function_call' | 'react' | 'react_router' | 'router'
+
+export type AppProviderAgentToolResponse = {
+ credential_id?: string | null
+ enabled?: boolean
+ isDeleted?: boolean
+ notAuthor?: boolean
+ plugin_unique_identifier?: string | null
+ provider_id: string
+ provider_name?: string
+ provider_type: ToolProviderType
+ tool_label?: string
+ tool_name: string
+ tool_parameters: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyDatasetToolResponse = {
+ dataset: AppDatasetReferenceResponse
+ [key: string]: unknown
+}
+
+export type AppLegacyGoogleSearchToolResponse = {
+ google_search: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyWebReaderToolResponse = {
+ web_reader: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyWikipediaToolResponse = {
+ wikipedia: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacyCurrentDatetimeToolResponse = {
+ current_datetime: {
+ [key: string]: JsonValue2
+ }
+ [key: string]: unknown
+}
+
+export type AppLegacySensitiveWordToolResponseItem = {
+ 'sensitive-word-avoidance': AppLegacySensitiveWordToolResponse
+ [key: string]: unknown
+}
+
+export type AppEmbeddingModelResponse = {
+ embedding_model_name: string
+ embedding_provider_name: string
+}
+
+export type AppChatPromptMessageResponse = {
+ role: string
+ text: string
+}
+
+export type AppConversationHistoriesRoleResponse = {
+ assistant_prefix: string
+ user_prefix: string
+}
+
+export type AppCompletionPromptTextResponse = {
+ text: string
+}
+
+export type AppDatasetListResponse = {
+ datasets: Array
+ strategy?: string
+ [key: string]: unknown
+}
+
+export type AppMetadataFilteringConditionsResponse = {
+ conditions?: Array | null
+ logical_operator?: 'and' | 'or' | null
+ [key: string]: unknown
+}
+
+export type RerankMode = 'reranking_model' | 'weighted_score'
+
+export type AppRerankingModelResponse = {
+ reranking_model_name?: string
+ reranking_provider_name?: string
+ [key: string]: unknown
+}
+
+export type AppWeightsResponse = {
+ keyword_setting: AppKeywordSettingResponse
+ vector_setting: AppVectorSettingResponse
+ weight_type?: 'customized' | 'keyword_first' | 'semantic_first'
+ [key: string]: unknown
+}
+
+export type JsonValue2 = unknown
+
+export type FileType = 'audio' | 'custom' | 'document' | 'image' | 'video'
+
+export type FileTransferMethod = 'datasource_file' | 'local_file' | 'remote_url' | 'tool_file'
+
+export type AppImageUploadResponse = {
+ detail?: 'high' | 'low' | null
+ enabled?: boolean
+ number_limits?: number
+ transfer_methods?: Array
+}
+
+export type AppUserInputFormConfigResponse = {
+ allowed_file_extensions?: Array
+ allowed_file_types?: Array
+ allowed_file_upload_methods?: Array
+ config?: {
+ [key: string]: JsonValue2
+ }
+ default?: JsonValue2
+ description?: string
+ enabled?: boolean
+ hide?: boolean
+ icon?: string | null
+ icon_background?: string | null
+ json_schema?:
+ | string
+ | {
+ [key: string]: JsonValue2
+ }
+ | null
+ label: string
+ max_length?: number | null
+ options?: Array
+ required?: boolean
+ type?: string
+ variable: string
+ [key: string]: unknown
+}
+
export type UserActionConfig = {
button_style?: ButtonStyle
id: string
@@ -2504,8 +2844,6 @@ export type FormInputConfig =
type: 'file-list'
} & FileListInputConfig)
-export type JsonValue2 = unknown
-
export type WorkflowFileUploadTransferPayload = {
enabled?: boolean | null
number_limits?: number | null
@@ -2556,7 +2894,7 @@ export type AgentSuggestedQuestionsAfterAnswerFeatureConfig = {
}
export type AgentTextToSpeechFeatureConfig = {
- autoPlay?: string | null
+ autoPlay?: 'disabled' | 'enabled' | null
enabled?: boolean
language?: string | null
voice?: string | null
@@ -2743,6 +3081,72 @@ export type AgentComposerKnowledgeDatasetCandidateResponse = {
name?: string | null
}
+export type ToolProviderType =
+ | 'api'
+ | 'app'
+ | 'builtin'
+ | 'dataset-retrieval'
+ | 'mcp'
+ | 'plugin'
+ | 'workflow'
+
+export type AppDatasetReferenceResponse = {
+ enabled?: boolean
+ id?: string
+ [key: string]: unknown
+}
+
+export type AppLegacySensitiveWordToolResponse = {
+ canned_response: string
+ enabled: boolean
+ words: Array
+ [key: string]: unknown
+}
+
+export type AppDatasetItemResponse = {
+ dataset: AppDatasetReferenceResponse
+ [key: string]: unknown
+}
+
+export type AppMetadataConditionResponse = {
+ comparison_operator:
+ | '<'
+ | '='
+ | '>'
+ | 'after'
+ | 'before'
+ | 'contains'
+ | 'empty'
+ | 'end with'
+ | 'in'
+ | 'is'
+ | 'is not'
+ | 'not contains'
+ | 'not empty'
+ | 'not in'
+ | 'start with'
+ | '≠'
+ | '≤'
+ | '≥'
+ id?: string
+ metadata_id?: string
+ name: string
+ value?: string | Array | number | number | null
+ [key: string]: unknown
+}
+
+export type AppKeywordSettingResponse = {
+ keyword_weight: number
+ [key: string]: unknown
+}
+
+export type AppVectorSettingResponse = {
+ embedding_model_name: string
+ embedding_provider_name: string
+ vector_weight: number
+ [key: string]: unknown
+}
+
export type ButtonStyle = 'accent' | 'default' | 'ghost' | 'primary'
export type ParagraphInputConfig = {
@@ -2774,10 +3178,6 @@ export type FileListInputConfig = {
type?: 'file-list'
}
-export type FileType = 'audio' | 'custom' | 'document' | 'image' | 'video'
-
-export type FileTransferMethod = 'datasource_file' | 'local_file' | 'remote_url' | 'tool_file'
-
export type AgentFileUploadImageFeatureConfig = {
enabled?: boolean
[key: string]: unknown
@@ -2840,15 +3240,6 @@ export type AgentSoulDifyToolCredentialRef = {
type?: 'provider' | 'tool'
}
-export type ToolProviderType =
- | 'api'
- | 'app'
- | 'builtin'
- | 'dataset-retrieval'
- | 'mcp'
- | 'plugin'
- | 'workflow'
-
export type StringSource = {
selector?: Array
type: ValueSourceType
@@ -2936,33 +3327,33 @@ export type AppPaginationWritable = {
}
export type AppDetailWithSiteWritable = {
- access_mode?: string | null
- api_base_url?: string | null
- app_id?: string | null
- bound_agent_id?: string | null
- created_at?: number | null
- created_by?: string | null
- deleted_tools?: Array
- description?: string | null
+ access_mode: WebAppAccessMode | null
+ api_base_url: string
+ app_id: string | null
+ bound_agent_id: string | null
+ created_at: number
+ created_by: string | null
+ deleted_tools: Array
+ description: string
enable_api: boolean
enable_site: boolean
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
id: string
- maintainer?: string | null
- max_active_requests?: number | null
- mode: string
- model_config?: AppModelConfigResponse | null
+ maintainer: string | null
+ max_active_requests: number | null
+ mode: AppMode
+ model_config: AppModelConfigResponse | null
name: string
- permission_keys?: Array
- site?: AppDetailSiteResponseWritable | null
- tags?: Array
- tracing?: unknown | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
- workflow?: WorkflowPartial | null
+ permission_keys: Array
+ site: AppDetailSiteResponseWritable | null
+ tags: Array
+ tracing: string | null
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
+ workflow: WorkflowPartial | null
}
export type RecentAppListResponseWritable = {
@@ -2997,7 +3388,7 @@ export type WorkflowCommentDetailWritable = {
}
export type AppPartialWritable = {
- access_mode?: string | null
+ access_mode?: WebAppAccessMode | null
app_id?: string | null
author_name?: string | null
bound_agent_id?: string | null
@@ -3008,12 +3399,12 @@ export type AppPartialWritable = {
has_draft_trigger?: boolean | null
icon?: string | null
icon_background?: string | null
- icon_type?: string | null
+ icon_type?: IconType | null
id: string
is_starred?: boolean
maintainer?: string | null
max_active_requests?: number | null
- mode: string
+ mode: AppMode
model_config?: ModelConfigPartial | null
name: string
permission_keys?: Array
@@ -3025,30 +3416,30 @@ export type AppPartialWritable = {
}
export type AppDetailSiteResponseWritable = {
- access_token?: string | null
- app_base_url?: string | null
- chat_color_theme?: string | null
- chat_color_theme_inverted?: boolean | null
- code?: string | null
- copyright?: string | null
- created_at?: number | null
- created_by?: string | null
- custom_disclaimer?: string | null
- customize_domain?: string | null
- customize_token_strategy?: string | null
- default_language?: string | null
- description?: string | null
- icon?: string | null
- icon_background?: string | null
- icon_type?: string | IconType | null
- input_placeholder?: string | null
- privacy_policy?: string | null
- prompt_public?: boolean | null
- show_workflow_steps?: boolean | null
- title?: string | null
- updated_at?: number | null
- updated_by?: string | null
- use_icon_as_answer_icon?: boolean | null
+ access_token: string | null
+ app_base_url: string
+ chat_color_theme: string | null
+ chat_color_theme_inverted: boolean
+ code: string | null
+ copyright: string | null
+ created_at: number
+ created_by: string | null
+ custom_disclaimer: string
+ customize_domain: string | null
+ customize_token_strategy: CustomizeTokenStrategy
+ default_language: string
+ description: string | null
+ icon: string | null
+ icon_background: string | null
+ icon_type: IconType | null
+ input_placeholder: string | null
+ privacy_policy: string | null
+ prompt_public: boolean
+ show_workflow_steps: boolean
+ title: string
+ updated_at: number
+ updated_by: string | null
+ use_icon_as_answer_icon: boolean
}
export type RecentAppResponseWritable = {
diff --git a/packages/contracts/generated/api/console/apps/zod.gen.ts b/packages/contracts/generated/api/console/apps/zod.gen.ts
index 8572e7e4244..50ab21e35f8 100644
--- a/packages/contracts/generated/api/console/apps/zod.gen.ts
+++ b/packages/contracts/generated/api/console/apps/zod.gen.ts
@@ -781,6 +781,11 @@ export const zAppIconPayload = z.object({
icon_type: zIconType.nullish(),
})
+/**
+ * WebAppAccessMode
+ */
+export const zWebAppAccessMode = z.enum(['private', 'private_all', 'public', 'sso_verified'])
+
/**
* DeletedTool
*/
@@ -791,65 +796,18 @@ export const zDeletedTool = z.object({
})
/**
- * AppModelConfigResponse
+ * AppMode
*/
-export const zAppModelConfigResponse = z.object({
- agent_mode: z.unknown().nullish(),
- annotation_reply: z.unknown().nullish(),
- chat_prompt_config: z.unknown().nullish(),
- completion_prompt_config: z.unknown().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- dataset_configs: z.unknown().nullish(),
- dataset_query_variable: z.string().nullish(),
- external_data_tools: z.unknown().nullish(),
- file_upload: z.unknown().nullish(),
- model: z.unknown().nullish(),
- more_like_this: z.unknown().nullish(),
- opening_statement: z.string().nullish(),
- pre_prompt: z.string().nullish(),
- prompt_type: z.string().nullish(),
- retriever_resource: z.unknown().nullish(),
- sensitive_word_avoidance: z.unknown().nullish(),
- speech_to_text: z.unknown().nullish(),
- suggested_questions: z.unknown().nullish(),
- suggested_questions_after_answer: z.unknown().nullish(),
- text_to_speech: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- user_input_form: z.unknown().nullish(),
-})
-
-/**
- * AppDetailSiteResponse
- */
-export const zAppDetailSiteResponse = z.object({
- access_token: z.string().nullish(),
- app_base_url: z.string().nullish(),
- chat_color_theme: z.string().nullish(),
- chat_color_theme_inverted: z.boolean().nullish(),
- code: z.string().nullish(),
- copyright: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- custom_disclaimer: z.string().nullish(),
- customize_domain: z.string().nullish(),
- customize_token_strategy: z.string().nullish(),
- default_language: z.string().nullish(),
- description: z.string().nullish(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.union([z.string(), zIconType]).nullish(),
- icon_url: z.string().nullable(),
- input_placeholder: z.string().nullish(),
- privacy_policy: z.string().nullish(),
- prompt_public: z.boolean().nullish(),
- show_workflow_steps: z.boolean().nullish(),
- title: z.string().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
-})
+export const zAppMode = z.enum([
+ 'advanced-chat',
+ 'agent',
+ 'agent-chat',
+ 'channel',
+ 'chat',
+ 'completion',
+ 'rag-pipeline',
+ 'workflow',
+])
/**
* Tag
@@ -871,66 +829,6 @@ export const zWorkflowPartial = z.object({
updated_by: z.string().nullish(),
})
-/**
- * AppDetailWithSite
- */
-export const zAppDetailWithSite = z.object({
- access_mode: z.string().nullish(),
- api_base_url: z.string().nullish(),
- app_id: z.string().nullish(),
- bound_agent_id: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- deleted_tools: z.array(zDeletedTool).optional(),
- description: z.string().nullish(),
- enable_api: z.boolean(),
- enable_site: z.boolean(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
- icon_url: z.string().nullable(),
- id: z.string(),
- maintainer: z.string().nullish(),
- max_active_requests: z.int().nullish(),
- mode: z.string(),
- model_config: zAppModelConfigResponse.nullish(),
- name: z.string(),
- permission_keys: z.array(z.string()).optional(),
- site: zAppDetailSiteResponse.nullish(),
- tags: z.array(zTag).optional(),
- tracing: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
-})
-
-/**
- * AppDetail
- */
-export const zAppDetail = z.object({
- access_mode: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- description: z.string().nullish(),
- enable_api: z.boolean(),
- enable_site: z.boolean(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- id: z.string(),
- maintainer: z.string().nullish(),
- mode: z.string(),
- model_config: zAppModelConfigResponse.nullish(),
- name: z.string(),
- permission_keys: z.array(z.string()).optional(),
- tags: z.array(zTag).optional(),
- tracing: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
-})
-
/**
* ImportStatus
*/
@@ -953,7 +851,7 @@ export const zDslImportWarning = z.object({
*/
export const zImport = z.object({
app_id: z.string().nullish(),
- app_mode: z.string().nullish(),
+ app_mode: zAppMode.nullish(),
current_dsl_version: z.string().optional().default('0.7.0'),
error: z.string().optional().default(''),
id: z.string(),
@@ -968,7 +866,7 @@ export const zImport = z.object({
*/
export const zAppImportResponse = z.object({
app_id: z.string().nullish(),
- app_mode: z.string().nullish(),
+ app_mode: zAppMode.nullish(),
current_dsl_version: z.string(),
error: z.string().optional().default(''),
id: z.string(),
@@ -2164,58 +2062,72 @@ export const zWorkflowDraftVariableListResponse = z.object({
})
/**
- * ModelConfigPartial
+ * AppAnnotationReplyDisabledResponse
*/
-export const zModelConfigPartial = z.object({
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- model: z.unknown().nullish(),
- pre_prompt: z.string().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
+export const zAppAnnotationReplyDisabledResponse = z.object({
+ enabled: z.literal(false),
})
/**
- * AppPartial
+ * AppEnabledConfigResponse
*/
-export const zAppPartial = z.object({
- access_mode: z.string().nullish(),
- app_id: z.string().nullish(),
- author_name: z.string().nullish(),
- bound_agent_id: z.string().nullish(),
- create_user_name: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- description: z.string().nullish(),
- has_draft_trigger: z.boolean().nullish(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
+export const zAppEnabledConfigResponse = z.object({
+ enabled: z.boolean(),
+})
+
+/**
+ * PromptType
+ *
+ * Prompt configuration type
+ */
+export const zPromptType = z.enum(['advanced', 'simple'])
+
+/**
+ * AppTextToSpeechResponse
+ */
+export const zAppTextToSpeechResponse = z.object({
+ autoPlay: z.enum(['disabled', 'enabled']).optional(),
+ enabled: z.boolean(),
+ language: z.string().optional(),
+ voice: z.string().optional(),
+})
+
+/**
+ * CustomizeTokenStrategy
+ *
+ * Site token customization strategy
+ */
+export const zCustomizeTokenStrategy = z.enum(['allow', 'must', 'not_allow', 'uuid'])
+
+/**
+ * AppDetailSiteResponse
+ */
+export const zAppDetailSiteResponse = z.object({
+ access_token: z.string().nullable(),
+ app_base_url: z.string(),
+ chat_color_theme: z.string().nullable(),
+ chat_color_theme_inverted: z.boolean(),
+ code: z.string().nullable(),
+ copyright: z.string().nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ custom_disclaimer: z.string(),
+ customize_domain: z.string().nullable(),
+ customize_token_strategy: zCustomizeTokenStrategy,
+ default_language: z.string(),
+ description: z.string().nullable(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
icon_url: z.string().nullable(),
- id: z.string(),
- is_starred: z.boolean().optional().default(false),
- maintainer: z.string().nullish(),
- max_active_requests: z.int().nullish(),
- mode: z.string(),
- model_config: zModelConfigPartial.nullish(),
- name: z.string(),
- permission_keys: z.array(z.string()).optional(),
- tags: z.array(zTag).optional(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
-})
-
-/**
- * AppPagination
- */
-export const zAppPagination = z.object({
- data: z.array(zAppPartial),
- has_more: z.boolean(),
- limit: z.int(),
- page: z.int(),
- total: z.int(),
+ input_placeholder: z.string().nullable(),
+ privacy_policy: z.string().nullable(),
+ prompt_public: z.boolean(),
+ show_workflow_steps: z.boolean(),
+ title: z.string(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
})
/**
@@ -2625,7 +2537,7 @@ export const zWorkflowSuggestedQuestionsAfterAnswerPayload = z.object({
* WorkflowTextToSpeechPayload
*/
export const zWorkflowTextToSpeechPayload = z.object({
- autoPlay: z.string().nullish(),
+ autoPlay: z.enum(['disabled', 'enabled']).nullish(),
enabled: z.boolean().nullish(),
language: z.string().nullish(),
voice: z.string().nullish(),
@@ -2888,8 +2800,200 @@ export const zWorkflowRunSnapshotView = z.object({
workflow_run_status: zWorkflowExecutionStatus,
})
+/**
+ * AppAgentPromptResponse
+ */
+export const zAppAgentPromptResponse = z.object({
+ first_prompt: z.string().optional(),
+ next_iteration: z.string().optional(),
+})
+
+/**
+ * PlanningStrategy
+ */
+export const zPlanningStrategy = z.enum(['function_call', 'react', 'react_router', 'router'])
+
+/**
+ * AppEmbeddingModelResponse
+ */
+export const zAppEmbeddingModelResponse = z.object({
+ embedding_model_name: z.string(),
+ embedding_provider_name: z.string(),
+})
+
+/**
+ * AppAnnotationReplyEnabledResponse
+ */
+export const zAppAnnotationReplyEnabledResponse = z.object({
+ embedding_model: zAppEmbeddingModelResponse,
+ enabled: z.literal(true),
+ id: z.string(),
+ score_threshold: z.number(),
+})
+
+/**
+ * AppChatPromptMessageResponse
+ */
+export const zAppChatPromptMessageResponse = z.object({
+ role: z.string(),
+ text: z.string(),
+})
+
+/**
+ * AppChatPromptConfigResponse
+ */
+export const zAppChatPromptConfigResponse = z.object({
+ prompt: z.array(zAppChatPromptMessageResponse).optional(),
+})
+
+/**
+ * AppConversationHistoriesRoleResponse
+ */
+export const zAppConversationHistoriesRoleResponse = z.object({
+ assistant_prefix: z.string(),
+ user_prefix: z.string(),
+})
+
+/**
+ * AppCompletionPromptTextResponse
+ */
+export const zAppCompletionPromptTextResponse = z.object({
+ text: z.string(),
+})
+
+/**
+ * AppCompletionPromptConfigResponse
+ */
+export const zAppCompletionPromptConfigResponse = z.object({
+ conversation_histories_role: zAppConversationHistoriesRoleResponse.optional(),
+ prompt: zAppCompletionPromptTextResponse.optional(),
+})
+
+/**
+ * RerankMode
+ */
+export const zRerankMode = z.enum(['reranking_model', 'weighted_score'])
+
+/**
+ * AppRerankingModelResponse
+ */
+export const zAppRerankingModelResponse = z.object({
+ reranking_model_name: z.string().optional(),
+ reranking_provider_name: z.string().optional(),
+})
+
export const zJsonValue2 = z.unknown()
+/**
+ * AppEnabledExternalDataToolResponse
+ */
+export const zAppEnabledExternalDataToolResponse = z.object({
+ config: z.record(z.string(), zJsonValue2),
+ enabled: z.literal(true),
+ icon: z.string().optional(),
+ icon_background: z.string().optional(),
+ label: z.string().optional(),
+ type: z.string(),
+ variable: z.string(),
+})
+
+/**
+ * AppDisabledExternalDataToolResponse
+ */
+export const zAppDisabledExternalDataToolResponse = z.object({
+ config: z.record(z.string(), zJsonValue2).optional(),
+ enabled: z.literal(false),
+ icon: z.string().optional(),
+ icon_background: z.string().optional(),
+ label: z.string().optional(),
+ type: z.string().optional(),
+ variable: z.string().optional(),
+})
+
+/**
+ * AppModelSelectionResponse
+ */
+export const zAppModelSelectionResponse = z.object({
+ completion_params: z.record(z.string(), zJsonValue2).optional(),
+ mode: z.union([zLlmMode, z.literal('')]).optional(),
+ name: z.string().optional(),
+ provider: z.string().optional(),
+})
+
+/**
+ * ModelConfigPartial
+ */
+export const zModelConfigPartial = z.object({
+ created_at: z.int().nullish(),
+ created_by: z.string().nullish(),
+ model: zAppModelSelectionResponse.nullish(),
+ pre_prompt: z.string().nullish(),
+ updated_at: z.int().nullish(),
+ updated_by: z.string().nullish(),
+})
+
+/**
+ * AppPartial
+ */
+export const zAppPartial = z.object({
+ access_mode: zWebAppAccessMode.nullish(),
+ app_id: z.string().nullish(),
+ author_name: z.string().nullish(),
+ bound_agent_id: z.string().nullish(),
+ create_user_name: z.string().nullish(),
+ created_at: z.int().nullish(),
+ created_by: z.string().nullish(),
+ description: z.string().nullish(),
+ has_draft_trigger: z.boolean().nullish(),
+ icon: z.string().nullish(),
+ icon_background: z.string().nullish(),
+ icon_type: zIconType.nullish(),
+ icon_url: z.string().nullable(),
+ id: z.string(),
+ is_starred: z.boolean().optional().default(false),
+ maintainer: z.string().nullish(),
+ max_active_requests: z.int().nullish(),
+ mode: zAppMode,
+ model_config: zModelConfigPartial.nullish(),
+ name: z.string(),
+ permission_keys: z.array(z.string()).optional(),
+ tags: z.array(zTag).optional(),
+ updated_at: z.int().nullish(),
+ updated_by: z.string().nullish(),
+ use_icon_as_answer_icon: z.boolean().nullish(),
+ workflow: zWorkflowPartial.nullish(),
+})
+
+/**
+ * AppPagination
+ */
+export const zAppPagination = z.object({
+ data: z.array(zAppPartial),
+ has_more: z.boolean(),
+ limit: z.int(),
+ page: z.int(),
+ total: z.int(),
+})
+
+/**
+ * AppSensitiveWordAvoidanceResponse
+ */
+export const zAppSensitiveWordAvoidanceResponse = z.object({
+ config: z.record(z.string(), zJsonValue2).optional(),
+ configs: z.array(zJsonValue2).optional(),
+ enabled: z.boolean(),
+ type: z.string().optional(),
+})
+
+/**
+ * AppSuggestedQuestionsAfterAnswerResponse
+ */
+export const zAppSuggestedQuestionsAfterAnswerResponse = z.object({
+ enabled: z.boolean(),
+ model: zAppModelSelectionResponse.optional(),
+ prompt: z.string().optional(),
+})
+
/**
* HumanInputFormSubmissionData
*/
@@ -2902,6 +3006,157 @@ export const zHumanInputFormSubmissionData = z.object({
submitted_data: z.record(z.string(), zJsonValue2).nullish(),
})
+/**
+ * AppLegacyGoogleSearchToolResponse
+ */
+export const zAppLegacyGoogleSearchToolResponse = z.object({
+ google_search: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppLegacyWebReaderToolResponse
+ */
+export const zAppLegacyWebReaderToolResponse = z.object({
+ web_reader: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppLegacyWikipediaToolResponse
+ */
+export const zAppLegacyWikipediaToolResponse = z.object({
+ wikipedia: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppLegacyCurrentDatetimeToolResponse
+ */
+export const zAppLegacyCurrentDatetimeToolResponse = z.object({
+ current_datetime: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * FileType
+ */
+export const zFileType = z.enum(['audio', 'custom', 'document', 'image', 'video'])
+
+/**
+ * FileTransferMethod
+ */
+export const zFileTransferMethod = z.enum([
+ 'datasource_file',
+ 'local_file',
+ 'remote_url',
+ 'tool_file',
+])
+
+/**
+ * AppImageUploadResponse
+ */
+export const zAppImageUploadResponse = z.object({
+ detail: z.enum(['high', 'low']).nullish(),
+ enabled: z.boolean().optional(),
+ number_limits: z.int().optional(),
+ transfer_methods: z.array(zFileTransferMethod).optional(),
+})
+
+/**
+ * AppFileUploadResponse
+ */
+export const zAppFileUploadResponse = z.object({
+ allowed_file_extensions: z.array(z.string()).optional(),
+ allowed_file_types: z.array(zFileType).optional(),
+ allowed_file_upload_methods: z.array(zFileTransferMethod).optional(),
+ enabled: z.boolean().optional(),
+ image: zAppImageUploadResponse.optional(),
+ number_limits: z.int().optional(),
+})
+
+/**
+ * AppUserInputFormConfigResponse
+ */
+export const zAppUserInputFormConfigResponse = z.object({
+ allowed_file_extensions: z.array(z.string()).optional(),
+ allowed_file_types: z.array(zFileType).optional(),
+ allowed_file_upload_methods: z.array(zFileTransferMethod).optional(),
+ config: z.record(z.string(), zJsonValue2).optional(),
+ default: zJsonValue2.optional(),
+ description: z.string().optional(),
+ enabled: z.boolean().optional(),
+ hide: z.boolean().optional(),
+ icon: z.string().nullish(),
+ icon_background: z.string().nullish(),
+ json_schema: z.union([z.string(), z.record(z.string(), zJsonValue2)]).nullish(),
+ label: z.string(),
+ max_length: z.int().nullish(),
+ options: z.array(z.string()).optional(),
+ required: z.boolean().optional(),
+ type: z.string().optional(),
+ variable: z.string(),
+})
+
+/**
+ * AppTextInputFormResponse
+ */
+export const zAppTextInputFormResponse = z.object({
+ 'text-input': zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppSelectFormResponse
+ */
+export const zAppSelectFormResponse = z.object({
+ select: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppParagraphFormResponse
+ */
+export const zAppParagraphFormResponse = z.object({
+ paragraph: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppNumberFormResponse
+ */
+export const zAppNumberFormResponse = z.object({
+ number: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppCheckboxFormResponse
+ */
+export const zAppCheckboxFormResponse = z.object({
+ checkbox: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppFileFormResponse
+ */
+export const zAppFileFormResponse = z.object({
+ file: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppFileListFormResponse
+ */
+export const zAppFileListFormResponse = z.object({
+ 'file-list': zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppExternalDataToolFormResponse
+ */
+export const zAppExternalDataToolFormResponse = z.object({
+ external_data_tool: zAppUserInputFormConfigResponse,
+})
+
+/**
+ * AppJsonObjectFormResponse
+ */
+export const zAppJsonObjectFormResponse = z.object({
+ json_object: zAppUserInputFormConfigResponse,
+})
+
/**
* WorkflowFileUploadTransferPayload
*/
@@ -2979,7 +3234,7 @@ export const zAgentFeatureToggleConfig = z.object({
* AgentTextToSpeechFeatureConfig
*/
export const zAgentTextToSpeechFeatureConfig = z.object({
- autoPlay: z.string().nullish(),
+ autoPlay: z.enum(['disabled', 'enabled']).nullish(),
enabled: z.boolean().optional().default(false),
language: z.string().nullish(),
voice: z.string().nullish(),
@@ -3311,6 +3566,296 @@ export const zAgentComposerCandidatesResponse = z.object({
variant: zComposerVariant,
})
+/**
+ * ToolProviderType
+ *
+ * Enum class for tool provider
+ */
+export const zToolProviderType = z.enum([
+ 'api',
+ 'app',
+ 'builtin',
+ 'dataset-retrieval',
+ 'mcp',
+ 'plugin',
+ 'workflow',
+])
+
+/**
+ * AppProviderAgentToolResponse
+ */
+export const zAppProviderAgentToolResponse = z.object({
+ credential_id: z.string().nullish(),
+ enabled: z.boolean().optional(),
+ isDeleted: z.boolean().optional(),
+ notAuthor: z.boolean().optional(),
+ plugin_unique_identifier: z.string().nullish(),
+ provider_id: z.string(),
+ provider_name: z.string().optional(),
+ provider_type: zToolProviderType,
+ tool_label: z.string().optional(),
+ tool_name: z.string(),
+ tool_parameters: z.record(z.string(), zJsonValue2),
+})
+
+/**
+ * AppDatasetReferenceResponse
+ */
+export const zAppDatasetReferenceResponse = z.object({
+ enabled: z.boolean().optional(),
+ id: z.string().optional(),
+})
+
+/**
+ * AppLegacyDatasetToolResponse
+ */
+export const zAppLegacyDatasetToolResponse = z.object({
+ dataset: zAppDatasetReferenceResponse,
+})
+
+/**
+ * AppLegacySensitiveWordToolResponse
+ */
+export const zAppLegacySensitiveWordToolResponse = z.object({
+ canned_response: z.string(),
+ enabled: z.boolean(),
+ words: z.array(z.string()),
+})
+
+/**
+ * AppLegacySensitiveWordToolResponseItem
+ */
+export const zAppLegacySensitiveWordToolResponseItem = z.object({
+ 'sensitive-word-avoidance': zAppLegacySensitiveWordToolResponse,
+})
+
+/**
+ * AppAgentModeResponse
+ */
+export const zAppAgentModeResponse = z.object({
+ enabled: z.boolean(),
+ max_iteration: z.int().optional(),
+ prompt: z.union([zAppAgentPromptResponse, z.string()]).nullish(),
+ strategy: z.union([zPlanningStrategy, z.enum(['cot', 'function-calling'])]).nullish(),
+ tools: z
+ .array(
+ z.union([
+ zAppProviderAgentToolResponse,
+ zAppLegacyDatasetToolResponse,
+ zAppLegacyGoogleSearchToolResponse,
+ zAppLegacyWebReaderToolResponse,
+ zAppLegacyWikipediaToolResponse,
+ zAppLegacyCurrentDatetimeToolResponse,
+ zAppLegacySensitiveWordToolResponseItem,
+ ]),
+ )
+ .optional(),
+})
+
+/**
+ * AppDatasetItemResponse
+ */
+export const zAppDatasetItemResponse = z.object({
+ dataset: zAppDatasetReferenceResponse,
+})
+
+/**
+ * AppDatasetListResponse
+ */
+export const zAppDatasetListResponse = z.object({
+ datasets: z.array(zAppDatasetItemResponse),
+ strategy: z.string().optional(),
+})
+
+/**
+ * AppMetadataConditionResponse
+ */
+export const zAppMetadataConditionResponse = z.object({
+ comparison_operator: z.enum([
+ '<',
+ '=',
+ '>',
+ 'after',
+ 'before',
+ 'contains',
+ 'empty',
+ 'end with',
+ 'in',
+ 'is',
+ 'is not',
+ 'not contains',
+ 'not empty',
+ 'not in',
+ 'start with',
+ '≠',
+ '≤',
+ '≥',
+ ]),
+ id: z.string().optional(),
+ metadata_id: z.string().optional(),
+ name: z.string(),
+ value: z.union([z.string(), z.array(z.string()), z.int(), z.number()]).nullish(),
+})
+
+/**
+ * AppMetadataFilteringConditionsResponse
+ */
+export const zAppMetadataFilteringConditionsResponse = z.object({
+ conditions: z.array(zAppMetadataConditionResponse).nullish(),
+ logical_operator: z.enum(['and', 'or']).nullish(),
+})
+
+/**
+ * AppKeywordSettingResponse
+ */
+export const zAppKeywordSettingResponse = z.object({
+ keyword_weight: z.number(),
+})
+
+/**
+ * AppVectorSettingResponse
+ */
+export const zAppVectorSettingResponse = z.object({
+ embedding_model_name: z.string(),
+ embedding_provider_name: z.string(),
+ vector_weight: z.number(),
+})
+
+/**
+ * AppWeightsResponse
+ */
+export const zAppWeightsResponse = z.object({
+ keyword_setting: zAppKeywordSettingResponse,
+ vector_setting: zAppVectorSettingResponse,
+ weight_type: z.enum(['customized', 'keyword_first', 'semantic_first']).optional(),
+})
+
+/**
+ * AppDatasetConfigsResponse
+ */
+export const zAppDatasetConfigsResponse = z.object({
+ datasets: zAppDatasetListResponse.optional(),
+ metadata_filtering_conditions: zAppMetadataFilteringConditionsResponse.nullish(),
+ metadata_filtering_mode: z.enum(['automatic', 'disabled', 'manual']).optional(),
+ metadata_model_config: zAppModelSelectionResponse.nullish(),
+ reranking_enable: z.boolean().optional(),
+ reranking_enabled: z.boolean().optional(),
+ reranking_mode: zRerankMode.optional(),
+ reranking_model: zAppRerankingModelResponse.nullish(),
+ retrieval_model: z.enum(['multiple', 'single']),
+ score_threshold: z.number().nullish(),
+ score_threshold_enabled: z.boolean().optional(),
+ top_k: z.int().optional(),
+ weights: zAppWeightsResponse.nullish(),
+})
+
+/**
+ * AppModelConfigResponse
+ */
+export const zAppModelConfigResponse = z.object({
+ agent_mode: zAppAgentModeResponse,
+ annotation_reply: z.union([
+ zAppAnnotationReplyEnabledResponse,
+ zAppAnnotationReplyDisabledResponse,
+ ]),
+ chat_prompt_config: zAppChatPromptConfigResponse,
+ completion_prompt_config: zAppCompletionPromptConfigResponse,
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ dataset_configs: zAppDatasetConfigsResponse,
+ dataset_query_variable: z.string().nullable(),
+ external_data_tools: z.array(
+ z.union([zAppEnabledExternalDataToolResponse, zAppDisabledExternalDataToolResponse]),
+ ),
+ file_upload: zAppFileUploadResponse,
+ model: zAppModelSelectionResponse,
+ more_like_this: zAppEnabledConfigResponse,
+ opening_statement: z.string().nullable(),
+ pre_prompt: z.string().nullable(),
+ prompt_type: zPromptType,
+ retriever_resource: zAppEnabledConfigResponse,
+ sensitive_word_avoidance: zAppSensitiveWordAvoidanceResponse,
+ speech_to_text: zAppEnabledConfigResponse,
+ suggested_questions: z.array(z.string()),
+ suggested_questions_after_answer: zAppSuggestedQuestionsAfterAnswerResponse,
+ text_to_speech: zAppTextToSpeechResponse,
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ user_input_form: z.array(
+ z.union([
+ zAppTextInputFormResponse,
+ zAppSelectFormResponse,
+ zAppParagraphFormResponse,
+ zAppNumberFormResponse,
+ zAppCheckboxFormResponse,
+ zAppFileFormResponse,
+ zAppFileListFormResponse,
+ zAppExternalDataToolFormResponse,
+ zAppJsonObjectFormResponse,
+ ]),
+ ),
+})
+
+/**
+ * AppDetailWithSite
+ */
+export const zAppDetailWithSite = z.object({
+ access_mode: zWebAppAccessMode.nullable(),
+ api_base_url: z.string(),
+ app_id: z.string().nullable(),
+ bound_agent_id: z.string().nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ deleted_tools: z.array(zDeletedTool),
+ description: z.string(),
+ enable_api: z.boolean(),
+ enable_site: z.boolean(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
+ icon_url: z.string().nullable(),
+ id: z.string(),
+ maintainer: z.string().nullable(),
+ max_active_requests: z.int().nullable(),
+ mode: zAppMode,
+ model_config: zAppModelConfigResponse.nullable(),
+ name: z.string(),
+ permission_keys: z.array(z.string()),
+ site: zAppDetailSiteResponse.nullable(),
+ tags: z.array(zTag),
+ tracing: z.string().nullable(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
+ workflow: zWorkflowPartial.nullable(),
+})
+
+/**
+ * AppDetail
+ */
+export const zAppDetail = z.object({
+ access_mode: zWebAppAccessMode.nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ description: z.string(),
+ enable_api: z.boolean(),
+ enable_site: z.boolean(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ id: z.string(),
+ maintainer: z.string().nullable(),
+ mode: zAppMode,
+ model_config: zAppModelConfigResponse.nullable(),
+ name: z.string(),
+ permission_keys: z.array(z.string()),
+ tags: z.array(zTag),
+ tracing: z.string().nullable(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
+ workflow: zWorkflowPartial.nullable(),
+})
+
/**
* ButtonStyle
*
@@ -3332,21 +3877,6 @@ export const zUserActionConfig = z.object({
title: z.string().max(100),
})
-/**
- * FileType
- */
-export const zFileType = z.enum(['audio', 'custom', 'document', 'image', 'video'])
-
-/**
- * FileTransferMethod
- */
-export const zFileTransferMethod = z.enum([
- 'datasource_file',
- 'local_file',
- 'remote_url',
- 'tool_file',
-])
-
/**
* FileInputConfig
*/
@@ -3542,21 +4072,6 @@ export const zAgentSoulDifyToolCredentialRef = z.object({
type: z.enum(['provider', 'tool']).optional().default('tool'),
})
-/**
- * ToolProviderType
- *
- * Enum class for tool provider
- */
-export const zToolProviderType = z.enum([
- 'api',
- 'app',
- 'builtin',
- 'dataset-retrieval',
- 'mcp',
- 'plugin',
- 'workflow',
-])
-
/**
* AgentSoulDifyToolConfig
*
@@ -4014,7 +4529,7 @@ export const zGeneratedAppResponseWritable = zJsonValue
* AppPartial
*/
export const zAppPartialWritable = z.object({
- access_mode: z.string().nullish(),
+ access_mode: zWebAppAccessMode.nullish(),
app_id: z.string().nullish(),
author_name: z.string().nullish(),
bound_agent_id: z.string().nullish(),
@@ -4025,12 +4540,12 @@ export const zAppPartialWritable = z.object({
has_draft_trigger: z.boolean().nullish(),
icon: z.string().nullish(),
icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
+ icon_type: zIconType.nullish(),
id: z.string(),
is_starred: z.boolean().optional().default(false),
maintainer: z.string().nullish(),
max_active_requests: z.int().nullish(),
- mode: z.string(),
+ mode: zAppMode,
model_config: zModelConfigPartial.nullish(),
name: z.string(),
permission_keys: z.array(z.string()).optional(),
@@ -4056,63 +4571,63 @@ export const zAppPaginationWritable = z.object({
* AppDetailSiteResponse
*/
export const zAppDetailSiteResponseWritable = z.object({
- access_token: z.string().nullish(),
- app_base_url: z.string().nullish(),
- chat_color_theme: z.string().nullish(),
- chat_color_theme_inverted: z.boolean().nullish(),
- code: z.string().nullish(),
- copyright: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- custom_disclaimer: z.string().nullish(),
- customize_domain: z.string().nullish(),
- customize_token_strategy: z.string().nullish(),
- default_language: z.string().nullish(),
- description: z.string().nullish(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.union([z.string(), zIconType]).nullish(),
- input_placeholder: z.string().nullish(),
- privacy_policy: z.string().nullish(),
- prompt_public: z.boolean().nullish(),
- show_workflow_steps: z.boolean().nullish(),
- title: z.string().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
+ access_token: z.string().nullable(),
+ app_base_url: z.string(),
+ chat_color_theme: z.string().nullable(),
+ chat_color_theme_inverted: z.boolean(),
+ code: z.string().nullable(),
+ copyright: z.string().nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ custom_disclaimer: z.string(),
+ customize_domain: z.string().nullable(),
+ customize_token_strategy: zCustomizeTokenStrategy,
+ default_language: z.string(),
+ description: z.string().nullable(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
+ input_placeholder: z.string().nullable(),
+ privacy_policy: z.string().nullable(),
+ prompt_public: z.boolean(),
+ show_workflow_steps: z.boolean(),
+ title: z.string(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
})
/**
* AppDetailWithSite
*/
export const zAppDetailWithSiteWritable = z.object({
- access_mode: z.string().nullish(),
- api_base_url: z.string().nullish(),
- app_id: z.string().nullish(),
- bound_agent_id: z.string().nullish(),
- created_at: z.int().nullish(),
- created_by: z.string().nullish(),
- deleted_tools: z.array(zDeletedTool).optional(),
- description: z.string().nullish(),
+ access_mode: zWebAppAccessMode.nullable(),
+ api_base_url: z.string(),
+ app_id: z.string().nullable(),
+ bound_agent_id: z.string().nullable(),
+ created_at: z.int(),
+ created_by: z.string().nullable(),
+ deleted_tools: z.array(zDeletedTool),
+ description: z.string(),
enable_api: z.boolean(),
enable_site: z.boolean(),
- icon: z.string().nullish(),
- icon_background: z.string().nullish(),
- icon_type: z.string().nullish(),
+ icon: z.string().nullable(),
+ icon_background: z.string().nullable(),
+ icon_type: zIconType.nullable(),
id: z.string(),
- maintainer: z.string().nullish(),
- max_active_requests: z.int().nullish(),
- mode: z.string(),
- model_config: zAppModelConfigResponse.nullish(),
+ maintainer: z.string().nullable(),
+ max_active_requests: z.int().nullable(),
+ mode: zAppMode,
+ model_config: zAppModelConfigResponse.nullable(),
name: z.string(),
- permission_keys: z.array(z.string()).optional(),
- site: zAppDetailSiteResponseWritable.nullish(),
- tags: z.array(zTag).optional(),
- tracing: z.unknown().nullish(),
- updated_at: z.int().nullish(),
- updated_by: z.string().nullish(),
- use_icon_as_answer_icon: z.boolean().nullish(),
- workflow: zWorkflowPartial.nullish(),
+ permission_keys: z.array(z.string()),
+ site: zAppDetailSiteResponseWritable.nullable(),
+ tags: z.array(zTag),
+ tracing: z.string().nullable(),
+ updated_at: z.int(),
+ updated_by: z.string().nullable(),
+ use_icon_as_answer_icon: z.boolean(),
+ workflow: zWorkflowPartial.nullable(),
})
/**
diff --git a/packages/contracts/generated/api/console/snippets/types.gen.ts b/packages/contracts/generated/api/console/snippets/types.gen.ts
index be473a7e1d3..57c28d99cbe 100644
--- a/packages/contracts/generated/api/console/snippets/types.gen.ts
+++ b/packages/contracts/generated/api/console/snippets/types.gen.ts
@@ -799,7 +799,7 @@ export type AgentSuggestedQuestionsAfterAnswerFeatureConfig = {
}
export type AgentTextToSpeechFeatureConfig = {
- autoPlay?: string | null
+ autoPlay?: 'disabled' | 'enabled' | null
enabled?: boolean
language?: string | null
voice?: string | null
diff --git a/packages/contracts/generated/api/console/snippets/zod.gen.ts b/packages/contracts/generated/api/console/snippets/zod.gen.ts
index c442c6ea565..520173ccdcc 100644
--- a/packages/contracts/generated/api/console/snippets/zod.gen.ts
+++ b/packages/contracts/generated/api/console/snippets/zod.gen.ts
@@ -760,7 +760,7 @@ export const zAgentFeatureToggleConfig = z.object({
* AgentTextToSpeechFeatureConfig
*/
export const zAgentTextToSpeechFeatureConfig = z.object({
- autoPlay: z.string().nullish(),
+ autoPlay: z.enum(['disabled', 'enabled']).nullish(),
enabled: z.boolean().optional().default(false),
language: z.string().nullish(),
voice: z.string().nullish(),
diff --git a/packages/contracts/generated/api/openapi/types.gen.ts b/packages/contracts/generated/api/openapi/types.gen.ts
index b6242c85432..6d5aea59107 100644
--- a/packages/contracts/generated/api/openapi/types.gen.ts
+++ b/packages/contracts/generated/api/openapi/types.gen.ts
@@ -81,7 +81,7 @@ export type AppDslImportPayload = {
export type AppDslImportResponse = {
app_id?: string | null
- app_mode?: string | null
+ app_mode?: AppMode | null
current_dsl_version?: string
error?: string
hints?: Array
@@ -305,7 +305,7 @@ export type HumanInputFormDefinitionResponse = {
export type Import = {
app_id?: string | null
- app_mode?: string | null
+ app_mode?: AppMode | null
current_dsl_version?: string
error?: string
id: string
diff --git a/packages/contracts/generated/api/openapi/zod.gen.ts b/packages/contracts/generated/api/openapi/zod.gen.ts
index 74078abe902..1a948478625 100644
--- a/packages/contracts/generated/api/openapi/zod.gen.ts
+++ b/packages/contracts/generated/api/openapi/zod.gen.ts
@@ -398,7 +398,7 @@ export const zImportStatus = z.enum(['completed', 'completed-with-warnings', 'fa
*/
export const zAppDslImportResponse = z.object({
app_id: z.string().nullish(),
- app_mode: z.string().nullish(),
+ app_mode: zAppMode.nullish(),
current_dsl_version: z.string().optional().default('0.7.0'),
error: z.string().optional().default(''),
hints: z.array(zHint).optional(),
@@ -414,7 +414,7 @@ export const zAppDslImportResponse = z.object({
*/
export const zImport = z.object({
app_id: z.string().nullish(),
- app_mode: z.string().nullish(),
+ app_mode: zAppMode.nullish(),
current_dsl_version: z.string().optional().default('0.7.0'),
error: z.string().optional().default(''),
id: z.string(),
diff --git a/web/app/components/app-sidebar/app-info/__tests__/use-app-info-actions.spec.ts b/web/app/components/app-sidebar/app-info/__tests__/use-app-info-actions.spec.ts
index d7913baba33..6a8bade05f7 100644
--- a/web/app/components/app-sidebar/app-info/__tests__/use-app-info-actions.spec.ts
+++ b/web/app/components/app-sidebar/app-info/__tests__/use-app-info-actions.spec.ts
@@ -198,7 +198,7 @@ describe('useAppInfoActions', () => {
describe('onEdit', () => {
it('should update app info and close modal on success', async () => {
- const updatedApp = { ...mockAppDetail, name: 'Updated' }
+ const updatedApp = { ...mockAppDetail, name: 'Updated', max_active_requests: null }
mockUpdateAppInfo.mockResolvedValue(updatedApp)
const { result } = renderHook(() => useAppInfoActions({}))
@@ -222,8 +222,8 @@ describe('useAppInfoActions', () => {
expect.any(Function),
)
const updateCachedApp = mockSetQueryData.mock.calls[0]![1]
- expect(updateCachedApp({ id: 'app-1', name: 'Old name' })).toEqual(
- expect.objectContaining({ id: 'app-1', name: 'Updated' }),
+ expect(updateCachedApp({ id: 'app-1', name: 'Old name', max_active_requests: 5 })).toEqual(
+ expect.objectContaining({ id: 'app-1', name: 'Updated', max_active_requests: null }),
)
expect(mockInvalidateQueries).toHaveBeenCalledWith({
queryKey: consoleQuery.apps.get.key(),
diff --git a/web/app/components/app-sidebar/app-info/use-app-info-actions.ts b/web/app/components/app-sidebar/app-info/use-app-info-actions.ts
index bc5255b14da..4c2f43d594b 100644
--- a/web/app/components/app-sidebar/app-info/use-app-info-actions.ts
+++ b/web/app/components/app-sidebar/app-info/use-app-info-actions.ts
@@ -68,7 +68,10 @@ const updateCachedAppMetadata = (cachedApp: AppDetailWithSite | undefined, app:
icon_background: app.icon_background,
icon_type: app.icon_type,
icon_url: app.icon_url,
- max_active_requests: app.max_active_requests,
+ max_active_requests:
+ app.max_active_requests === undefined
+ ? cachedApp.max_active_requests
+ : app.max_active_requests,
name: app.name,
updated_at: app.updated_at,
use_icon_as_answer_icon: app.use_icon_as_answer_icon,
diff --git a/web/app/components/app/configuration/dataset-config/settings-modal/__tests__/index.spec.tsx b/web/app/components/app/configuration/dataset-config/settings-modal/__tests__/index.spec.tsx
index 003ae8c6535..cff81dec096 100644
--- a/web/app/components/app/configuration/dataset-config/settings-modal/__tests__/index.spec.tsx
+++ b/web/app/components/app/configuration/dataset-config/settings-modal/__tests__/index.spec.tsx
@@ -646,8 +646,12 @@ describe('SettingsModal', () => {
it('should disable save button while saving', async () => {
// Arrange
const user = userEvent.setup()
+ let finishSave!: (dataset: DataSet) => void
mockUpdateDatasetSetting.mockImplementation(
- () => new Promise((resolve) => setTimeout(resolve, 100)),
+ () =>
+ new Promise((resolve) => {
+ finishSave = resolve
+ }),
)
// Act
@@ -658,6 +662,9 @@ describe('SettingsModal', () => {
// Assert
expect(saveButton).toBeDisabled()
+
+ finishSave(createDataset())
+ await waitFor(() => expect(saveButton).toBeEnabled())
})
it('should show error toast when save fails', async () => {
diff --git a/web/app/components/app/configuration/hooks/__tests__/use-configuration.spec.tsx b/web/app/components/app/configuration/hooks/__tests__/use-configuration.spec.tsx
index de28eeb197d..776b6c8a1c6 100644
--- a/web/app/components/app/configuration/hooks/__tests__/use-configuration.spec.tsx
+++ b/web/app/components/app/configuration/hooks/__tests__/use-configuration.spec.tsx
@@ -4,6 +4,7 @@ import { consoleQuery } from '@/service/console'
import { seedAccountProfileQuery } from '@/test/console/account-profile'
import { createQueryClientWrapper } from '@/test/console/query-client'
import { renderHook as renderHookWithConsoleState } from '@/test/console/render'
+import { createAppDetailFixture } from '@/test/fixtures/app'
import { createTestQueryClient } from '@/test/query-client'
import { AppModeEnum, ModelModeType } from '@/types/app'
import { AppACLPermission } from '@/utils/permission'
@@ -272,14 +273,17 @@ describe('useConfiguration', () => {
const detailQueryKey = consoleQuery.apps.byAppId.get.queryKey({
input: { params: { app_id: 'app-1' } },
})
- queryClient.setQueryData(detailQueryKey, {
- enable_api: false,
- enable_site: false,
- icon_url: null,
- id: 'app-1',
- mode: 'chat',
- name: 'Cached app',
- })
+ queryClient.setQueryData(
+ detailQueryKey,
+ createAppDetailFixture({
+ enable_api: false,
+ enable_site: false,
+ icon_url: null,
+ id: 'app-1',
+ mode: 'chat',
+ name: 'Cached app',
+ }),
+ )
await waitFor(() => {
expect(result.current.showLoading).toBe(false)
diff --git a/web/app/components/app/switch-app-modal/__tests__/index.spec.tsx b/web/app/components/app/switch-app-modal/__tests__/index.spec.tsx
index a45e7ecea8a..85d9ca7cb94 100644
--- a/web/app/components/app/switch-app-modal/__tests__/index.spec.tsx
+++ b/web/app/components/app/switch-app-modal/__tests__/index.spec.tsx
@@ -91,7 +91,7 @@ const createMockApp = (overrides: Partial = {}): AppPartial => ({
created_at: Date.now(),
updated_at: Date.now(),
tags: [],
- access_mode: 'public_access',
+ access_mode: 'public',
...overrides,
})
diff --git a/web/app/components/plugins/plugin-detail-panel/app-selector/app-inputs-panel.tsx b/web/app/components/plugins/plugin-detail-panel/app-selector/app-inputs-panel.tsx
index 532013fe8d8..e2cc079c024 100644
--- a/web/app/components/plugins/plugin-detail-panel/app-selector/app-inputs-panel.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/app-selector/app-inputs-panel.tsx
@@ -1,5 +1,5 @@
'use client'
-import type { AppDetailWithSite } from '@dify/contracts/api/console/apps/types.gen'
+import type { AppPartial } from '@dify/contracts/api/console/apps/types.gen'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { useRef } from 'react'
@@ -13,7 +13,7 @@ type Props = Readonly<{
app_id: string
inputs: Record
}
- appDetail: Pick
+ appDetail: Pick
onFormChange: (value: Record) => void
}>
diff --git a/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts b/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts
index 7e4551792b6..41729e79b21 100644
--- a/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts
+++ b/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts
@@ -1,6 +1,7 @@
'use client'
import type {
AppDetailWithSite,
+ AppPartial,
WorkflowResponse,
} from '@dify/contracts/api/console/apps/types.gen'
import type { FileUpload } from '@/app/components/base/features/types'
@@ -162,7 +163,7 @@ function buildWorkflowSchema(
}
type UseAppInputsFormSchemaParams = {
- appDetail: Pick
+ appDetail: Pick
}
type UseAppInputsFormSchemaResult = {
diff --git a/web/features/agent-v2/agent-detail/__tests__/navigation.spec.tsx b/web/features/agent-v2/agent-detail/__tests__/navigation.spec.tsx
index a893684cbf4..5ebc5365e84 100644
--- a/web/features/agent-v2/agent-detail/__tests__/navigation.spec.tsx
+++ b/web/features/agent-v2/agent-detail/__tests__/navigation.spec.tsx
@@ -3,6 +3,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { render, screen, waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { AgentPermission } from '@/features/agent-v2/acl'
+import { createAgentFixture } from '@/test/fixtures/agent'
import { AgentDetailSection, AgentDetailTop } from '../navigation'
const mocks = vi.hoisted(() => ({
@@ -86,22 +87,23 @@ vi.mock('@/service/console', () => ({
},
}))
-const createAgent = (overrides: Partial = {}): AgentAppDetailWithSite => ({
- permission_keys: Object.values(AgentPermission),
- app_id: 'app-1',
- description: 'Find and summarize market materials.',
- enable_api: true,
- enable_site: true,
- icon: '🧪',
- icon_background: '#E0F2FE',
- icon_type: 'emoji',
- id: 'agent-1',
- icon_url: null,
- mode: 'agent',
- name: 'Research Agent',
- role: 'Research Assistant',
- ...overrides,
-})
+const createAgent = (overrides: Partial = {}): AgentAppDetailWithSite =>
+ createAgentFixture({
+ permission_keys: Object.values(AgentPermission),
+ app_id: 'app-1',
+ description: 'Find and summarize market materials.',
+ enable_api: true,
+ enable_site: true,
+ icon: '🧪',
+ icon_background: '#E0F2FE',
+ icon_type: 'emoji',
+ id: 'agent-1',
+ icon_url: null,
+ mode: 'agent',
+ name: 'Research Agent',
+ role: 'Research Assistant',
+ ...overrides,
+ })
function renderAgentDetailSection(expand = true) {
const queryClient = new QueryClient()
diff --git a/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx b/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx
index 4363f7e124f..1bb893babe0 100644
--- a/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx
+++ b/web/features/agent-v2/agent-detail/access/components/__tests__/access-surface-cards.spec.tsx
@@ -15,6 +15,8 @@ import { consoleQuery } from '@/service/console'
import { seedAccountProfileQuery } from '@/test/console/account-profile'
import { createQueryClientWrapper } from '@/test/console/query-client'
import { seedFeatures, seedSystemFeatures } from '@/test/console/query-data'
+import { createAgentFixture } from '@/test/fixtures/agent'
+import { createAppDetailFixture, createAppSiteFixture } from '@/test/fixtures/app'
import { ServiceApiAccessCard } from '../service-api-access-card'
import { WebAppAccessCard } from '../web-app-access-card'
@@ -230,7 +232,7 @@ vi.mock('@/service/console', () => ({
}))
function createAgent(overrides: Partial = {}): AgentAppDetailWithSite {
- return {
+ return createAgentFixture({
permission_keys: Object.values(AgentPermission),
access_ready: true,
enable_api: true,
@@ -243,32 +245,23 @@ function createAgent(overrides: Partial = {}): AgentAppD
backing_app_id: 'app-1',
api_base_url: 'https://api.example.test/v1',
access_mode: 'sso_verified',
- site: {
- access_token: 'site-token',
+ site: createAppSiteFixture({
app_base_url: 'https://chat.example.test',
- chat_color_theme_inverted: false,
- default_language: 'en-US',
- icon_url: null,
- show_workflow_steps: false,
title: 'Support Agent',
- use_icon_as_answer_icon: false,
- } as NonNullable & {
- access_token: string
- app_base_url: string
- },
+ }),
...overrides,
- }
+ })
}
function createAppDetailResponse(overrides: Partial = {}): AppDetail {
- return {
+ return createAppDetailFixture({
enable_api: true,
enable_site: true,
id: 'app-1',
mode: 'agent',
name: 'Support Agent',
...overrides,
- }
+ })
}
function createAgentApiAccessResponse(
@@ -624,6 +617,35 @@ describe('Agent access surface cards', () => {
expect(toast.error).toHaveBeenCalledWith('common.actionMsg.modifiedUnsuccessfully')
})
+ it('should replace the Web App URL token without discarding the cached site settings', async () => {
+ const user = userEvent.setup()
+ const agent = createAgent()
+ const queryClient = renderWithQueryClient(
+ ,
+ )
+ queryClient.setQueryData(['agent-detail', 'agent-1'], agent)
+ mocks.siteAccessTokenResetMutation.mockResolvedValueOnce(
+ createAppSiteFixture({ code: 'new-site-token' }),
+ )
+
+ await user.click(
+ screen.getByRole('button', { name: 'agentV2.agentDetail.access.webApp.refreshUrl' }),
+ )
+
+ expect(mocks.siteAccessTokenResetMutation.mock.calls[0]?.[0]).toEqual({
+ params: { app_id: 'app-1' },
+ })
+ await waitFor(() => {
+ expect(
+ queryClient.getQueryData(['agent-detail', 'agent-1'])?.site,
+ ).toMatchObject({
+ code: 'new-site-token',
+ access_token: 'new-site-token',
+ title: 'Support Agent',
+ })
+ })
+ })
+
it('should open the customize dialog with the backing app id and API base URL', async () => {
const user = userEvent.setup()
@@ -707,7 +729,7 @@ describe('Agent access surface cards', () => {
})
})
- it('should save settings through the backing app id and update the agent detail cache', async () => {
+ it('should save settings through the backing app id and invalidate agent detail', async () => {
const user = userEvent.setup()
mocks.getUserCanAccess.mockResolvedValue({ result: false })
const agent = createAgent({
@@ -781,18 +803,9 @@ describe('Agent access surface cards', () => {
})
})
expect(mocks.siteMutation.mock.calls[0]?.[0].body).not.toHaveProperty('enable_sso')
- expect(
- queryClient.getQueryData(['agent-detail', 'agent-1']),
- ).toMatchObject({
- site: {
- access_token: 'new-site-token',
- chat_color_theme: '#123456',
- description: 'Updated web description.',
- icon_url: null,
- title: 'Support Portal',
- },
+ await waitFor(() => {
+ expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['agent-detail', 'agent-1'] })
})
- expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: ['agent-detail', 'agent-1'] })
})
it('should fall back to the Agent icon tuple when WebApp site icon data is missing', async () => {
@@ -918,10 +931,10 @@ describe('Agent access surface cards', () => {
).toBeDisabled()
})
- it('should keep customize disabled until the generated contract provides the required fields', () => {
+ it('should keep customize disabled when the app base URL is empty', () => {
renderWithQueryClient(
,
@@ -1246,22 +1259,19 @@ describe('Agent access surface cards', () => {
expect(screen.getByRole('button', { name: organizationAccessLabel })).toBeDisabled()
})
- it.each([null, 'future-access-mode'])(
- 'should hide the access mode entry when the access mode is %s',
- (accessMode) => {
- renderWithQueryClient(
- ,
- )
+ it('should hide the access mode entry when the access mode is unavailable', () => {
+ renderWithQueryClient(
+ ,
+ )
- expect(
- screen.queryByRole('button', { name: organizationAccessLabel }),
- ).not.toBeInTheDocument()
- },
- )
+ expect(
+ screen.queryByRole('button', { name: organizationAccessLabel }),
+ ).not.toBeInTheDocument()
+ })
it('should open the shared App access control dialog for the backing app', async () => {
const user = userEvent.setup()
diff --git a/web/features/agent-v2/agent-detail/access/components/web-app-access-card.tsx b/web/features/agent-v2/agent-detail/access/components/web-app-access-card.tsx
index d89ccb1f818..1de5c3b07d9 100644
--- a/web/features/agent-v2/agent-detail/access/components/web-app-access-card.tsx
+++ b/web/features/agent-v2/agent-detail/access/components/web-app-access-card.tsx
@@ -117,8 +117,8 @@ export function WebAppAccessCard({
...agentDetail,
site: {
...agentDetail.site,
- ...site,
- access_token: site.code,
+ code: site.code ?? agentDetail.site.code,
+ access_token: site.code ?? agentDetail.site.access_token,
},
}
},
@@ -191,39 +191,12 @@ export function WebAppAccessCard({
const sitePayload = body satisfies AppSiteUpdatePayload
try {
- const updatedSite = await updateSiteMutation.mutateAsync({
+ await updateSiteMutation.mutateAsync({
params: {
app_id: appId,
},
body: sitePayload,
})
-
- queryClient.setQueryData(
- agentDetailQueryKey,
- (agentDetail) =>
- agentDetail
- ? {
- ...agentDetail,
- site: {
- ...agentDetail.site,
- ...updatedSite,
- ...sitePayload,
- access_token:
- updatedSite.code ??
- agentDetail.site?.access_token ??
- agentDetail.site?.code ??
- null,
- code:
- updatedSite.code ??
- agentDetail.site?.code ??
- agentDetail.site?.access_token ??
- null,
- app_base_url: agentDetail.site?.app_base_url ?? site?.app_base_url ?? null,
- icon_url: null,
- },
- }
- : agentDetail,
- )
await queryClient.invalidateQueries({ queryKey: agentDetailQueryKey })
toast.success(tCommon(($) => $['actionMsg.modifiedSuccessfully']))
} catch {
diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.browser.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.browser.spec.tsx
index 9563ca628ae..d541d2c9a5d 100644
--- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.browser.spec.tsx
+++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.browser.spec.tsx
@@ -9,6 +9,7 @@ import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { consoleQuery } from '@/service/console'
import { createSystemFeaturesFixture } from '@/test/console/system-features'
import { createAgentFixture } from '@/test/fixtures/agent'
+import { createAppSiteFixture } from '@/test/fixtures/app'
import { createTestQueryClient } from '@/test/query-client'
import { AgentConfigurePublishBar } from '../publish-bar'
@@ -49,11 +50,10 @@ async function setup() {
createAgentFixture({
access_ready: true,
enable_site: true,
- site: {
+ site: createAppSiteFixture({
access_token: 'published-token',
app_base_url: 'https://apps.example.test',
- icon_url: null,
- },
+ }),
}),
)
queryClient.setQueryData(
diff --git a/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.spec.tsx b/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.spec.tsx
index 0fd9743f2b5..962a408488e 100644
--- a/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.spec.tsx
+++ b/web/features/agent-v2/agent-detail/configure/components/orchestrate/__tests__/publish-bar.spec.tsx
@@ -17,6 +17,7 @@ import {
import { agentComposerPromptAtom } from '@/features/agent-v2/agent-composer/store-modules/prompt'
import { systemFeaturesQueryOptions } from '@/features/system-features/client'
import { consoleQuery } from '@/service/console'
+import { createAppSiteFixture } from '@/test/fixtures/app'
import { createNuqsTestWrapper } from '@/test/nuqs-testing'
import { AgentConfigurePublishBar } from '../publish-bar'
@@ -1140,11 +1141,10 @@ describe('AgentConfigurePublishBar', () => {
const readyAgent = {
access_ready: true,
enable_site: true,
- site: {
+ site: createAppSiteFixture({
access_token: 'published-token',
app_base_url: 'https://apps.example.test',
- icon_url: null,
- },
+ }),
}
it.each([
diff --git a/web/service/console/client.spec.ts b/web/service/console/client.spec.ts
index e64ea69fd0f..940fdd817c4 100644
--- a/web/service/console/client.spec.ts
+++ b/web/service/console/client.spec.ts
@@ -6,6 +6,8 @@ import type { MutationFunctionContext, QueryFunctionContext } from '@tanstack/re
import type { consoleQuery as ConsoleQuery } from '@/service/console'
import { MutationObserver, QueryClient, QueryObserver } from '@tanstack/react-query'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vite-plus/test'
+import { createAgentFixture } from '@/test/fixtures/agent'
+import { createAppDetailFixture } from '@/test/fixtures/app'
import { normalizeConsoleOpenAPIURL } from './openapi-url'
const loadConsoleQuery = async () => {
@@ -84,22 +86,8 @@ const getRetryFn = (queryOptions: object): RetryFn => {
return retry as RetryFn
}
-const createAgent = (overrides: Partial = {}): AgentMutationResponse => ({
- ...overrides,
- access_ready: overrides.access_ready ?? true,
- debug_conversation_has_messages: overrides.debug_conversation_has_messages ?? false,
- debug_conversation_message_count: overrides.debug_conversation_message_count ?? 0,
- enable_api: overrides.enable_api ?? true,
- enable_site: overrides.enable_site ?? true,
- description: overrides.description ?? 'Agent description',
- hidden_app_backed: overrides.hidden_app_backed ?? false,
- id: overrides.id ?? 'agent-1',
- icon_url: overrides.icon_url ?? null,
- mode: overrides.mode ?? 'agent',
- name: overrides.name ?? 'Agent',
- permission_keys: overrides.permission_keys ?? [],
- role: overrides.role ?? 'Assistant',
-})
+const createAgent = (overrides: Partial = {}): AgentMutationResponse =>
+ createAgentFixture({ role: 'Assistant', ...overrides })
const createComposerState = (
overrides: Partial = {},
@@ -645,13 +633,7 @@ describe('consoleQuery app mutation defaults', () => {
.spyOn(queryClient, 'invalidateQueries')
.mockImplementation(() => new Promise(() => {}))
const context = createMutationContext(queryClient)
- const appDetail: AppDetail = {
- enable_api: true,
- enable_site: true,
- id: 'app-1',
- mode: 'chat',
- name: 'App',
- }
+ const appDetail: AppDetail = createAppDetailFixture()
const appSite: AppSiteResponse = {
app_id: 'app-1',
customize_token_strategy: 'fixed',
@@ -723,14 +705,11 @@ describe('consoleQuery app mutation defaults', () => {
const otherDetailQueryKey = consoleQuery.apps.byAppId.get.queryKey({
input: { params: { app_id: 'app-2' } },
})
- const updatedApp = {
+ const updatedApp = createAppDetailFixture({
enable_api: false,
enable_site: false,
- icon_url: null,
- id: 'app-1',
- mode: 'chat',
name: 'Updated app',
- }
+ })
queryClient.setQueryData(detailQueryKey, { ...updatedApp, name: 'Old app' })
queryClient.setQueryData(otherDetailQueryKey, { ...updatedApp, id: 'app-2', name: 'Other app' })
diff --git a/web/test/fixtures/agent.ts b/web/test/fixtures/agent.ts
index d510f6b660f..be1e59869eb 100644
--- a/web/test/fixtures/agent.ts
+++ b/web/test/fixtures/agent.ts
@@ -1,9 +1,11 @@
import type { AgentAppDetailWithSite } from '@dify/contracts/api/console/agent/types.gen'
import { zAgentAppDetailWithSite } from '@dify/contracts/api/console/agent/zod.gen'
import { AgentPermission } from '@/features/agent-v2/acl'
+import { createAppDetailFixture } from './app'
export function createAgentFixture(overrides: Partial = {}) {
return zAgentAppDetailWithSite.parse({
+ ...createAppDetailFixture(),
id: 'agent-1',
app_id: 'app-1',
name: 'Agent',
diff --git a/web/test/fixtures/app.ts b/web/test/fixtures/app.ts
new file mode 100644
index 00000000000..e53f02c530c
--- /dev/null
+++ b/web/test/fixtures/app.ts
@@ -0,0 +1,73 @@
+import type {
+ AppDetailSiteResponse,
+ AppDetailWithSite,
+} from '@dify/contracts/api/console/apps/types.gen'
+
+export function createAppSiteFixture(
+ overrides: Partial = {},
+): AppDetailSiteResponse {
+ return {
+ access_token: 'site-token',
+ app_base_url: 'https://apps.example.test',
+ chat_color_theme: null,
+ chat_color_theme_inverted: false,
+ code: 'site-token',
+ copyright: null,
+ created_at: 1,
+ created_by: null,
+ custom_disclaimer: '',
+ customize_domain: null,
+ customize_token_strategy: 'not_allow',
+ default_language: 'en-US',
+ description: null,
+ icon: null,
+ icon_background: null,
+ icon_type: null,
+ icon_url: null,
+ input_placeholder: null,
+ privacy_policy: null,
+ prompt_public: false,
+ show_workflow_steps: false,
+ title: 'App',
+ updated_at: 1,
+ updated_by: null,
+ use_icon_as_answer_icon: false,
+ ...overrides,
+ }
+}
+
+export function createAppDetailFixture(
+ overrides: Partial = {},
+): AppDetailWithSite {
+ return {
+ access_mode: null,
+ api_base_url: 'https://api.example.test/v1',
+ app_id: null,
+ bound_agent_id: null,
+ created_at: 1,
+ created_by: null,
+ deleted_tools: [],
+ description: '',
+ enable_api: true,
+ enable_site: true,
+ icon: null,
+ icon_background: null,
+ icon_type: null,
+ icon_url: null,
+ id: 'app-1',
+ maintainer: null,
+ max_active_requests: null,
+ mode: 'chat',
+ model_config: null,
+ name: 'App',
+ permission_keys: [],
+ site: null,
+ tags: [],
+ tracing: null,
+ updated_at: 1,
+ updated_by: null,
+ use_icon_as_answer_icon: false,
+ workflow: null,
+ ...overrides,
+ }
+}