diff --git a/api/controllers/common/schema.py b/api/controllers/common/schema.py index e3172f81c73..0fb2f3c5884 100644 --- a/api/controllers/common/schema.py +++ b/api/controllers/common/schema.py @@ -27,12 +27,18 @@ QueryParamDoc = TypedDict( "description": NotRequired[str], "enum": NotRequired[list[object]], "default": NotRequired[object], + "format": NotRequired[str], "minimum": NotRequired[int | float], "maximum": NotRequired[int | float], + "exclusiveMinimum": NotRequired[int | float], + "exclusiveMaximum": NotRequired[int | float], "minLength": NotRequired[int], "maxLength": NotRequired[int], + "pattern": NotRequired[str], "minItems": NotRequired[int], "maxItems": NotRequired[int], + "uniqueItems": NotRequired[bool], + "multipleOf": NotRequired[int | float], }, ) @@ -129,6 +135,7 @@ def query_params_from_model(model: type[BaseModel]) -> dict[str, QueryParamDoc]: """ schema = model.model_json_schema(ref_template=DEFAULT_REF_TEMPLATE_OPENAPI_3_0) + definitions = _schema_definitions(schema) properties = schema.get("properties", {}) if not isinstance(properties, Mapping): return {} @@ -141,7 +148,11 @@ def query_params_from_model(model: type[BaseModel]) -> dict[str, QueryParamDoc]: if not isinstance(name, str) or not isinstance(property_schema, Mapping): continue - params[name] = _query_param_from_property(property_schema, required=name in required_names) + params[name] = _query_param_from_property( + property_schema, + required=name in required_names, + definitions=definitions, + ) return params @@ -198,8 +209,18 @@ def _drop_malformed_defaulted_integer_params(model: type[BaseModel], params: dic params.pop(name) -def _query_param_from_property(property_schema: Mapping[str, Any], *, required: bool) -> QueryParamDoc: - param_schema = _nullable_property_schema(property_schema) +def _schema_definitions(schema: Mapping[str, Any]) -> Mapping[str, Any]: + definitions = schema.get("$defs") + return definitions if isinstance(definitions, Mapping) else {} + + +def _query_param_from_property( + property_schema: Mapping[str, Any], + *, + required: bool, + definitions: Mapping[str, Any], +) -> QueryParamDoc: + param_schema = _resolve_schema_ref(_nullable_property_schema(property_schema), definitions) param_doc: QueryParamDoc = {"in": "query", "required": required} description = param_schema.get("description") @@ -212,9 +233,16 @@ def _query_param_from_property(property_schema: Mapping[str, Any], *, required: if schema_type == "array": items = param_schema.get("items") if isinstance(items, Mapping): - item_type = items.get("type") + item_schema = _resolve_schema_ref(items, definitions) + item_type = item_schema.get("type") if isinstance(item_type, str): param_doc["items"] = {"type": item_type} + item_enum = item_schema.get("enum") + if isinstance(item_enum, list): + param_doc.setdefault("items", {})["enum"] = item_enum + item_format = item_schema.get("format") + if isinstance(item_format, str): + param_doc.setdefault("items", {})["format"] = item_format enum = param_schema.get("enum") if isinstance(enum, list): @@ -224,6 +252,10 @@ def _query_param_from_property(property_schema: Mapping[str, Any], *, required: if default is not None: param_doc["default"] = default + schema_format = param_schema.get("format") + if isinstance(schema_format, str): + param_doc["format"] = schema_format + minimum = param_schema.get("minimum") if isinstance(minimum, int | float): param_doc["minimum"] = minimum @@ -232,6 +264,14 @@ def _query_param_from_property(property_schema: Mapping[str, Any], *, required: if isinstance(maximum, int | float): param_doc["maximum"] = maximum + exclusive_minimum = param_schema.get("exclusiveMinimum") + if isinstance(exclusive_minimum, int | float): + param_doc["exclusiveMinimum"] = exclusive_minimum + + exclusive_maximum = param_schema.get("exclusiveMaximum") + if isinstance(exclusive_maximum, int | float): + param_doc["exclusiveMaximum"] = exclusive_maximum + min_length = param_schema.get("minLength") if isinstance(min_length, int): param_doc["minLength"] = min_length @@ -240,6 +280,10 @@ def _query_param_from_property(property_schema: Mapping[str, Any], *, required: if isinstance(max_length, int): param_doc["maxLength"] = max_length + pattern = param_schema.get("pattern") + if isinstance(pattern, str): + param_doc["pattern"] = pattern + min_items = param_schema.get("minItems") if isinstance(min_items, int): param_doc["minItems"] = min_items @@ -248,9 +292,31 @@ def _query_param_from_property(property_schema: Mapping[str, Any], *, required: if isinstance(max_items, int): param_doc["maxItems"] = max_items + unique_items = param_schema.get("uniqueItems") + if isinstance(unique_items, bool): + param_doc["uniqueItems"] = unique_items + + multiple_of = param_schema.get("multipleOf") + if isinstance(multiple_of, int | float): + param_doc["multipleOf"] = multiple_of + return param_doc +def _resolve_schema_ref(property_schema: Mapping[str, Any], definitions: Mapping[str, Any]) -> Mapping[str, Any]: + ref = property_schema.get("$ref") + if not isinstance(ref, str): + return property_schema + + ref_name = ref.rsplit("/", 1)[-1] + resolved = definitions.get(ref_name) + if not isinstance(resolved, Mapping): + return property_schema + + property_without_ref = {key: value for key, value in property_schema.items() if key != "$ref"} + return {**resolved, **property_without_ref} + + def _nullable_property_schema(property_schema: Mapping[str, Any]) -> Mapping[str, Any]: any_of = property_schema.get("anyOf") if not isinstance(any_of, list): diff --git a/api/controllers/console/app/advanced_prompt_template.py b/api/controllers/console/app/advanced_prompt_template.py index 0ad7eee7cdf..ca8e7096822 100644 --- a/api/controllers/console/app/advanced_prompt_template.py +++ b/api/controllers/console/app/advanced_prompt_template.py @@ -2,7 +2,7 @@ from flask import request from flask_restx import Resource, fields from pydantic import BaseModel, Field -from controllers.common.schema import DEFAULT_REF_TEMPLATE_OPENAPI_3_0 +from controllers.common.schema import DEFAULT_REF_TEMPLATE_OPENAPI_3_0, query_params_from_model from controllers.console import console_ns from controllers.console.wraps import account_initialization_required, setup_required from libs.login import login_required @@ -26,7 +26,7 @@ console_ns.schema_model( class AdvancedPromptTemplateList(Resource): @console_ns.doc("get_advanced_prompt_templates") @console_ns.doc(description="Get advanced prompt templates based on app mode and model configuration") - @console_ns.expect(console_ns.models[AdvancedPromptTemplateQuery.__name__]) + @console_ns.doc(params=query_params_from_model(AdvancedPromptTemplateQuery)) @console_ns.response( 200, "Prompt templates retrieved successfully", fields.List(fields.Raw(description="Prompt template data")) ) diff --git a/api/controllers/console/app/agent.py b/api/controllers/console/app/agent.py index 2c3adb6a018..833ca97fa72 100644 --- a/api/controllers/console/app/agent.py +++ b/api/controllers/console/app/agent.py @@ -2,7 +2,7 @@ from flask import request from flask_restx import Resource, fields from pydantic import BaseModel, Field, field_validator -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required, with_current_user @@ -36,7 +36,7 @@ class AgentLogApi(Resource): @console_ns.doc("get_agent_logs") @console_ns.doc(description="Get agent execution logs for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[AgentLogQuery.__name__]) + @console_ns.doc(params=query_params_from_model(AgentLogQuery)) @console_ns.response( 200, "Agent logs retrieved successfully", fields.List(fields.Raw(description="Agent log entries")) ) diff --git a/api/controllers/console/app/annotation.py b/api/controllers/console/app/annotation.py index d066177df3c..497f3653633 100644 --- a/api/controllers/console/app/annotation.py +++ b/api/controllers/console/app/annotation.py @@ -6,7 +6,7 @@ from flask_restx import Resource from pydantic import BaseModel, Field, TypeAdapter, field_validator from controllers.common.errors import NoFileUploadedError, TooManyFilesError -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.wraps import ( account_initialization_required, @@ -77,6 +77,11 @@ class AnnotationReplyStatusQuery(BaseModel): action: Literal["enable", "disable"] +class AnnotationHitHistoryListQuery(BaseModel): + page: int = Field(default=1, ge=1, description="Page number") + limit: int = Field(default=20, ge=1, description="Page size") + + class AnnotationFilePayload(BaseModel): message_id: str = Field(..., description="Message ID") @@ -99,6 +104,7 @@ register_schema_models( CreateAnnotationPayload, UpdateAnnotationPayload, AnnotationReplyStatusQuery, + AnnotationHitHistoryListQuery, AnnotationFilePayload, ) @@ -204,7 +210,7 @@ class AnnotationApi(Resource): @console_ns.doc("list_annotations") @console_ns.doc(description="Get annotations for an app with pagination") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[AnnotationListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(AnnotationListQuery)) @console_ns.response(200, "Annotations retrieved successfully") @console_ns.response(403, "Insufficient permissions") @setup_required @@ -424,11 +430,7 @@ class AnnotationHitHistoryListApi(Resource): @console_ns.doc("list_annotation_hit_histories") @console_ns.doc(description="Get hit histories for an annotation") @console_ns.doc(params={"app_id": "Application ID", "annotation_id": "Annotation ID"}) - @console_ns.expect( - console_ns.parser() - .add_argument("page", type=int, location="args", default=1, help="Page number") - .add_argument("limit", type=int, location="args", default=20, help="Page size") - ) + @console_ns.doc(params=query_params_from_model(AnnotationHitHistoryListQuery)) @console_ns.response( 200, "Hit histories retrieved successfully", diff --git a/api/controllers/console/app/app.py b/api/controllers/console/app/app.py index 818da5553d5..598bb13577b 100644 --- a/api/controllers/console/app/app.py +++ b/api/controllers/console/app/app.py @@ -14,7 +14,12 @@ from werkzeug.exceptions import BadRequest from controllers.common.fields import RedirectUrlResponse, SimpleResultResponse from controllers.common.helpers import FileInfo -from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models +from controllers.common.schema import ( + query_params_from_model, + register_enum_models, + register_response_schema_models, + register_schema_models, +) from controllers.console import console_ns from controllers.console.app.wraps import get_app_model, with_session from controllers.console.workspace.models import LoadBalancingPayload @@ -495,7 +500,7 @@ register_schema_models( class AppListApi(Resource): @console_ns.doc("list_apps") @console_ns.doc(description="Get list of applications with pagination and filtering") - @console_ns.expect(console_ns.models[AppListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(AppListQuery)) @console_ns.response(200, "Success", console_ns.models[AppPagination.__name__]) @setup_required @login_required @@ -737,7 +742,7 @@ class AppExportApi(Resource): @console_ns.doc("export_app") @console_ns.doc(description="Export application configuration as DSL") @console_ns.doc(params={"app_id": "Application ID to export"}) - @console_ns.expect(console_ns.models[AppExportQuery.__name__]) + @console_ns.doc(params=query_params_from_model(AppExportQuery)) @console_ns.response(200, "App exported successfully", console_ns.models[AppExportResponse.__name__]) @console_ns.response(403, "Insufficient permissions") @get_app_model diff --git a/api/controllers/console/app/audio.py b/api/controllers/console/app/audio.py index acf2215e45b..f0d904faef2 100644 --- a/api/controllers/console/app/audio.py +++ b/api/controllers/console/app/audio.py @@ -6,7 +6,7 @@ from pydantic import BaseModel, Field from werkzeug.exceptions import InternalServerError import services -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( AppUnavailableError, @@ -162,7 +162,7 @@ class TextModesApi(Resource): @console_ns.doc("get_text_to_speech_voices") @console_ns.doc(description="Get available TTS voices for a specific language") @console_ns.doc(params={"app_id": "App ID"}) - @console_ns.expect(console_ns.models[TextToSpeechVoiceQuery.__name__]) + @console_ns.doc(params=query_params_from_model(TextToSpeechVoiceQuery)) @console_ns.response( 200, "TTS voices retrieved successfully", fields.List(fields.Raw(description="Available voices")) ) diff --git a/api/controllers/console/app/conversation.py b/api/controllers/console/app/conversation.py index 7c20f025680..b9fcf2073d7 100644 --- a/api/controllers/console/app/conversation.py +++ b/api/controllers/console/app/conversation.py @@ -9,7 +9,7 @@ from sqlalchemy import func, or_ from sqlalchemy.orm import selectinload from werkzeug.exceptions import NotFound -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import ( @@ -91,7 +91,7 @@ class CompletionConversationApi(Resource): @console_ns.doc("list_completion_conversations") @console_ns.doc(description="Get completion conversations with pagination and filtering") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[CompletionConversationQuery.__name__]) + @console_ns.doc(params=query_params_from_model(CompletionConversationQuery)) @console_ns.response(200, "Success", console_ns.models[ConversationPaginationResponse.__name__]) @console_ns.response(403, "Insufficient permissions") @setup_required @@ -206,7 +206,7 @@ class ChatConversationApi(Resource): @console_ns.doc("list_chat_conversations") @console_ns.doc(description="Get chat conversations with pagination, filtering and summary") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[ChatConversationQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ChatConversationQuery)) @console_ns.response(200, "Success", console_ns.models[ConversationWithSummaryPaginationResponse.__name__]) @console_ns.response(403, "Insufficient permissions") @setup_required diff --git a/api/controllers/console/app/conversation_variables.py b/api/controllers/console/app/conversation_variables.py index beaef482756..9cf3f278eac 100644 --- a/api/controllers/console/app/conversation_variables.py +++ b/api/controllers/console/app/conversation_variables.py @@ -9,7 +9,7 @@ from pydantic import BaseModel, Field, field_validator from sqlalchemy import select from sqlalchemy.orm import sessionmaker -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required @@ -84,7 +84,7 @@ class ConversationVariablesApi(Resource): @console_ns.doc("get_conversation_variables") @console_ns.doc(description="Get conversation variables for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[ConversationVariablesQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ConversationVariablesQuery)) @console_ns.response( 200, "Conversation variables retrieved successfully", diff --git a/api/controllers/console/app/message.py b/api/controllers/console/app/message.py index 90f30126f43..e698f7e234c 100644 --- a/api/controllers/console/app/message.py +++ b/api/controllers/console/app/message.py @@ -11,7 +11,7 @@ from werkzeug.exceptions import InternalServerError, NotFound from controllers.common.controller_schemas import MessageFeedbackPayload as _MessageFeedbackPayloadBase from controllers.common.fields import SimpleResultResponse -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( CompletionRequestError, @@ -174,7 +174,7 @@ class ChatMessageListApi(Resource): @console_ns.doc("list_chat_messages") @console_ns.doc(description="Get chat messages for a conversation with pagination") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[ChatMessagesQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ChatMessagesQuery)) @console_ns.response(200, "Success", console_ns.models[MessageInfiniteScrollPaginationResponse.__name__]) @console_ns.response(404, "Conversation not found") @login_required @@ -372,7 +372,7 @@ class MessageFeedbackExportApi(Resource): @console_ns.doc("export_feedbacks") @console_ns.doc(description="Export user feedback data for Google Sheets") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[FeedbackExportQuery.__name__]) + @console_ns.doc(params=query_params_from_model(FeedbackExportQuery)) @console_ns.response(200, "Feedback data exported successfully") @console_ns.response(400, "Invalid parameters") @console_ns.response(500, "Internal server error") diff --git a/api/controllers/console/app/ops_trace.py b/api/controllers/console/app/ops_trace.py index a1123a580ea..2e20c3876a5 100644 --- a/api/controllers/console/app/ops_trace.py +++ b/api/controllers/console/app/ops_trace.py @@ -5,7 +5,7 @@ from flask_restx import Resource, fields from pydantic import BaseModel, Field from werkzeug.exceptions import BadRequest -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.error import TracingConfigCheckError, TracingConfigIsExist, TracingConfigNotExist from controllers.console.app.wraps import get_app_model @@ -36,7 +36,7 @@ class TraceAppConfigApi(Resource): @console_ns.doc("get_trace_app_config") @console_ns.doc(description="Get tracing configuration for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[TraceProviderQuery.__name__]) + @console_ns.doc(params=query_params_from_model(TraceProviderQuery)) @console_ns.response( 200, "Tracing configuration retrieved successfully", fields.Raw(description="Tracing configuration data") ) diff --git a/api/controllers/console/app/statistic.py b/api/controllers/console/app/statistic.py index 2595ed00813..61d871e885b 100644 --- a/api/controllers/console/app/statistic.py +++ b/api/controllers/console/app/statistic.py @@ -5,7 +5,7 @@ from flask import abort, jsonify, request from flask_restx import Resource, fields from pydantic import BaseModel, Field, field_validator -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required, with_current_user @@ -39,7 +39,7 @@ class DailyMessageStatistic(Resource): @console_ns.doc("get_daily_message_statistics") @console_ns.doc(description="Get daily message statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Daily message statistics retrieved successfully", @@ -99,7 +99,7 @@ class DailyConversationStatistic(Resource): @console_ns.doc("get_daily_conversation_statistics") @console_ns.doc(description="Get daily conversation statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Daily conversation statistics retrieved successfully", @@ -158,7 +158,7 @@ class DailyTerminalsStatistic(Resource): @console_ns.doc("get_daily_terminals_statistics") @console_ns.doc(description="Get daily terminal/end-user statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Daily terminal statistics retrieved successfully", @@ -218,7 +218,7 @@ class DailyTokenCostStatistic(Resource): @console_ns.doc("get_daily_token_cost_statistics") @console_ns.doc(description="Get daily token cost statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Daily token cost statistics retrieved successfully", @@ -281,7 +281,7 @@ class AverageSessionInteractionStatistic(Resource): @console_ns.doc("get_average_session_interaction_statistics") @console_ns.doc(description="Get average session interaction statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Average session interaction statistics retrieved successfully", @@ -360,7 +360,7 @@ class UserSatisfactionRateStatistic(Resource): @console_ns.doc("get_user_satisfaction_rate_statistics") @console_ns.doc(description="Get user satisfaction rate statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "User satisfaction rate statistics retrieved successfully", @@ -429,7 +429,7 @@ class AverageResponseTimeStatistic(Resource): @console_ns.doc("get_average_response_time_statistics") @console_ns.doc(description="Get average response time statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Average response time statistics retrieved successfully", @@ -489,7 +489,7 @@ class TokensPerSecondStatistic(Resource): @console_ns.doc("get_tokens_per_second_statistics") @console_ns.doc(description="Get tokens per second statistics for an application") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[StatisticTimeRangeQuery.__name__]) + @console_ns.doc(params=query_params_from_model(StatisticTimeRangeQuery)) @console_ns.response( 200, "Tokens per second statistics retrieved successfully", diff --git a/api/controllers/console/app/workflow.py b/api/controllers/console/app/workflow.py index 6a14937ffa0..22eeac955cc 100644 --- a/api/controllers/console/app/workflow.py +++ b/api/controllers/console/app/workflow.py @@ -15,6 +15,7 @@ from controllers.common.controller_schemas import DefaultBlockConfigQuery, Workf from controllers.common.errors import InvalidArgumentError from controllers.common.fields import NewAppResponse, SimpleResultResponse from controllers.common.schema import ( + query_params_from_model, register_response_schema_model, register_response_schema_models, register_schema_models, @@ -1054,7 +1055,7 @@ class DefaultBlockConfigApi(Resource): @console_ns.doc(params={"app_id": "Application ID", "block_type": "Block type"}) @console_ns.response(200, "Default block configuration retrieved successfully") @console_ns.response(404, "Block type not found") - @console_ns.expect(console_ns.models[DefaultBlockConfigQuery.__name__]) + @console_ns.doc(params=query_params_from_model(DefaultBlockConfigQuery)) @setup_required @login_required @account_initialization_required @@ -1149,7 +1150,7 @@ class WorkflowFeaturesApi(Resource): @console_ns.route("/apps//workflows") class PublishedAllWorkflowApi(Resource): - @console_ns.expect(console_ns.models[WorkflowListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowListQuery)) @console_ns.doc("get_all_published_workflows") @console_ns.doc(description="Get all published workflows for an application") @console_ns.doc(params={"app_id": "Application ID"}) diff --git a/api/controllers/console/app/workflow_app_log.py b/api/controllers/console/app/workflow_app_log.py index dec183a3004..72bececd999 100644 --- a/api/controllers/console/app/workflow_app_log.py +++ b/api/controllers/console/app/workflow_app_log.py @@ -7,7 +7,7 @@ from flask_restx import Resource from pydantic import BaseModel, Field, field_validator from sqlalchemy.orm import sessionmaker -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required @@ -166,7 +166,7 @@ class WorkflowAppLogApi(Resource): @console_ns.doc("get_workflow_app_logs") @console_ns.doc(description="Get workflow application execution logs") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[WorkflowAppLogQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowAppLogQuery)) @console_ns.response( 200, "Workflow app logs retrieved successfully", @@ -209,7 +209,7 @@ class WorkflowArchivedLogApi(Resource): @console_ns.doc("get_workflow_archived_logs") @console_ns.doc(description="Get workflow archived execution logs") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[WorkflowAppLogQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowAppLogQuery)) @console_ns.response( 200, "Workflow archived logs retrieved successfully", diff --git a/api/controllers/console/app/workflow_draft_variable.py b/api/controllers/console/app/workflow_draft_variable.py index 8ebd65eccf2..c23a0d63a62 100644 --- a/api/controllers/console/app/workflow_draft_variable.py +++ b/api/controllers/console/app/workflow_draft_variable.py @@ -10,7 +10,7 @@ from pydantic import BaseModel, Field from sqlalchemy.orm import sessionmaker from controllers.common.errors import InvalidArgumentError, NotFoundError -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.error import ( DraftWorkflowNotExist, @@ -248,7 +248,7 @@ def _api_prerequisite[T, **P, R]( @console_ns.route("/apps//workflows/draft/variables") class WorkflowVariableCollectionApi(Resource): - @console_ns.expect(console_ns.models[WorkflowDraftVariableListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowDraftVariableListQuery)) @console_ns.doc("get_workflow_variables") @console_ns.doc(description="Get draft workflow variables") @console_ns.doc(params={"app_id": "Application ID"}) diff --git a/api/controllers/console/app/workflow_statistic.py b/api/controllers/console/app/workflow_statistic.py index 05d579527e7..8b3c9967293 100644 --- a/api/controllers/console/app/workflow_statistic.py +++ b/api/controllers/console/app/workflow_statistic.py @@ -3,7 +3,7 @@ from flask_restx import Resource from pydantic import BaseModel, Field, field_validator from sqlalchemy.orm import sessionmaker -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.app.wraps import get_app_model from controllers.console.wraps import account_initialization_required, setup_required, with_current_user @@ -41,7 +41,7 @@ class WorkflowDailyRunsStatistic(Resource): @console_ns.doc("get_workflow_daily_runs_statistic") @console_ns.doc(description="Get workflow daily runs statistics") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[WorkflowStatisticQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowStatisticQuery)) @console_ns.response(200, "Daily runs statistics retrieved successfully") @get_app_model @setup_required @@ -80,7 +80,7 @@ class WorkflowDailyTerminalsStatistic(Resource): @console_ns.doc("get_workflow_daily_terminals_statistic") @console_ns.doc(description="Get workflow daily terminals statistics") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[WorkflowStatisticQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowStatisticQuery)) @console_ns.response(200, "Daily terminals statistics retrieved successfully") @get_app_model @setup_required @@ -119,7 +119,7 @@ class WorkflowDailyTokenCostStatistic(Resource): @console_ns.doc("get_workflow_daily_token_cost_statistic") @console_ns.doc(description="Get workflow daily token cost statistics") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[WorkflowStatisticQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowStatisticQuery)) @console_ns.response(200, "Daily token cost statistics retrieved successfully") @get_app_model @setup_required @@ -158,7 +158,7 @@ class WorkflowAverageAppInteractionStatistic(Resource): @console_ns.doc("get_workflow_average_app_interaction_statistic") @console_ns.doc(description="Get workflow average app interaction statistics") @console_ns.doc(params={"app_id": "Application ID"}) - @console_ns.expect(console_ns.models[WorkflowStatisticQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowStatisticQuery)) @console_ns.response(200, "Average app interaction statistics retrieved successfully") @setup_required @login_required diff --git a/api/controllers/console/app/workflow_trigger.py b/api/controllers/console/app/workflow_trigger.py index 11c8b2ee553..6a1bd843ee2 100644 --- a/api/controllers/console/app/workflow_trigger.py +++ b/api/controllers/console/app/workflow_trigger.py @@ -9,7 +9,7 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import NotFound from configs import dify_config -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from extensions.ext_database import db from fields.base import ResponseModel from libs.login import login_required @@ -86,7 +86,7 @@ register_schema_models( class WebhookTriggerApi(Resource): """Webhook Trigger API""" - @console_ns.expect(console_ns.models[Parser.__name__]) + @console_ns.doc(params=query_params_from_model(Parser)) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/auth/activate.py b/api/controllers/console/auth/activate.py index 65e278edb54..7e7810d86da 100644 --- a/api/controllers/console/auth/activate.py +++ b/api/controllers/console/auth/activate.py @@ -4,7 +4,7 @@ from pydantic import BaseModel, Field, field_validator from configs import dify_config from constants.languages import supported_language -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.error import AccountInFreezeError, AlreadyActivateError from extensions.ext_database import db @@ -69,7 +69,7 @@ register_schema_models( class ActivateCheckApi(Resource): @console_ns.doc("check_activation_token") @console_ns.doc(description="Check if activation token is valid") - @console_ns.expect(console_ns.models[ActivateCheckQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ActivateCheckQuery)) @console_ns.response( 200, "Success", diff --git a/api/controllers/console/billing/compliance.py b/api/controllers/console/billing/compliance.py index b0b364e54d2..8bc474964ab 100644 --- a/api/controllers/console/billing/compliance.py +++ b/api/controllers/console/billing/compliance.py @@ -2,6 +2,7 @@ from flask import request from flask_restx import Resource from pydantic import BaseModel, Field +from controllers.common.schema import query_params_from_model from libs.helper import extract_remote_ip from libs.login import login_required from models import Account @@ -30,7 +31,7 @@ console_ns.schema_model( @console_ns.route("/compliance/download") class ComplianceApi(Resource): - @console_ns.expect(console_ns.models[ComplianceDownloadQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ComplianceDownloadQuery)) @console_ns.doc("download_compliance_document") @console_ns.doc(description="Get compliance document download link") @setup_required diff --git a/api/controllers/console/datasets/website.py b/api/controllers/console/datasets/website.py index 335c8f60308..9b0d5132b15 100644 --- a/api/controllers/console/datasets/website.py +++ b/api/controllers/console/datasets/website.py @@ -4,7 +4,7 @@ from flask import request from flask_restx import Resource from pydantic import BaseModel -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.datasets.error import WebsiteCrawlError from controllers.console.wraps import account_initialization_required, setup_required @@ -57,7 +57,7 @@ class WebsiteCrawlStatusApi(Resource): @console_ns.doc("get_crawl_status") @console_ns.doc(description="Get website crawl status") @console_ns.doc(params={"job_id": "Crawl job ID", "provider": "Crawl provider (firecrawl/watercrawl/jinareader)"}) - @console_ns.expect(console_ns.models[WebsiteCrawlStatusQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WebsiteCrawlStatusQuery)) @console_ns.response(200, "Crawl status retrieved successfully") @console_ns.response(404, "Crawl job not found") @console_ns.response(400, "Invalid provider") diff --git a/api/controllers/console/explore/conversation.py b/api/controllers/console/explore/conversation.py index 9cebba496b5..5b625debeae 100644 --- a/api/controllers/console/explore/conversation.py +++ b/api/controllers/console/explore/conversation.py @@ -7,7 +7,7 @@ from sqlalchemy.orm import sessionmaker from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import ConversationRenamePayload -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console.app.error import AppUnavailableError from controllers.console.explore.error import NotChatAppError from controllers.console.explore.wraps import InstalledAppResource @@ -44,7 +44,7 @@ register_response_schema_models(console_ns, ResultResponse) endpoint="installed_app_conversations", ) class ConversationListApi(InstalledAppResource): - @console_ns.expect(console_ns.models[ConversationListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ConversationListQuery)) @with_current_user def get(self, current_user: Account, installed_app: InstalledApp): app_model = installed_app.app diff --git a/api/controllers/console/explore/message.py b/api/controllers/console/explore/message.py index a19355f90ba..88c0e679ad3 100644 --- a/api/controllers/console/explore/message.py +++ b/api/controllers/console/explore/message.py @@ -7,7 +7,7 @@ from pydantic import BaseModel, TypeAdapter from werkzeug.exceptions import InternalServerError, NotFound from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console.app.error import ( AppMoreLikeThisDisabledError, AppUnavailableError, @@ -60,7 +60,7 @@ register_response_schema_models(console_ns, ResultResponse, SuggestedQuestionsRe endpoint="installed_app_messages", ) class MessageListApi(InstalledAppResource): - @console_ns.expect(console_ns.models[MessageListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(MessageListQuery)) @with_current_user def get(self, current_user: Account, installed_app: InstalledApp): app_model = installed_app.app @@ -129,7 +129,7 @@ class MessageFeedbackApi(InstalledAppResource): endpoint="installed_app_more_like_this", ) class MessageMoreLikeThisApi(InstalledAppResource): - @console_ns.expect(console_ns.models[MoreLikeThisQuery.__name__]) + @console_ns.doc(params=query_params_from_model(MoreLikeThisQuery)) @with_current_user def get(self, current_user: Account, installed_app: InstalledApp, message_id: UUID): app_model = installed_app.app diff --git a/api/controllers/console/explore/saved_message.py b/api/controllers/console/explore/saved_message.py index cf48eeea725..b8c0a9bb841 100644 --- a/api/controllers/console/explore/saved_message.py +++ b/api/controllers/console/explore/saved_message.py @@ -5,7 +5,7 @@ from pydantic import TypeAdapter from werkzeug.exceptions import NotFound from controllers.common.controller_schemas import SavedMessageCreatePayload, SavedMessageListQuery -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import AppUnavailableError from controllers.console.explore.error import NotCompletionAppError @@ -24,7 +24,7 @@ register_response_schema_models(console_ns, ResultResponse) @console_ns.route("/installed-apps//saved-messages", endpoint="installed_app_saved_messages") class SavedMessageListApi(InstalledAppResource): - @console_ns.expect(console_ns.models[SavedMessageListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(SavedMessageListQuery)) @with_current_user def get(self, current_user: Account, installed_app: InstalledApp): app_model = installed_app.app diff --git a/api/controllers/console/snippets/snippet_workflow.py b/api/controllers/console/snippets/snippet_workflow.py index 59608afc554..c54d555686a 100644 --- a/api/controllers/console/snippets/snippet_workflow.py +++ b/api/controllers/console/snippets/snippet_workflow.py @@ -8,7 +8,7 @@ from pydantic import Field from sqlalchemy.orm import Session, sessionmaker from werkzeug.exceptions import BadRequest, InternalServerError, NotFound -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.app.error import DraftWorkflowNotExist, DraftWorkflowNotSync from controllers.console.app.workflow import ( @@ -283,7 +283,7 @@ class SnippetDefaultBlockConfigsApi(Resource): @console_ns.route("/snippets//workflows") class SnippetPublishedAllWorkflowApi(Resource): - @console_ns.expect(console_ns.models[SnippetWorkflowListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(SnippetWorkflowListQuery)) @console_ns.doc("get_all_snippet_published_workflows") @console_ns.doc(description="Get all published workflows for a snippet") @console_ns.doc(params={"snippet_id": "Snippet ID"}) diff --git a/api/controllers/console/snippets/snippet_workflow_draft_variable.py b/api/controllers/console/snippets/snippet_workflow_draft_variable.py index 491a78a9b93..5c52287daab 100644 --- a/api/controllers/console/snippets/snippet_workflow_draft_variable.py +++ b/api/controllers/console/snippets/snippet_workflow_draft_variable.py @@ -19,6 +19,7 @@ from flask_restx import Resource, marshal, marshal_with from sqlalchemy.orm import Session, sessionmaker from controllers.common.errors import InvalidArgumentError, NotFoundError +from controllers.common.schema import query_params_from_model from controllers.console import console_ns from controllers.console.app.error import DraftWorkflowNotExist from controllers.console.app.workflow_draft_variable import ( @@ -90,7 +91,7 @@ def _snippet_draft_var_prerequisite[T, **P, R]( @console_ns.route("/snippets//workflows/draft/variables") class SnippetWorkflowVariableCollectionApi(Resource): - @console_ns.expect(console_ns.models[WorkflowDraftVariableListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkflowDraftVariableListQuery)) @console_ns.doc("get_snippet_workflow_variables") @console_ns.doc(description="List draft workflow variables without values (paginated, snippet scope)") @console_ns.response( diff --git a/api/controllers/console/workspace/account.py b/api/controllers/console/workspace/account.py index e58f34dc3b9..1b83e9c4824 100644 --- a/api/controllers/console/workspace/account.py +++ b/api/controllers/console/workspace/account.py @@ -585,7 +585,7 @@ class EducationApi(Resource): @console_ns.route("/account/education/autocomplete") class EducationAutoCompleteApi(Resource): - @console_ns.expect(console_ns.models[EducationAutocompleteQuery.__name__]) + @console_ns.doc(params=query_params_from_model(EducationAutocompleteQuery)) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/endpoint.py b/api/controllers/console/workspace/endpoint.py index c539debf087..f69c5273177 100644 --- a/api/controllers/console/workspace/endpoint.py +++ b/api/controllers/console/workspace/endpoint.py @@ -12,7 +12,7 @@ from flask import request from flask_restx import Resource from pydantic import BaseModel, Field -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.wraps import ( account_initialization_required, @@ -201,7 +201,7 @@ class DeprecatedEndpointCreateApi(Resource): class EndpointListApi(Resource): @console_ns.doc("list_endpoints") @console_ns.doc(description="List plugin endpoints with pagination") - @console_ns.expect(console_ns.models[EndpointListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(EndpointListQuery)) @console_ns.response( 200, "Success", @@ -234,7 +234,7 @@ class EndpointListApi(Resource): class EndpointListForSinglePluginApi(Resource): @console_ns.doc("list_plugin_endpoints") @console_ns.doc(description="List endpoints for a specific plugin") - @console_ns.expect(console_ns.models[EndpointListForPluginQuery.__name__]) + @console_ns.doc(params=query_params_from_model(EndpointListForPluginQuery)) @console_ns.response( 200, "Success", diff --git a/api/controllers/console/workspace/model_providers.py b/api/controllers/console/workspace/model_providers.py index e77f17b2d0e..dc05b73436e 100644 --- a/api/controllers/console/workspace/model_providers.py +++ b/api/controllers/console/workspace/model_providers.py @@ -6,7 +6,7 @@ from flask_restx import Resource from pydantic import BaseModel, Field, field_validator from controllers.common.fields import SimpleResultResponse -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.wraps import ( account_initialization_required, @@ -98,7 +98,7 @@ register_response_schema_models(console_ns, SimpleResultResponse) @console_ns.route("/workspaces/current/model-providers") class ModelProviderListApi(Resource): - @console_ns.expect(console_ns.models[ParserModelList.__name__]) + @console_ns.doc(params=query_params_from_model(ParserModelList)) @setup_required @login_required @account_initialization_required @@ -115,7 +115,7 @@ class ModelProviderListApi(Resource): @console_ns.route("/workspaces/current/model-providers//credentials") class ModelProviderCredentialApi(Resource): - @console_ns.expect(console_ns.models[ParserCredentialId.__name__]) + @console_ns.doc(params=query_params_from_model(ParserCredentialId)) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/models.py b/api/controllers/console/workspace/models.py index 19e3fc60bbf..860acce443c 100644 --- a/api/controllers/console/workspace/models.py +++ b/api/controllers/console/workspace/models.py @@ -6,7 +6,12 @@ from flask_restx import Resource from pydantic import BaseModel, Field, field_validator from controllers.common.fields import SimpleResultResponse -from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models +from controllers.common.schema import ( + query_params_from_model, + register_enum_models, + register_response_schema_models, + register_schema_models, +) from controllers.console import console_ns from controllers.console.wraps import ( account_initialization_required, @@ -141,7 +146,7 @@ register_enum_models(console_ns, ModelType) @console_ns.route("/workspaces/current/default-model") class DefaultModelApi(Resource): - @console_ns.expect(console_ns.models[ParserGetDefault.__name__]) + @console_ns.doc(params=query_params_from_model(ParserGetDefault)) @setup_required @login_required @account_initialization_required @@ -267,7 +272,7 @@ class ModelProviderModelApi(Resource): @console_ns.route("/workspaces/current/model-providers//models/credentials") class ModelProviderModelCredentialApi(Resource): - @console_ns.expect(console_ns.models[ParserGetCredentials.__name__]) + @console_ns.doc(params=query_params_from_model(ParserGetCredentials)) @setup_required @login_required @account_initialization_required @@ -515,7 +520,7 @@ class ModelProviderModelValidateApi(Resource): @console_ns.route("/workspaces/current/model-providers//models/parameter-rules") class ModelProviderModelParameterRuleApi(Resource): - @console_ns.expect(console_ns.models[ParserParameter.__name__]) + @console_ns.doc(params=query_params_from_model(ParserParameter)) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py index d0538f2de22..1f9867f4587 100644 --- a/api/controllers/console/workspace/plugin.py +++ b/api/controllers/console/workspace/plugin.py @@ -10,7 +10,12 @@ from werkzeug.exceptions import Forbidden from configs import dify_config from controllers.common.fields import SuccessResponse -from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models +from controllers.common.schema import ( + query_params_from_model, + register_enum_models, + register_response_schema_models, + register_schema_models, +) from controllers.console import console_ns from controllers.console.workspace import plugin_permission_required from controllers.console.wraps import ( @@ -221,7 +226,7 @@ class PluginDebuggingKeyApi(Resource): @console_ns.route("/workspaces/current/plugin/list") class PluginListApi(Resource): - @console_ns.expect(console_ns.models[ParserList.__name__]) + @console_ns.doc(params=query_params_from_model(ParserList)) @setup_required @login_required @account_initialization_required @@ -274,7 +279,7 @@ class PluginListInstallationsFromIdsApi(Resource): @console_ns.route("/workspaces/current/plugin/icon") class PluginIconApi(Resource): - @console_ns.expect(console_ns.models[ParserIcon.__name__]) + @console_ns.doc(params=query_params_from_model(ParserIcon)) @setup_required def get(self): args = ParserIcon.model_validate(request.args.to_dict(flat=True)) @@ -290,7 +295,7 @@ class PluginIconApi(Resource): @console_ns.route("/workspaces/current/plugin/asset") class PluginAssetApi(Resource): - @console_ns.expect(console_ns.models[ParserAsset.__name__]) + @console_ns.doc(params=query_params_from_model(ParserAsset)) @setup_required @login_required @account_initialization_required @@ -425,7 +430,7 @@ class PluginInstallFromMarketplaceApi(Resource): @console_ns.route("/workspaces/current/plugin/marketplace/pkg") class PluginFetchMarketplacePkgApi(Resource): - @console_ns.expect(console_ns.models[ParserPluginIdentifierQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ParserPluginIdentifierQuery)) @setup_required @login_required @account_initialization_required @@ -449,7 +454,7 @@ class PluginFetchMarketplacePkgApi(Resource): @console_ns.route("/workspaces/current/plugin/fetch-manifest") class PluginFetchManifestApi(Resource): - @console_ns.expect(console_ns.models[ParserPluginIdentifierQuery.__name__]) + @console_ns.doc(params=query_params_from_model(ParserPluginIdentifierQuery)) @setup_required @login_required @account_initialization_required @@ -468,7 +473,7 @@ class PluginFetchManifestApi(Resource): @console_ns.route("/workspaces/current/plugin/tasks") class PluginFetchInstallTasksApi(Resource): - @console_ns.expect(console_ns.models[ParserTasks.__name__]) + @console_ns.doc(params=query_params_from_model(ParserTasks)) @setup_required @login_required @account_initialization_required @@ -655,7 +660,7 @@ class PluginFetchPermissionApi(Resource): @console_ns.route("/workspaces/current/plugin/parameters/dynamic-options") class PluginFetchDynamicSelectOptionsApi(Resource): - @console_ns.expect(console_ns.models[ParserDynamicOptions.__name__]) + @console_ns.doc(params=query_params_from_model(ParserDynamicOptions)) @setup_required @login_required @is_admin_or_owner_required @@ -817,7 +822,7 @@ class PluginAutoUpgradeExcludePluginApi(Resource): @console_ns.route("/workspaces/current/plugin/readme") class PluginReadmeApi(Resource): - @console_ns.expect(console_ns.models[ParserReadme.__name__]) + @console_ns.doc(params=query_params_from_model(ParserReadme)) @setup_required @login_required @account_initialization_required diff --git a/api/controllers/console/workspace/snippets.py b/api/controllers/console/workspace/snippets.py index 4bec22e091d..ca27066ef12 100644 --- a/api/controllers/console/workspace/snippets.py +++ b/api/controllers/console/workspace/snippets.py @@ -8,7 +8,7 @@ from sqlalchemy.orm import Session, sessionmaker from werkzeug.datastructures import MultiDict from werkzeug.exceptions import NotFound -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.console import console_ns from controllers.console.snippets.payloads import ( CreateSnippetPayload, @@ -89,7 +89,7 @@ snippet_pagination_model = console_ns.model("SnippetPagination", snippet_paginat @console_ns.route("/workspaces/current/customized-snippets") class CustomizedSnippetsApi(Resource): @console_ns.doc("list_customized_snippets") - @console_ns.expect(console_ns.models.get(SnippetListQuery.__name__)) + @console_ns.doc(params=query_params_from_model(SnippetListQuery)) @console_ns.response(200, "Snippets retrieved successfully", snippet_pagination_model) @setup_required @login_required diff --git a/api/controllers/console/workspace/workspace.py b/api/controllers/console/workspace/workspace.py index 60ecaa16bdb..ad41290987a 100644 --- a/api/controllers/console/workspace/workspace.py +++ b/api/controllers/console/workspace/workspace.py @@ -16,7 +16,7 @@ from controllers.common.errors import ( TooManyFilesError, UnsupportedFileTypeError, ) -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.console import console_ns from controllers.console.admin import admin_required from controllers.console.error import AccountNotLinkTenantError @@ -201,7 +201,7 @@ class TenantListApi(Resource): @console_ns.route("/all-workspaces") class WorkspaceListApi(Resource): - @console_ns.expect(console_ns.models[WorkspaceListQuery.__name__]) + @console_ns.doc(params=query_params_from_model(WorkspaceListQuery)) @setup_required @admin_required def get(self): diff --git a/api/controllers/service_api/app/conversation.py b/api/controllers/service_api/app/conversation.py index b298801ca02..f121374ca9a 100644 --- a/api/controllers/service_api/app/conversation.py +++ b/api/controllers/service_api/app/conversation.py @@ -10,7 +10,7 @@ from werkzeug.exceptions import BadRequest, NotFound import services from controllers.common.controller_schemas import ConversationRenamePayload -from controllers.common.schema import register_schema_models +from controllers.common.schema import query_params_from_model, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import NotChatAppError from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token @@ -138,7 +138,7 @@ register_schema_models( @service_api_ns.route("/conversations") class ConversationApi(Resource): - @service_api_ns.expect(service_api_ns.models[ConversationListQuery.__name__]) + @service_api_ns.doc(params=query_params_from_model(ConversationListQuery)) @service_api_ns.doc("list_conversations") @service_api_ns.doc(description="List all conversations for the current user") @service_api_ns.doc( @@ -250,7 +250,7 @@ class ConversationRenameApi(Resource): @service_api_ns.route("/conversations//variables") class ConversationVariablesApi(Resource): - @service_api_ns.expect(service_api_ns.models[ConversationVariablesQuery.__name__]) + @service_api_ns.doc(params=query_params_from_model(ConversationVariablesQuery)) @service_api_ns.doc("list_conversation_variables") @service_api_ns.doc(description="List all variables for a conversation") @service_api_ns.doc(params={"c_id": "Conversation ID"}) diff --git a/api/controllers/service_api/app/file_preview.py b/api/controllers/service_api/app/file_preview.py index 44f765d866d..11317016df3 100644 --- a/api/controllers/service_api/app/file_preview.py +++ b/api/controllers/service_api/app/file_preview.py @@ -8,7 +8,7 @@ from pydantic import BaseModel, Field from sqlalchemy import select from controllers.common.file_response import enforce_download_for_html -from controllers.common.schema import register_schema_model +from controllers.common.schema import query_params_from_model, register_schema_model from controllers.service_api import service_api_ns from controllers.service_api.app.error import ( FileAccessDeniedError, @@ -38,7 +38,7 @@ class FilePreviewApi(Resource): Files can only be accessed if they belong to messages within the requesting app's context. """ - @service_api_ns.expect(service_api_ns.models[FilePreviewQuery.__name__]) + @service_api_ns.doc(params=query_params_from_model(FilePreviewQuery)) @service_api_ns.doc("preview_file") @service_api_ns.doc(description="Preview or download a file uploaded via Service API") @service_api_ns.doc(params={"file_id": "UUID of the file to preview"}) diff --git a/api/controllers/service_api/app/message.py b/api/controllers/service_api/app/message.py index a77c4fb6608..bdb16794efe 100644 --- a/api/controllers/service_api/app/message.py +++ b/api/controllers/service_api/app/message.py @@ -9,7 +9,7 @@ from werkzeug.exceptions import BadRequest, InternalServerError, NotFound import services from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery from controllers.common.fields import SimpleResultStringListResponse -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import NotChatAppError from controllers.service_api.wraps import FetchUserArg, WhereisUserArg, validate_app_token @@ -39,7 +39,7 @@ register_response_schema_models(service_api_ns, ResultResponse, SimpleResultStri @service_api_ns.route("/messages") class MessageListApi(Resource): - @service_api_ns.expect(service_api_ns.models[MessageListQuery.__name__]) + @service_api_ns.doc(params=query_params_from_model(MessageListQuery)) @service_api_ns.doc("list_messages") @service_api_ns.doc(description="List messages in a conversation") @service_api_ns.doc( @@ -120,7 +120,7 @@ class MessageFeedbackApi(Resource): @service_api_ns.route("/app/feedbacks") class AppGetFeedbacksApi(Resource): - @service_api_ns.expect(service_api_ns.models[FeedbackListQuery.__name__]) + @service_api_ns.doc(params=query_params_from_model(FeedbackListQuery)) @service_api_ns.doc("get_app_feedbacks") @service_api_ns.doc(description="Get all feedbacks for the application") @service_api_ns.doc( diff --git a/api/controllers/service_api/app/workflow.py b/api/controllers/service_api/app/workflow.py index 975fdf0cd92..04fb9900a2f 100644 --- a/api/controllers/service_api/app/workflow.py +++ b/api/controllers/service_api/app/workflow.py @@ -12,7 +12,7 @@ from werkzeug.exceptions import BadRequest, InternalServerError, NotFound from controllers.common.controller_schemas import WorkflowRunPayload as WorkflowRunPayloadBase from controllers.common.fields import SimpleResultResponse -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.service_api import service_api_ns from controllers.service_api.app.error import ( CompletionRequestError, @@ -407,7 +407,7 @@ class WorkflowTaskStopApi(Resource): @service_api_ns.route("/workflows/logs") class WorkflowAppLogApi(Resource): - @service_api_ns.expect(service_api_ns.models[WorkflowLogQuery.__name__]) + @service_api_ns.doc(params=query_params_from_model(WorkflowLogQuery)) @service_api_ns.doc("get_workflow_logs") @service_api_ns.doc(description="Get workflow execution logs") @service_api_ns.doc( diff --git a/api/controllers/web/message.py b/api/controllers/web/message.py index e40e57c4367..ea941401129 100644 --- a/api/controllers/web/message.py +++ b/api/controllers/web/message.py @@ -7,7 +7,7 @@ from pydantic import BaseModel, Field, TypeAdapter from werkzeug.exceptions import InternalServerError, NotFound from controllers.common.controller_schemas import MessageFeedbackPayload, MessageListQuery -from controllers.common.schema import register_response_schema_models, register_schema_models +from controllers.common.schema import query_params_from_model, register_response_schema_models, register_schema_models from controllers.web import web_ns from controllers.web.error import ( AppMoreLikeThisDisabledError, @@ -156,7 +156,7 @@ class MessageFeedbackApi(WebApiResource): class MessageMoreLikeThisApi(WebApiResource): @web_ns.doc("Generate More Like This") @web_ns.doc(description="Generate a new completion similar to an existing message (completion apps only).") - @web_ns.expect(web_ns.models[MessageMoreLikeThisQuery.__name__]) + @web_ns.doc(params=query_params_from_model(MessageMoreLikeThisQuery)) @web_ns.doc( responses={ 200: "Success", diff --git a/api/dev/generate_swagger_specs.py b/api/dev/generate_swagger_specs.py index 6b959b6d17e..d3b62511ea6 100644 --- a/api/dev/generate_swagger_specs.py +++ b/api/dev/generate_swagger_specs.py @@ -330,99 +330,6 @@ def _replace_legacy_refs(value: object) -> object: HTTP_METHODS = {"delete", "get", "head", "options", "patch", "post", "put", "trace"} -def _resolve_component_schema(payload: dict[str, object], schema: object) -> dict[str, object] | None: - if not isinstance(schema, dict): - return None - - ref = schema.get("$ref") - if isinstance(ref, str) and ref.startswith("#/components/schemas/"): - name = ref.removeprefix("#/components/schemas/") - components = payload.get("components") - if not isinstance(components, dict): - return None - schemas = components.get("schemas") - if not isinstance(schemas, dict): - return None - resolved = schemas.get(name) - return resolved if isinstance(resolved, dict) else None - - return schema - - -def _request_body_schema(request_body: object) -> object | None: - if not isinstance(request_body, dict): - return None - content = request_body.get("content") - if not isinstance(content, dict): - return None - media_type = content.get("application/json") - if not isinstance(media_type, dict): - return None - return media_type.get("schema") - - -def _query_parameters_from_schema(schema: dict[str, object]) -> list[dict[str, object]]: - properties = schema.get("properties") - if not isinstance(properties, dict): - return [] - - required = schema.get("required") - required_names = set(required) if isinstance(required, list) else set() - parameters: list[dict[str, object]] = [] - - for name, property_schema in sorted(properties.items()): - if not isinstance(name, str) or not isinstance(property_schema, dict): - continue - schema_copy = dict(property_schema) - description = schema_copy.get("description") - parameter: dict[str, object] = { - "name": name, - "in": "query", - "required": name in required_names, - "schema": schema_copy, - } - if isinstance(description, str): - parameter["description"] = description - parameters.append(parameter) - - return parameters - - -def _move_get_request_bodies_to_query_parameters(payload: dict[str, object]) -> dict[str, object]: - """Represent GET request bodies as query parameters in exported specs.""" - - paths = payload.get("paths") - if not isinstance(paths, dict): - return payload - - for path_item in paths.values(): - if not isinstance(path_item, dict): - continue - operation = path_item.get("get") - if not isinstance(operation, dict) or "requestBody" not in operation: - continue - - schema = _resolve_component_schema(payload, _request_body_schema(operation.get("requestBody"))) - existing_parameters = operation.get("parameters") - parameters = list(existing_parameters) if isinstance(existing_parameters, list) else [] - existing_query_names = { - parameter.get("name") - for parameter in parameters - if isinstance(parameter, dict) and parameter.get("in") == "query" - } - - if schema is not None: - for parameter in _query_parameters_from_schema(schema): - if parameter["name"] not in existing_query_names: - parameters.append(parameter) - - if parameters: - operation["parameters"] = parameters - operation.pop("requestBody", None) - - return payload - - def _deduplicate_operation_ids(payload: dict[str, object]) -> dict[str, object]: """Make operationId values unique while preserving already-unique IDs.""" @@ -497,7 +404,6 @@ def generate_specs(output_dir: Path) -> list[Path]: if not isinstance(payload, dict): raise RuntimeError(f"unexpected response payload for {target.route}") payload = _merge_registered_schemas(payload, target.namespace) - payload = _move_get_request_bodies_to_query_parameters(payload) payload = _deduplicate_operation_ids(payload) payload = drop_null_values(payload) payload = sort_openapi_arrays(payload) diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md index c0d9fb653a3..cada682d092 100644 --- a/api/openapi/markdown/console-openapi.md +++ b/api/openapi/markdown/console-openapi.md @@ -283,9 +283,9 @@ Check if activation token is valid | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| email | query | | No | | +| email | query | | No | string | | token | query | | Yes | string | -| workspace_id | query | | No | | +| workspace_id | query | | No | string | #### Responses @@ -570,13 +570,13 @@ Get list of applications with pagination and filtering | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| creator_ids | query | Filter by creator account IDs | No | | -| is_created_by_me | query | Filter by creator | No | | +| creator_ids | query | Filter by creator account IDs | No | [ string ] | +| is_created_by_me | query | Filter by creator | No | boolean | | limit | query | Page size (1-100) | No | integer,
**Default:** 20 | | mode | query | App mode filter | No | string,
**Available values:** "advanced-chat", "agent", "agent-chat", "all", "channel", "chat", "completion", "workflow",
**Default:** all | -| name | query | Filter by app name | No | | +| name | query | Filter by app name | No | string | | page | query | Page number (1-99999) | No | integer,
**Default:** 1 | -| tag_ids | query | Filter by tag IDs | No | | +| tag_ids | query | Filter by tag IDs | No | [ string ] | #### Responses @@ -1406,12 +1406,12 @@ Get chat conversations with pagination, filtering and summary | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | | annotation_status | query | Annotation status filter | No | string,
**Available values:** "all", "annotated", "not_annotated",
**Default:** all | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| keyword | query | Search keyword | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| keyword | query | Search keyword | No | string | | limit | query | Page size (1-100) | No | integer,
**Default:** 20 | | page | query | Page number | No | integer,
**Default:** 1 | | sort_by | query | Sort field and direction | No | string,
**Available values:** "-created_at", "-updated_at", "created_at", "updated_at",
**Default:** -updated_at | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -1465,7 +1465,7 @@ Get chat messages for a conversation with pagination | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | | conversation_id | query | Conversation ID | Yes | string | -| first_id | query | First message ID for pagination | No | | +| first_id | query | First message ID for pagination | No | string | | limit | query | Number of messages to return (1-100) | No | integer,
**Default:** 20 | #### Responses @@ -1517,11 +1517,11 @@ Get completion conversations with pagination and filtering | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | | annotation_status | query | Annotation status filter | No | string,
**Available values:** "all", "annotated", "not_annotated",
**Default:** all | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| keyword | query | Search keyword | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| keyword | query | Search keyword | No | string | | limit | query | Page size (1-100) | No | integer,
**Default:** 20 | | page | query | Page number | No | integer,
**Default:** 1 | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -1683,7 +1683,7 @@ Export application configuration as DSL | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID to export | Yes | string | | include_secret | query | Include secrets in export | No | boolean | -| workflow_id | query | Specific workflow ID to export | No | | +| workflow_id | query | Specific workflow ID to export | No | string | #### Responses @@ -1723,12 +1723,12 @@ Export user feedback data for Google Sheets | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end_date | query | End date (YYYY-MM-DD) | No | | +| end_date | query | End date (YYYY-MM-DD) | No | string | | format | query | Export format | No | string,
**Available values:** "csv", "json",
**Default:** csv | -| from_source | query | Filter by feedback source | No | | -| has_comment | query | Only include feedback with comments | No | | -| rating | query | Filter by rating | No | | -| start_date | query | Start date (YYYY-MM-DD) | No | | +| from_source | query | Filter by feedback source | No | string,
**Available values:** "admin", "user" | +| has_comment | query | Only include feedback with comments | No | boolean | +| rating | query | Filter by rating | No | string,
**Available values:** "dislike", "like" | +| start_date | query | Start date (YYYY-MM-DD) | No | string | #### Responses @@ -1968,8 +1968,8 @@ Get average response time statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -1985,8 +1985,8 @@ Get average session interaction statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2002,8 +2002,8 @@ Get daily conversation statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2019,8 +2019,8 @@ Get daily terminal/end-user statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2036,8 +2036,8 @@ Get daily message statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2053,8 +2053,8 @@ Get daily token cost statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2070,8 +2070,8 @@ Get tokens per second statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2087,8 +2087,8 @@ Get user satisfaction rate statistics for an application | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date (YYYY-MM-DD HH:MM) | No | | +| end | query | End date (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2309,15 +2309,15 @@ Get workflow application execution logs | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| created_at__after | query | Filter logs created after this timestamp | No | | -| created_at__before | query | Filter logs created before this timestamp | No | | -| created_by_account | query | Filter by account | No | | -| created_by_end_user_session_id | query | Filter by end user session ID | No | | +| created_at__after | query | Filter logs created after this timestamp | No | dateTime | +| created_at__before | query | Filter logs created before this timestamp | No | dateTime | +| created_by_account | query | Filter by account | No | string | +| created_by_end_user_session_id | query | Filter by end user session ID | No | string | | detail | query | Whether to return detailed logs | No | boolean | -| keyword | query | Search keyword for filtering logs | No | | +| keyword | query | Search keyword for filtering logs | No | string | | limit | query | Number of items per page (1-100) | No | integer,
**Default:** 20 | | page | query | Page number (1-99999) | No | integer,
**Default:** 1 | -| status | query | Execution status filter (succeeded, failed, stopped, partial-succeeded) | No | | +| status | query | Execution status filter (succeeded, failed, stopped, partial-succeeded) | No | string,
**Available values:** "failed", "partial-succeeded", "paused", "running", "scheduled", "stopped", "succeeded" | #### Responses @@ -2335,15 +2335,15 @@ Get workflow archived execution logs | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| created_at__after | query | Filter logs created after this timestamp | No | | -| created_at__before | query | Filter logs created before this timestamp | No | | -| created_by_account | query | Filter by account | No | | -| created_by_end_user_session_id | query | Filter by end user session ID | No | | +| created_at__after | query | Filter logs created after this timestamp | No | dateTime | +| created_at__before | query | Filter logs created before this timestamp | No | dateTime | +| created_by_account | query | Filter by account | No | string | +| created_by_end_user_session_id | query | Filter by end user session ID | No | string | | detail | query | Whether to return detailed logs | No | boolean | -| keyword | query | Search keyword for filtering logs | No | | +| keyword | query | Search keyword for filtering logs | No | string | | limit | query | Number of items per page (1-100) | No | integer,
**Default:** 20 | | page | query | Page number (1-99999) | No | integer,
**Default:** 1 | -| status | query | Execution status filter (succeeded, failed, stopped, partial-succeeded) | No | | +| status | query | Execution status filter (succeeded, failed, stopped, partial-succeeded) | No | string,
**Available values:** "failed", "partial-succeeded", "paused", "running", "scheduled", "stopped", "succeeded" | #### Responses @@ -2710,8 +2710,8 @@ Get workflow average app interaction statistics | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date and time (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | | +| end | query | End date and time (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2727,8 +2727,8 @@ Get workflow daily runs statistics | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date and time (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | | +| end | query | End date and time (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2744,8 +2744,8 @@ Get workflow daily terminals statistics | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date and time (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | | +| end | query | End date and time (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2761,8 +2761,8 @@ Get workflow daily token cost statistics | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| end | query | End date and time (YYYY-MM-DD HH:MM) | No | | -| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | | +| end | query | End date and time (YYYY-MM-DD HH:MM) | No | string | +| start | query | Start date and time (YYYY-MM-DD HH:MM) | No | string | #### Responses @@ -2783,7 +2783,7 @@ Get all published workflows for an application | limit | query | | No | integer,
**Default:** 10 | | named_only | query | | No | boolean | | page | query | | No | integer,
**Default:** 1 | -| user_id | query | | No | | +| user_id | query | | No | string | #### Responses @@ -2819,7 +2819,7 @@ Get default block configuration by type | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | | block_type | path | Block type | Yes | string | -| q | query | | No | | +| q | query | | No | string | #### Responses @@ -3467,8 +3467,8 @@ Get draft workflow variables | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | app_id | path | Application ID | Yes | string | -| limit | query | Number of items per page (1-100) | No | string | -| page | query | Page number (1-100000) | No | string | +| limit | query | Items per page | No | integer,
**Default:** 20 | +| page | query | Page number | No | integer,
**Default:** 1 | #### Responses @@ -3667,9 +3667,7 @@ Full value for one declared output of a published run. | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| credential_id | query | | No | | -| datasource_type | query | | Yes | string | -| inputs | query | | Yes | object | +| node_id | query | | Yes | string | | app_id | path | | Yes | string | #### Responses @@ -5762,9 +5760,9 @@ Request body: | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| last_id | query | | No | | +| last_id | query | | No | string | | limit | query | | No | integer,
**Default:** 20 | -| pinned | query | | No | | +| pinned | query | | No | boolean | | installed_app_id | path | | Yes | string | #### Responses @@ -5841,7 +5839,7 @@ Request body: | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | conversation_id | query | Conversation UUID | Yes | string | -| first_id | query | First message ID for pagination | No | | +| first_id | query | First message ID for pagination | No | string | | limit | query | Number of messages to return (1-100) | No | integer,
**Default:** 20 | | installed_app_id | path | | Yes | string | @@ -5935,7 +5933,7 @@ Request body: | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| last_id | query | | No | | +| last_id | query | | No | string | | limit | query | | No | integer,
**Default:** 20 | | installed_app_id | path | | Yes | string | @@ -8155,7 +8153,7 @@ Get website crawl status | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | job_id | path | Crawl job ID | Yes | string | -| provider | query | Crawl provider (firecrawl/watercrawl/jinareader) | No | string | +| provider | query | Crawl provider (firecrawl/watercrawl/jinareader) | Yes | string,
**Available values:** "firecrawl", "jinareader", "watercrawl" | #### Responses @@ -8267,12 +8265,12 @@ Get list of available agent providers | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| creators | query | Filter by creator account IDs | No | | -| is_published | query | Filter by published status | No | | -| keyword | query | | No | | +| creators | query | Filter by creator account IDs | No | [ string ] | +| is_published | query | Filter by published status | No | boolean | +| keyword | query | | No | string | | limit | query | | No | integer,
**Default:** 20 | | page | query | | No | integer,
**Default:** 1 | -| tag_ids | query | Filter by tag IDs | No | | +| tag_ids | query | Filter by tag IDs | No | [ string ] | #### Responses @@ -8448,7 +8446,7 @@ Increment snippet use count by 1 | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| model_type | query | | Yes | [ModelType](#modeltype) | +| model_type | query | Enum class for model type. | Yes | string,
**Available values:** "llm", "moderation", "rerank", "speech2text", "text-embedding", "tts" | #### Responses @@ -8747,7 +8745,7 @@ Update a plugin endpoint | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| model_type | query | | No | | +| model_type | query | Enum class for model type. | No | string,
**Available values:** "llm", "moderation", "rerank", "speech2text", "text-embedding", "tts" | #### Responses @@ -8792,7 +8790,7 @@ Update a plugin endpoint | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| credential_id | query | | No | | +| credential_id | query | | No | string | | provider | path | | Yes | string | #### Responses @@ -8952,10 +8950,10 @@ Update a plugin endpoint | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| config_from | query | | No | | -| credential_id | query | | No | | +| config_from | query | | No | string | +| credential_id | query | | No | string | | model | query | | Yes | string | -| model_type | query | | Yes | [ModelType](#modeltype) | +| model_type | query | Enum class for model type. | Yes | string,
**Available values:** "llm", "moderation", "rerank", "speech2text", "text-embedding", "tts" | | provider | path | | Yes | string | #### Responses @@ -9320,7 +9318,7 @@ Returns permission flags that control workspace features like member invitations | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | action | query | | Yes | string | -| credential_id | query | | No | | +| credential_id | query | | No | string | | parameter | query | | Yes | string | | plugin_id | query | | Yes | string | | provider | query | | Yes | string | @@ -11466,6 +11464,13 @@ Soft lifecycle state for Agent records. | page | integer | | Yes | | total | integer | | Yes | +#### AnnotationHitHistoryListQuery + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| limit | integer,
**Default:** 20 | Page size | No | +| page | integer,
**Default:** 1 | Page number | No | + #### AnnotationList | Name | Type | Description | Required | diff --git a/api/openapi/markdown/openapi-openapi.md b/api/openapi/markdown/openapi-openapi.md index f0394f6cc56..625699c0619 100644 --- a/api/openapi/markdown/openapi-openapi.md +++ b/api/openapi/markdown/openapi-openapi.md @@ -81,7 +81,7 @@ User-scoped operations | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | limit | query | | No | integer,
**Default:** 20 | -| mode | query | | No | string | +| mode | query | | No | string,
**Available values:** "advanced-chat", "agent", "agent-chat", "channel", "chat", "completion", "rag-pipeline", "workflow" | | name | query | | No | string | | page | query | | No | integer,
**Default:** 1 | | tag | query | | No | string | @@ -318,7 +318,7 @@ Upload a file to use as an input variable when running the app | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | limit | query | | No | integer,
**Default:** 20 | -| mode | query | | No | string | +| mode | query | | No | string,
**Available values:** "advanced-chat", "agent", "agent-chat", "channel", "chat", "completion", "rag-pipeline", "workflow" | | name | query | | No | string | | page | query | | No | integer,
**Default:** 1 | diff --git a/api/openapi/markdown/service-openapi.md b/api/openapi/markdown/service-openapi.md index 47350fa8479..5c0738062d6 100644 --- a/api/openapi/markdown/service-openapi.md +++ b/api/openapi/markdown/service-openapi.md @@ -264,7 +264,7 @@ Supports pagination using last_id and limit parameters. | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| last_id | query | Last conversation ID for pagination | No | | +| last_id | query | Last conversation ID for pagination | No | string | | limit | query | Number of conversations to return | No | integer,
**Default:** 20 | | sort_by | query | Sort order for conversations | No | string,
**Available values:** "-created_at", "-updated_at", "created_at", "updated_at",
**Default:** -updated_at | @@ -327,9 +327,9 @@ Conversational variables are only available for chat applications. | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | c_id | path | Conversation ID | Yes | string | -| last_id | query | Last variable ID for pagination | No | | +| last_id | query | Last variable ID for pagination | No | string | | limit | query | Number of variables to return | No | integer,
**Default:** 20 | -| variable_name | query | Filter variables by name | No | | +| variable_name | query | Filter variables by name | No | string | #### Responses @@ -1570,7 +1570,7 @@ Retrieves messages with pagination support using first_id. | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | | conversation_id | query | Conversation UUID | Yes | string | -| first_id | query | First message ID for pagination | No | | +| first_id | query | First message ID for pagination | No | string | | limit | query | Number of messages to return (1-100) | No | integer,
**Default:** 20 | #### Responses @@ -1722,14 +1722,14 @@ Returns paginated workflow execution logs with filtering options. | Name | Located in | Description | Required | Schema | | ---- | ---------- | ----------- | -------- | ------ | -| created_at__after | query | | No | | -| created_at__before | query | | No | | -| created_by_account | query | | No | | -| created_by_end_user_session_id | query | | No | | -| keyword | query | | No | | +| created_at__after | query | | No | string | +| created_at__before | query | | No | string | +| created_by_account | query | | No | string | +| created_by_end_user_session_id | query | | No | string | +| keyword | query | | No | string | | limit | query | | No | integer,
**Default:** 20 | | page | query | | No | integer,
**Default:** 1 | -| status | query | | No | | +| status | query | | No | string,
**Available values:** "failed", "stopped", "succeeded" | #### Responses 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 bfc98f5f517..03af7643f3c 100644 --- a/api/tests/unit_tests/commands/test_generate_swagger_specs.py +++ b/api/tests/unit_tests/commands/test_generate_swagger_specs.py @@ -95,7 +95,7 @@ def test_generate_specs_writes_unique_operation_ids(tmp_path): assert len(operation_ids) == len(set(operation_ids)) -def test_generate_specs_moves_get_request_bodies_to_query_parameters(tmp_path): +def test_generate_specs_writes_get_operations_without_request_bodies(tmp_path): module = _load_generate_swagger_specs_module() written_paths = module.generate_specs(tmp_path) diff --git a/api/tests/unit_tests/controllers/common/test_schema.py b/api/tests/unit_tests/controllers/common/test_schema.py index 9cd83ad54db..b8d99327872 100644 --- a/api/tests/unit_tests/controllers/common/test_schema.py +++ b/api/tests/unit_tests/controllers/common/test_schema.py @@ -1,4 +1,5 @@ import sys +from datetime import datetime from enum import StrEnum from typing import Literal from unittest.mock import MagicMock, patch @@ -43,6 +44,8 @@ class QueryModel(BaseModel): page: int = Field(default=1, ge=1, le=100, description="Page number") keyword: str | None = Field(default=None, min_length=1, max_length=50, description="Search keyword") status: Literal["active", "inactive"] | None = Field(default=None, description="Status filter") + enum_status: StatusEnum | None = Field(default=None, description="Enum status filter") + created_at: datetime | None = Field(default=None, description="Creation time") app_id: str = Field(..., alias="appId", description="Application ID") tag_ids: list[str] = Field(default_factory=list, min_length=1, max_length=3, description="Tag IDs") ambiguous: int | str | None = Field(default=None, description="Ambiguous query parameter") @@ -303,6 +306,20 @@ def test_query_params_from_model_builds_flask_restx_doc_params(): "type": "string", "enum": ["active", "inactive"], } + assert params["enum_status"] == { + "in": "query", + "required": False, + "description": "Enum status filter", + "type": "string", + "enum": ["active", "inactive"], + } + assert params["created_at"] == { + "in": "query", + "required": False, + "description": "Creation time", + "type": "string", + "format": "date-time", + } assert params["appId"] == { "in": "query", "required": True, diff --git a/api/tests/unit_tests/controllers/test_swagger.py b/api/tests/unit_tests/controllers/test_swagger.py index fae4268210d..8ad590c4dd0 100644 --- a/api/tests/unit_tests/controllers/test_swagger.py +++ b/api/tests/unit_tests/controllers/test_swagger.py @@ -1,5 +1,7 @@ """OpenAPI JSON rendering tests for Flask-RESTX API blueprints.""" +from collections.abc import Iterator + import pytest from flask import Flask @@ -31,6 +33,17 @@ def _parameters_by_name(operation: dict[str, object]) -> dict[str, dict[str, obj return result +def _get_operations(payload: dict[str, object]) -> Iterator[tuple[str, dict[str, object]]]: + paths = payload["paths"] + assert isinstance(paths, dict) + for path, path_item in paths.items(): + if not isinstance(path, str) or not isinstance(path_item, dict): + continue + operation = path_item.get("get") + if isinstance(operation, dict): + yield path, operation + + def _multipart_form_schema(operation: dict[str, object]) -> dict[str, object]: request_body = operation.get("requestBody") assert isinstance(request_body, dict) @@ -93,6 +106,8 @@ def test_openapi_json_endpoints_render(monkeypatch: pytest.MonkeyPatch): assert isinstance(payload["components"]["schemas"], dict) missing_refs = _schema_refs(payload) - set(payload["components"]["schemas"]) assert not missing_refs + get_request_body_paths = [path for path, operation in _get_operations(payload) if "requestBody" in operation] + assert not get_request_body_paths assert app.config["RESTX_INCLUDE_ALL_MODELS"] is True diff --git a/cli/src/api/apps.ts b/cli/src/api/apps.ts index 40bb5c80053..ea0e41c252f 100644 --- a/cli/src/api/apps.ts +++ b/cli/src/api/apps.ts @@ -1,4 +1,4 @@ -import type { AppDescribeResponse, AppListResponse } from '@dify/contracts/api/openapi/types.gen' +import type { AppDescribeResponse, AppListResponse, AppMode } from '@dify/contracts/api/openapi/types.gen' import type { OpenApiClient } from '@/http/orpc' import type { HttpClient } from '@/http/types' import { createOpenApiClient } from '@/http/orpc' @@ -7,7 +7,7 @@ export type ListQuery = { readonly workspaceId: string readonly page?: number readonly limit?: number - readonly mode?: string + readonly mode?: AppMode | '' readonly name?: string readonly tag?: string } diff --git a/cli/src/commands/get/app/index.ts b/cli/src/commands/get/app/index.ts index 9b60ab8e956..47594813704 100644 --- a/cli/src/commands/get/app/index.ts +++ b/cli/src/commands/get/app/index.ts @@ -8,6 +8,7 @@ import { runGetApp } from './run' const APP_MODE_VALUES: readonly AppMode[] = [ 'advanced-chat', + 'agent', 'agent-chat', 'channel', 'chat', @@ -56,7 +57,7 @@ export default class GetApp extends DifyCommand { allWorkspaces: flags['all-workspaces'], page: flags.page, limitRaw: flags.limit, - mode: flags.mode, + mode: flags.mode as AppMode | undefined, name: flags.name, tag: flags.tag, format, diff --git a/cli/src/commands/get/app/run.ts b/cli/src/commands/get/app/run.ts index 5c061d2548f..102cf066499 100644 --- a/cli/src/commands/get/app/run.ts +++ b/cli/src/commands/get/app/run.ts @@ -17,7 +17,7 @@ export type GetAppOptions = { readonly allWorkspaces?: boolean readonly page?: number readonly limitRaw?: string - readonly mode?: string + readonly mode?: AppMode readonly name?: string readonly tag?: string readonly format?: string diff --git a/packages/contracts/generated/api/console/activate/types.gen.ts b/packages/contracts/generated/api/console/activate/types.gen.ts index 5160896b75c..aff306f3211 100644 --- a/packages/contracts/generated/api/console/activate/types.gen.ts +++ b/packages/contracts/generated/api/console/activate/types.gen.ts @@ -53,9 +53,9 @@ export type GetActivateCheckData = { body?: never path?: never query: { - email?: string | null + email?: string token: string - workspace_id?: string | null + workspace_id?: string } url: '/activate/check' } diff --git a/packages/contracts/generated/api/console/activate/zod.gen.ts b/packages/contracts/generated/api/console/activate/zod.gen.ts index 4f877fcd7e0..00f85767b7c 100644 --- a/packages/contracts/generated/api/console/activate/zod.gen.ts +++ b/packages/contracts/generated/api/console/activate/zod.gen.ts @@ -46,9 +46,9 @@ export const zPostActivateBody = zActivatePayload export const zPostActivateResponse = zActivationResponse export const zGetActivateCheckQuery = z.object({ - email: z.string().nullish(), + email: z.string().optional(), token: z.string(), - workspace_id: z.string().nullish(), + workspace_id: z.string().optional(), }) /** diff --git a/packages/contracts/generated/api/console/apps/types.gen.ts b/packages/contracts/generated/api/console/apps/types.gen.ts index 42fd165ba05..08cb46ef329 100644 --- a/packages/contracts/generated/api/console/apps/types.gen.ts +++ b/packages/contracts/generated/api/console/apps/types.gen.ts @@ -602,15 +602,6 @@ export type WorkflowTriggerListResponse = { data: Array } -export type WorkflowExecutionStatus - = | 'failed' - | 'partial-succeeded' - | 'paused' - | 'running' - | 'scheduled' - | 'stopped' - | 'succeeded' - export type WorkflowAppLogPaginationResponse = { data: Array has_more: boolean @@ -1567,6 +1558,15 @@ export type AgentComposerImpactBindingResponse = { workflow_id: string } +export type WorkflowExecutionStatus + = | 'failed' + | 'partial-succeeded' + | 'paused' + | 'running' + | 'scheduled' + | 'stopped' + | 'succeeded' + export type NodeStatus = 'failed' | 'idle' | 'ready' | 'running' export type NodeOutputView = { @@ -2250,8 +2250,8 @@ export type GetAppsData = { body?: never path?: never query?: { - creator_ids?: Array | null - is_created_by_me?: boolean | null + creator_ids?: Array + is_created_by_me?: boolean limit?: number mode?: | 'advanced-chat' @@ -2262,9 +2262,9 @@ export type GetAppsData = { | 'chat' | 'completion' | 'workflow' - name?: string | null + name?: string page?: number - tag_ids?: Array | null + tag_ids?: Array } url: '/apps' } @@ -3288,12 +3288,12 @@ export type GetAppsByAppIdChatConversationsData = { } query?: { annotation_status?: 'all' | 'annotated' | 'not_annotated' - end?: string | null - keyword?: string | null + end?: string + keyword?: string limit?: number page?: number sort_by?: '-created_at' | '-updated_at' | 'created_at' | 'updated_at' - start?: string | null + start?: string } url: '/apps/{app_id}/chat-conversations' } @@ -3379,7 +3379,7 @@ export type GetAppsByAppIdChatMessagesData = { } query: { conversation_id: string - first_id?: string | null + first_id?: string limit?: number } url: '/apps/{app_id}/chat-messages' @@ -3451,11 +3451,11 @@ export type GetAppsByAppIdCompletionConversationsData = { } query?: { annotation_status?: 'all' | 'annotated' | 'not_annotated' - end?: string | null - keyword?: string | null + end?: string + keyword?: string limit?: number page?: number - start?: string | null + start?: string } url: '/apps/{app_id}/completion-conversations' } @@ -3658,7 +3658,7 @@ export type GetAppsByAppIdExportData = { } query?: { include_secret?: boolean - workflow_id?: string | null + workflow_id?: string } url: '/apps/{app_id}/export' } @@ -3712,12 +3712,12 @@ export type GetAppsByAppIdFeedbacksExportData = { app_id: string } query?: { - end_date?: string | null + end_date?: string format?: 'csv' | 'json' - from_source?: 'admin' | 'user' | null - has_comment?: boolean | null - rating?: 'dislike' | 'like' | null - start_date?: string | null + from_source?: 'admin' | 'user' + has_comment?: boolean + rating?: 'dislike' | 'like' + start_date?: string } url: '/apps/{app_id}/feedbacks/export' } @@ -4011,8 +4011,8 @@ export type GetAppsByAppIdStatisticsAverageResponseTimeData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/average-response-time' } @@ -4032,8 +4032,8 @@ export type GetAppsByAppIdStatisticsAverageSessionInteractionsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/average-session-interactions' } @@ -4053,8 +4053,8 @@ export type GetAppsByAppIdStatisticsDailyConversationsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/daily-conversations' } @@ -4074,8 +4074,8 @@ export type GetAppsByAppIdStatisticsDailyEndUsersData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/daily-end-users' } @@ -4095,8 +4095,8 @@ export type GetAppsByAppIdStatisticsDailyMessagesData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/daily-messages' } @@ -4116,8 +4116,8 @@ export type GetAppsByAppIdStatisticsTokenCostsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/token-costs' } @@ -4137,8 +4137,8 @@ export type GetAppsByAppIdStatisticsTokensPerSecondData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/tokens-per-second' } @@ -4158,8 +4158,8 @@ export type GetAppsByAppIdStatisticsUserSatisfactionRateData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/statistics/user-satisfaction-rate' } @@ -4417,15 +4417,22 @@ export type GetAppsByAppIdWorkflowAppLogsData = { app_id: string } query?: { - created_at__after?: string | null - created_at__before?: string | null - created_by_account?: string | null - created_by_end_user_session_id?: string | null + created_at__after?: string + created_at__before?: string + created_by_account?: string + created_by_end_user_session_id?: string detail?: boolean - keyword?: string | null + keyword?: string limit?: number page?: number - status?: WorkflowExecutionStatus | null + status?: + | 'failed' + | 'partial-succeeded' + | 'paused' + | 'running' + | 'scheduled' + | 'stopped' + | 'succeeded' } url: '/apps/{app_id}/workflow-app-logs' } @@ -4443,15 +4450,22 @@ export type GetAppsByAppIdWorkflowArchivedLogsData = { app_id: string } query?: { - created_at__after?: string | null - created_at__before?: string | null - created_by_account?: string | null - created_by_end_user_session_id?: string | null + created_at__after?: string + created_at__before?: string + created_by_account?: string + created_by_end_user_session_id?: string detail?: boolean - keyword?: string | null + keyword?: string limit?: number page?: number - status?: WorkflowExecutionStatus | null + status?: + | 'failed' + | 'partial-succeeded' + | 'paused' + | 'running' + | 'scheduled' + | 'stopped' + | 'succeeded' } url: '/apps/{app_id}/workflow-archived-logs' } @@ -4838,8 +4852,8 @@ export type GetAppsByAppIdWorkflowStatisticsAverageAppInteractionsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/workflow/statistics/average-app-interactions' } @@ -4859,8 +4873,8 @@ export type GetAppsByAppIdWorkflowStatisticsDailyConversationsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/workflow/statistics/daily-conversations' } @@ -4880,8 +4894,8 @@ export type GetAppsByAppIdWorkflowStatisticsDailyTerminalsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/workflow/statistics/daily-terminals' } @@ -4901,8 +4915,8 @@ export type GetAppsByAppIdWorkflowStatisticsTokenCostsData = { app_id: string } query?: { - end?: string | null - start?: string | null + end?: string + start?: string } url: '/apps/{app_id}/workflow/statistics/token-costs' } @@ -4925,7 +4939,7 @@ export type GetAppsByAppIdWorkflowsData = { limit?: number named_only?: boolean page?: number - user_id?: string | null + user_id?: string } url: '/apps/{app_id}/workflows' } @@ -4962,7 +4976,7 @@ export type GetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeData = block_type: string } query?: { - q?: string | null + q?: string } url: '/apps/{app_id}/workflows/default-workflow-block-configs/{block_type}' } @@ -5721,8 +5735,8 @@ export type GetAppsByAppIdWorkflowsDraftVariablesData = { app_id: string } query?: { - limit?: string - page?: string + limit?: number + page?: number } url: '/apps/{app_id}/workflows/draft/variables' } @@ -5991,11 +6005,7 @@ export type GetAppsByAppIdWorkflowsTriggersWebhookData = { app_id: string } query: { - credential_id?: string | null - datasource_type: string - inputs: { - [key: string]: unknown - } + node_id: string } url: '/apps/{app_id}/workflows/triggers/webhook' } diff --git a/packages/contracts/generated/api/console/apps/zod.gen.ts b/packages/contracts/generated/api/console/apps/zod.gen.ts index 14a8d50f4e0..12d9dab3c77 100644 --- a/packages/contracts/generated/api/console/apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/apps/zod.gen.ts @@ -394,19 +394,6 @@ export const zWorkflowTriggerListResponse = z.object({ data: z.array(zWorkflowTriggerResponse), }) -/** - * WorkflowExecutionStatus - */ -export const zWorkflowExecutionStatus = z.enum([ - 'failed', - 'partial-succeeded', - 'paused', - 'running', - 'scheduled', - 'stopped', - 'succeeded', -]) - /** * WorkflowRunExportResponse */ @@ -1430,6 +1417,19 @@ export const zAgentComposerImpactResponse = z.object({ workflow_node_count: z.int(), }) +/** + * WorkflowExecutionStatus + */ +export const zWorkflowExecutionStatus = z.enum([ + 'failed', + 'partial-succeeded', + 'paused', + 'running', + 'scheduled', + 'stopped', + 'succeeded', +]) + /** * NodeStatus * @@ -3010,8 +3010,8 @@ export const zWorkflowCommentDetailWritable = z.object({ }) export const zGetAppsQuery = z.object({ - creator_ids: z.array(z.string()).nullish(), - is_created_by_me: z.boolean().nullish(), + creator_ids: z.array(z.string()).optional(), + is_created_by_me: z.boolean().optional(), limit: z.int().gte(1).lte(100).optional().default(20), mode: z .enum([ @@ -3026,9 +3026,9 @@ export const zGetAppsQuery = z.object({ ]) .optional() .default('all'), - name: z.string().nullish(), + name: z.string().optional(), page: z.int().gte(1).lte(99999).optional().default(1), - tag_ids: z.array(z.string()).nullish(), + tag_ids: z.array(z.string()).optional(), }) /** @@ -3494,8 +3494,8 @@ export const zGetAppsByAppIdAnnotationsByAnnotationIdHitHistoriesPath = z.object }) export const zGetAppsByAppIdAnnotationsByAnnotationIdHitHistoriesQuery = z.object({ - limit: z.int().optional().default(20), - page: z.int().optional().default(1), + limit: z.int().gte(1).optional().default(20), + page: z.int().gte(1).optional().default(1), }) /** @@ -3530,15 +3530,15 @@ export const zGetAppsByAppIdChatConversationsPath = z.object({ export const zGetAppsByAppIdChatConversationsQuery = z.object({ annotation_status: z.enum(['all', 'annotated', 'not_annotated']).optional().default('all'), - end: z.string().nullish(), - keyword: z.string().nullish(), + end: z.string().optional(), + keyword: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), page: z.int().gte(1).lte(99999).optional().default(1), sort_by: z .enum(['-created_at', '-updated_at', 'created_at', 'updated_at']) .optional() .default('-updated_at'), - start: z.string().nullish(), + start: z.string().optional(), }) /** @@ -3572,7 +3572,7 @@ export const zGetAppsByAppIdChatMessagesPath = z.object({ export const zGetAppsByAppIdChatMessagesQuery = z.object({ conversation_id: z.string(), - first_id: z.string().nullish(), + first_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), }) @@ -3608,11 +3608,11 @@ export const zGetAppsByAppIdCompletionConversationsPath = z.object({ export const zGetAppsByAppIdCompletionConversationsQuery = z.object({ annotation_status: z.enum(['all', 'annotated', 'not_annotated']).optional().default('all'), - end: z.string().nullish(), - keyword: z.string().nullish(), + end: z.string().optional(), + keyword: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), page: z.int().gte(1).lte(99999).optional().default(1), - start: z.string().nullish(), + start: z.string().optional(), }) /** @@ -3703,7 +3703,7 @@ export const zGetAppsByAppIdExportPath = z.object({ export const zGetAppsByAppIdExportQuery = z.object({ include_secret: z.boolean().optional().default(false), - workflow_id: z.string().nullish(), + workflow_id: z.string().optional(), }) /** @@ -3727,12 +3727,12 @@ export const zGetAppsByAppIdFeedbacksExportPath = z.object({ }) export const zGetAppsByAppIdFeedbacksExportQuery = z.object({ - end_date: z.string().nullish(), + end_date: z.string().optional(), format: z.enum(['csv', 'json']).optional().default('csv'), - from_source: z.enum(['admin', 'user']).nullish(), - has_comment: z.boolean().nullish(), - rating: z.enum(['dislike', 'like']).nullish(), - start_date: z.string().nullish(), + from_source: z.enum(['admin', 'user']).optional(), + has_comment: z.boolean().optional(), + rating: z.enum(['dislike', 'like']).optional(), + start_date: z.string().optional(), }) /** @@ -3859,8 +3859,8 @@ export const zGetAppsByAppIdStatisticsAverageResponseTimePath = z.object({ }) export const zGetAppsByAppIdStatisticsAverageResponseTimeQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3875,8 +3875,8 @@ export const zGetAppsByAppIdStatisticsAverageSessionInteractionsPath = z.object( }) export const zGetAppsByAppIdStatisticsAverageSessionInteractionsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3891,8 +3891,8 @@ export const zGetAppsByAppIdStatisticsDailyConversationsPath = z.object({ }) export const zGetAppsByAppIdStatisticsDailyConversationsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3907,8 +3907,8 @@ export const zGetAppsByAppIdStatisticsDailyEndUsersPath = z.object({ }) export const zGetAppsByAppIdStatisticsDailyEndUsersQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3923,8 +3923,8 @@ export const zGetAppsByAppIdStatisticsDailyMessagesPath = z.object({ }) export const zGetAppsByAppIdStatisticsDailyMessagesQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3939,8 +3939,8 @@ export const zGetAppsByAppIdStatisticsTokenCostsPath = z.object({ }) export const zGetAppsByAppIdStatisticsTokenCostsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3955,8 +3955,8 @@ export const zGetAppsByAppIdStatisticsTokensPerSecondPath = z.object({ }) export const zGetAppsByAppIdStatisticsTokensPerSecondQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -3971,8 +3971,8 @@ export const zGetAppsByAppIdStatisticsUserSatisfactionRatePath = z.object({ }) export const zGetAppsByAppIdStatisticsUserSatisfactionRateQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -4097,15 +4097,17 @@ export const zGetAppsByAppIdWorkflowAppLogsPath = z.object({ }) export const zGetAppsByAppIdWorkflowAppLogsQuery = z.object({ - created_at__after: z.iso.datetime().nullish(), - created_at__before: z.iso.datetime().nullish(), - created_by_account: z.string().nullish(), - created_by_end_user_session_id: z.string().nullish(), + created_at__after: z.iso.datetime().optional(), + created_at__before: z.iso.datetime().optional(), + created_by_account: z.string().optional(), + created_by_end_user_session_id: z.string().optional(), detail: z.boolean().optional().default(false), - keyword: z.string().nullish(), + keyword: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), page: z.int().gte(1).lte(99999).optional().default(1), - status: zWorkflowExecutionStatus.nullish(), + status: z + .enum(['failed', 'partial-succeeded', 'paused', 'running', 'scheduled', 'stopped', 'succeeded']) + .optional(), }) /** @@ -4118,15 +4120,17 @@ export const zGetAppsByAppIdWorkflowArchivedLogsPath = z.object({ }) export const zGetAppsByAppIdWorkflowArchivedLogsQuery = z.object({ - created_at__after: z.iso.datetime().nullish(), - created_at__before: z.iso.datetime().nullish(), - created_by_account: z.string().nullish(), - created_by_end_user_session_id: z.string().nullish(), + created_at__after: z.iso.datetime().optional(), + created_at__before: z.iso.datetime().optional(), + created_by_account: z.string().optional(), + created_by_end_user_session_id: z.string().optional(), detail: z.boolean().optional().default(false), - keyword: z.string().nullish(), + keyword: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), page: z.int().gte(1).lte(99999).optional().default(1), - status: zWorkflowExecutionStatus.nullish(), + status: z + .enum(['failed', 'partial-succeeded', 'paused', 'running', 'scheduled', 'stopped', 'succeeded']) + .optional(), }) /** @@ -4376,8 +4380,8 @@ export const zGetAppsByAppIdWorkflowStatisticsAverageAppInteractionsPath = z.obj }) export const zGetAppsByAppIdWorkflowStatisticsAverageAppInteractionsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -4393,8 +4397,8 @@ export const zGetAppsByAppIdWorkflowStatisticsDailyConversationsPath = z.object( }) export const zGetAppsByAppIdWorkflowStatisticsDailyConversationsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -4410,8 +4414,8 @@ export const zGetAppsByAppIdWorkflowStatisticsDailyTerminalsPath = z.object({ }) export const zGetAppsByAppIdWorkflowStatisticsDailyTerminalsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -4427,8 +4431,8 @@ export const zGetAppsByAppIdWorkflowStatisticsTokenCostsPath = z.object({ }) export const zGetAppsByAppIdWorkflowStatisticsTokenCostsQuery = z.object({ - end: z.string().nullish(), - start: z.string().nullish(), + end: z.string().optional(), + start: z.string().optional(), }) /** @@ -4444,7 +4448,7 @@ export const zGetAppsByAppIdWorkflowsQuery = z.object({ limit: z.int().gte(1).lte(100).optional().default(10), named_only: z.boolean().optional().default(false), page: z.int().gte(1).lte(99999).optional().default(1), - user_id: z.string().nullish(), + user_id: z.string().optional(), }) /** @@ -4470,7 +4474,7 @@ export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypePath }) export const zGetAppsByAppIdWorkflowsDefaultWorkflowBlockConfigsByBlockTypeQuery = z.object({ - q: z.string().nullish(), + q: z.string().optional(), }) /** @@ -4880,8 +4884,8 @@ export const zGetAppsByAppIdWorkflowsDraftVariablesPath = z.object({ }) export const zGetAppsByAppIdWorkflowsDraftVariablesQuery = z.object({ - limit: z.string().optional(), - page: z.string().optional(), + limit: z.int().gte(1).lte(100).optional().default(20), + page: z.int().gte(1).lte(100000).optional().default(1), }) /** @@ -5007,9 +5011,7 @@ export const zGetAppsByAppIdWorkflowsTriggersWebhookPath = z.object({ }) export const zGetAppsByAppIdWorkflowsTriggersWebhookQuery = z.object({ - credential_id: z.string().nullish(), - datasource_type: z.string(), - inputs: z.record(z.string(), z.unknown()), + node_id: z.string(), }) /** diff --git a/packages/contracts/generated/api/console/installed-apps/types.gen.ts b/packages/contracts/generated/api/console/installed-apps/types.gen.ts index 355b24eeb6f..875c2492443 100644 --- a/packages/contracts/generated/api/console/installed-apps/types.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/types.gen.ts @@ -259,9 +259,9 @@ export type GetInstalledAppsByInstalledAppIdConversationsData = { installed_app_id: string } query?: { - last_id?: string | null + last_id?: string limit?: number - pinned?: boolean | null + pinned?: boolean } url: '/installed-apps/{installed_app_id}/conversations' } @@ -352,7 +352,7 @@ export type GetInstalledAppsByInstalledAppIdMessagesData = { } query: { conversation_id: string - first_id?: string | null + first_id?: string limit?: number } url: '/installed-apps/{installed_app_id}/messages' @@ -464,7 +464,7 @@ export type GetInstalledAppsByInstalledAppIdSavedMessagesData = { installed_app_id: string } query?: { - last_id?: string | null + last_id?: string limit?: number } url: '/installed-apps/{installed_app_id}/saved-messages' diff --git a/packages/contracts/generated/api/console/installed-apps/zod.gen.ts b/packages/contracts/generated/api/console/installed-apps/zod.gen.ts index bfa75c9d997..31d6189d9ce 100644 --- a/packages/contracts/generated/api/console/installed-apps/zod.gen.ts +++ b/packages/contracts/generated/api/console/installed-apps/zod.gen.ts @@ -234,9 +234,9 @@ export const zGetInstalledAppsByInstalledAppIdConversationsPath = z.object({ }) export const zGetInstalledAppsByInstalledAppIdConversationsQuery = z.object({ - last_id: z.string().nullish(), + last_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), - pinned: z.boolean().nullish(), + pinned: z.boolean().optional(), }) /** @@ -299,7 +299,7 @@ export const zGetInstalledAppsByInstalledAppIdMessagesPath = z.object({ export const zGetInstalledAppsByInstalledAppIdMessagesQuery = z.object({ conversation_id: z.string(), - first_id: z.string().nullish(), + first_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), }) @@ -373,7 +373,7 @@ export const zGetInstalledAppsByInstalledAppIdSavedMessagesPath = z.object({ }) export const zGetInstalledAppsByInstalledAppIdSavedMessagesQuery = z.object({ - last_id: z.string().nullish(), + last_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), }) diff --git a/packages/contracts/generated/api/console/website/orpc.gen.ts b/packages/contracts/generated/api/console/website/orpc.gen.ts index 3632d32121a..5ed1fcd8abf 100644 --- a/packages/contracts/generated/api/console/website/orpc.gen.ts +++ b/packages/contracts/generated/api/console/website/orpc.gen.ts @@ -32,7 +32,7 @@ export const get = oc .input( z.object({ params: zGetWebsiteCrawlStatusByJobIdPath, - query: zGetWebsiteCrawlStatusByJobIdQuery.optional(), + query: zGetWebsiteCrawlStatusByJobIdQuery, }), ) .output(zGetWebsiteCrawlStatusByJobIdResponse) diff --git a/packages/contracts/generated/api/console/website/types.gen.ts b/packages/contracts/generated/api/console/website/types.gen.ts index 8dba2c1370c..c8ea0de7b65 100644 --- a/packages/contracts/generated/api/console/website/types.gen.ts +++ b/packages/contracts/generated/api/console/website/types.gen.ts @@ -40,8 +40,8 @@ export type GetWebsiteCrawlStatusByJobIdData = { path: { job_id: string } - query?: { - provider?: string + query: { + provider: 'firecrawl' | 'jinareader' | 'watercrawl' } url: '/website/crawl/status/{job_id}' } diff --git a/packages/contracts/generated/api/console/website/zod.gen.ts b/packages/contracts/generated/api/console/website/zod.gen.ts index 13038ac0b1a..88f1d4a7c81 100644 --- a/packages/contracts/generated/api/console/website/zod.gen.ts +++ b/packages/contracts/generated/api/console/website/zod.gen.ts @@ -23,7 +23,7 @@ export const zGetWebsiteCrawlStatusByJobIdPath = z.object({ }) export const zGetWebsiteCrawlStatusByJobIdQuery = z.object({ - provider: z.string().optional(), + provider: z.enum(['firecrawl', 'jinareader', 'watercrawl']), }) /** diff --git a/packages/contracts/generated/api/console/workspaces/types.gen.ts b/packages/contracts/generated/api/console/workspaces/types.gen.ts index 335634279a5..5597046c629 100644 --- a/packages/contracts/generated/api/console/workspaces/types.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/types.gen.ts @@ -85,8 +85,6 @@ export type AccountWithRoleList = { accounts: Array } -export type ModelType = 'llm' | 'moderation' | 'rerank' | 'speech2text' | 'text-embedding' | 'tts' - export type ParserPostDefault = { model_settings: Array } @@ -643,6 +641,8 @@ export type Inner = { export type TenantAccountRole = 'admin' | 'dataset_operator' | 'editor' | 'normal' | 'owner' +export type ModelType = 'llm' | 'moderation' | 'rerank' | 'speech2text' | 'text-embedding' | 'tts' + export type LoadBalancingPayload = { configs?: Array<{ [key: string]: unknown @@ -752,12 +752,12 @@ export type GetWorkspacesCurrentCustomizedSnippetsData = { body?: never path?: never query?: { - creators?: Array | null - is_published?: boolean | null - keyword?: string | null + creators?: Array + is_published?: boolean + keyword?: string limit?: number page?: number - tag_ids?: Array | null + tag_ids?: Array } url: '/workspaces/current/customized-snippets' } @@ -1024,7 +1024,7 @@ export type GetWorkspacesCurrentDefaultModelData = { body?: never path?: never query: { - model_type: ModelType + model_type: 'llm' | 'moderation' | 'rerank' | 'speech2text' | 'text-embedding' | 'tts' } url: '/workspaces/current/default-model' } @@ -1391,7 +1391,7 @@ export type GetWorkspacesCurrentModelProvidersData = { body?: never path?: never query?: { - model_type?: ModelType | null + model_type?: 'llm' | 'moderation' | 'rerank' | 'speech2text' | 'text-embedding' | 'tts' } url: '/workspaces/current/model-providers' } @@ -1445,7 +1445,7 @@ export type GetWorkspacesCurrentModelProvidersByProviderCredentialsData = { provider: string } query?: { - credential_id?: string | null + credential_id?: string } url: '/workspaces/current/model-providers/{provider}/credentials' } @@ -1603,10 +1603,10 @@ export type GetWorkspacesCurrentModelProvidersByProviderModelsCredentialsData = provider: string } query: { - config_from?: string | null - credential_id?: string | null + config_from?: string + credential_id?: string model: string - model_type: ModelType + model_type: 'llm' | 'moderation' | 'rerank' | 'speech2text' | 'text-embedding' | 'tts' } url: '/workspaces/current/model-providers/{provider}/models/credentials' } @@ -2023,7 +2023,7 @@ export type GetWorkspacesCurrentPluginParametersDynamicOptionsData = { path?: never query: { action: string - credential_id?: string | null + credential_id?: string parameter: string plugin_id: string provider: string diff --git a/packages/contracts/generated/api/console/workspaces/zod.gen.ts b/packages/contracts/generated/api/console/workspaces/zod.gen.ts index e1eab1a76c3..3c46c777b28 100644 --- a/packages/contracts/generated/api/console/workspaces/zod.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/zod.gen.ts @@ -16,20 +16,6 @@ export const zSnippetImportPayload = z.object({ yaml_url: z.string().nullish(), }) -/** - * ModelType - * - * Enum class for model type. - */ -export const zModelType = z.enum([ - 'llm', - 'moderation', - 'rerank', - 'speech2text', - 'text-embedding', - 'tts', -]) - /** * SimpleResultResponse */ @@ -203,71 +189,6 @@ export const zParserCredentialValidate = z.object({ credentials: z.record(z.string(), z.unknown()), }) -/** - * ParserDeleteModels - */ -export const zParserDeleteModels = z.object({ - model: z.string(), - model_type: zModelType, -}) - -/** - * ParserDeleteCredential - */ -export const zParserDeleteCredential = z.object({ - credential_id: z.string(), - model: z.string(), - model_type: zModelType, -}) - -/** - * ParserCreateCredential - */ -export const zParserCreateCredential = z.object({ - credentials: z.record(z.string(), z.unknown()), - model: z.string(), - model_type: zModelType, - name: z.string().max(30).nullish(), -}) - -/** - * ParserUpdateCredential - */ -export const zParserUpdateCredential = z.object({ - credential_id: z.string(), - credentials: z.record(z.string(), z.unknown()), - model: z.string(), - model_type: zModelType, - name: z.string().max(30).nullish(), -}) - -/** - * ParserSwitch - */ -export const zParserSwitch = z.object({ - credential_id: z.string(), - model: z.string(), - model_type: zModelType, -}) - -/** - * ParserValidate - */ -export const zParserValidate = z.object({ - credentials: z.record(z.string(), z.unknown()), - model: z.string(), - model_type: zModelType, -}) - -/** - * LoadBalancingCredentialPayload - */ -export const zLoadBalancingCredentialPayload = z.object({ - credentials: z.record(z.string(), z.unknown()), - model: z.string(), - model_type: zModelType, -}) - /** * ParserPreferredProviderType */ @@ -655,6 +576,99 @@ export const zAccountWithRoleList = z.object({ accounts: z.array(zAccountWithRole), }) +/** + * TenantAccountRole + */ +export const zTenantAccountRole = z.enum(['admin', 'dataset_operator', 'editor', 'normal', 'owner']) + +/** + * MemberInvitePayload + */ +export const zMemberInvitePayload = z.object({ + emails: z.array(z.string()).optional(), + language: z.string().nullish(), + role: zTenantAccountRole, +}) + +/** + * ModelType + * + * Enum class for model type. + */ +export const zModelType = z.enum([ + 'llm', + 'moderation', + 'rerank', + 'speech2text', + 'text-embedding', + 'tts', +]) + +/** + * ParserDeleteModels + */ +export const zParserDeleteModels = z.object({ + model: z.string(), + model_type: zModelType, +}) + +/** + * ParserDeleteCredential + */ +export const zParserDeleteCredential = z.object({ + credential_id: z.string(), + model: z.string(), + model_type: zModelType, +}) + +/** + * ParserCreateCredential + */ +export const zParserCreateCredential = z.object({ + credentials: z.record(z.string(), z.unknown()), + model: z.string(), + model_type: zModelType, + name: z.string().max(30).nullish(), +}) + +/** + * ParserUpdateCredential + */ +export const zParserUpdateCredential = z.object({ + credential_id: z.string(), + credentials: z.record(z.string(), z.unknown()), + model: z.string(), + model_type: zModelType, + name: z.string().max(30).nullish(), +}) + +/** + * ParserSwitch + */ +export const zParserSwitch = z.object({ + credential_id: z.string(), + model: z.string(), + model_type: zModelType, +}) + +/** + * ParserValidate + */ +export const zParserValidate = z.object({ + credentials: z.record(z.string(), z.unknown()), + model: z.string(), + model_type: zModelType, +}) + +/** + * LoadBalancingCredentialPayload + */ +export const zLoadBalancingCredentialPayload = z.object({ + credentials: z.record(z.string(), z.unknown()), + model: z.string(), + model_type: zModelType, +}) + /** * Inner */ @@ -671,20 +685,6 @@ export const zParserPostDefault = z.object({ model_settings: z.array(zInner), }) -/** - * TenantAccountRole - */ -export const zTenantAccountRole = z.enum(['admin', 'dataset_operator', 'editor', 'normal', 'owner']) - -/** - * MemberInvitePayload - */ -export const zMemberInvitePayload = z.object({ - emails: z.array(z.string()).optional(), - language: z.string().nullish(), - role: zTenantAccountRole, -}) - /** * LoadBalancingPayload */ @@ -941,12 +941,12 @@ export const zGetWorkspacesCurrentAgentProvidersResponse = z.array( ) export const zGetWorkspacesCurrentCustomizedSnippetsQuery = z.object({ - creators: z.array(z.string()).nullish(), - is_published: z.boolean().nullish(), - keyword: z.string().nullish(), + creators: z.array(z.string()).optional(), + is_published: z.boolean().optional(), + keyword: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), page: z.int().gte(1).lte(99999).optional().default(1), - tag_ids: z.array(z.string()).nullish(), + tag_ids: z.array(z.string()).optional(), }) /** @@ -1049,7 +1049,7 @@ export const zPostWorkspacesCurrentCustomizedSnippetsBySnippetIdUseCountIncremen export const zGetWorkspacesCurrentDatasetOperatorsResponse = zAccountWithRoleList export const zGetWorkspacesCurrentDefaultModelQuery = z.object({ - model_type: zModelType, + model_type: z.enum(['llm', 'moderation', 'rerank', 'speech2text', 'text-embedding', 'tts']), }) /** @@ -1213,7 +1213,9 @@ export const zPutWorkspacesCurrentMembersByMemberIdUpdateRoleResponse = z.record ) export const zGetWorkspacesCurrentModelProvidersQuery = z.object({ - model_type: zModelType.nullish(), + model_type: z + .enum(['llm', 'moderation', 'rerank', 'speech2text', 'text-embedding', 'tts']) + .optional(), }) /** @@ -1250,7 +1252,7 @@ export const zGetWorkspacesCurrentModelProvidersByProviderCredentialsPath = z.ob }) export const zGetWorkspacesCurrentModelProvidersByProviderCredentialsQuery = z.object({ - credential_id: z.string().nullish(), + credential_id: z.string().optional(), }) /** @@ -1371,10 +1373,10 @@ export const zGetWorkspacesCurrentModelProvidersByProviderModelsCredentialsPath }) export const zGetWorkspacesCurrentModelProvidersByProviderModelsCredentialsQuery = z.object({ - config_from: z.string().nullish(), - credential_id: z.string().nullish(), + config_from: z.string().optional(), + credential_id: z.string().optional(), model: z.string(), - model_type: zModelType, + model_type: z.enum(['llm', 'moderation', 'rerank', 'speech2text', 'text-embedding', 'tts']), }) /** @@ -1641,7 +1643,7 @@ export const zGetWorkspacesCurrentPluginMarketplacePkgResponse = z.record(z.stri export const zGetWorkspacesCurrentPluginParametersDynamicOptionsQuery = z.object({ action: z.string(), - credential_id: z.string().nullish(), + credential_id: z.string().optional(), parameter: z.string(), plugin_id: z.string(), provider: z.string(), diff --git a/packages/contracts/generated/api/openapi/types.gen.ts b/packages/contracts/generated/api/openapi/types.gen.ts index 6d630639592..2dccca42e63 100644 --- a/packages/contracts/generated/api/openapi/types.gen.ts +++ b/packages/contracts/generated/api/openapi/types.gen.ts @@ -569,7 +569,15 @@ export type GetAppsData = { path?: never query: { limit?: number - mode?: string + mode?: + | 'advanced-chat' + | 'agent' + | 'agent-chat' + | 'channel' + | 'chat' + | 'completion' + | 'rag-pipeline' + | 'workflow' name?: string page?: number tag?: string @@ -891,7 +899,15 @@ export type GetPermittedExternalAppsData = { path?: never query?: { limit?: number - mode?: string + mode?: + | 'advanced-chat' + | 'agent' + | 'agent-chat' + | 'channel' + | 'chat' + | 'completion' + | 'rag-pipeline' + | 'workflow' name?: string page?: number } diff --git a/packages/contracts/generated/api/openapi/zod.gen.ts b/packages/contracts/generated/api/openapi/zod.gen.ts index 6379ffc62e2..e8077b321af 100644 --- a/packages/contracts/generated/api/openapi/zod.gen.ts +++ b/packages/contracts/generated/api/openapi/zod.gen.ts @@ -678,7 +678,18 @@ export const zDeleteAccountSessionsBySessionIdResponse = zRevokeResponse export const zGetAppsQuery = z.object({ limit: z.int().gte(1).lte(200).optional().default(20), - mode: z.string().optional(), + mode: z + .enum([ + 'advanced-chat', + 'agent', + 'agent-chat', + 'channel', + 'chat', + 'completion', + 'rag-pipeline', + 'workflow', + ]) + .optional(), name: z.string().max(200).optional(), page: z.int().gte(1).optional().default(1), tag: z.string().max(100).optional(), @@ -827,7 +838,18 @@ export const zPostOauthDeviceTokenResponse = z.record(z.string(), z.unknown()) export const zGetPermittedExternalAppsQuery = z.object({ limit: z.int().gte(1).lte(200).optional().default(20), - mode: z.string().optional(), + mode: z + .enum([ + 'advanced-chat', + 'agent', + 'agent-chat', + 'channel', + 'chat', + 'completion', + 'rag-pipeline', + 'workflow', + ]) + .optional(), name: z.string().max(200).optional(), page: z.int().gte(1).optional().default(1), }) diff --git a/packages/contracts/generated/api/service/types.gen.ts b/packages/contracts/generated/api/service/types.gen.ts index f57d90bcfb7..f3310887fff 100644 --- a/packages/contracts/generated/api/service/types.gen.ts +++ b/packages/contracts/generated/api/service/types.gen.ts @@ -1424,7 +1424,7 @@ export type GetConversationsData = { body?: never path?: never query?: { - last_id?: string | null + last_id?: string limit?: number sort_by?: '-created_at' | '-updated_at' | 'created_at' | 'updated_at' } @@ -1514,9 +1514,9 @@ export type GetConversationsByCIdVariablesData = { c_id: string } query?: { - last_id?: string | null + last_id?: string limit?: number - variable_name?: string | null + variable_name?: string } url: '/conversations/{c_id}/variables' } @@ -3236,7 +3236,7 @@ export type GetMessagesData = { path?: never query: { conversation_id: string - first_id?: string | null + first_id?: string limit?: number } url: '/messages' @@ -3466,14 +3466,14 @@ export type GetWorkflowsLogsData = { body?: never path?: never query?: { - created_at__after?: string | null - created_at__before?: string | null - created_by_account?: string | null - created_by_end_user_session_id?: string | null - keyword?: string | null + created_at__after?: string + created_at__before?: string + created_by_account?: string + created_by_end_user_session_id?: string + keyword?: string limit?: number page?: number - status?: 'failed' | 'stopped' | 'succeeded' | null + status?: 'failed' | 'stopped' | 'succeeded' } url: '/workflows/logs' } diff --git a/packages/contracts/generated/api/service/zod.gen.ts b/packages/contracts/generated/api/service/zod.gen.ts index 4575e95b718..93eae180806 100644 --- a/packages/contracts/generated/api/service/zod.gen.ts +++ b/packages/contracts/generated/api/service/zod.gen.ts @@ -1533,7 +1533,7 @@ export const zPostCompletionMessagesByTaskIdStopPath = z.object({ export const zPostCompletionMessagesByTaskIdStopResponse = zSimpleResultResponse export const zGetConversationsQuery = z.object({ - last_id: z.string().nullish(), + last_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), sort_by: z .enum(['-created_at', '-updated_at', 'created_at', 'updated_at']) @@ -1571,9 +1571,9 @@ export const zGetConversationsByCIdVariablesPath = z.object({ }) export const zGetConversationsByCIdVariablesQuery = z.object({ - last_id: z.string().nullish(), + last_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), - variable_name: z.string().min(1).max(255).nullish(), + variable_name: z.string().min(1).max(255).optional(), }) /** @@ -2226,7 +2226,7 @@ export const zGetInfoResponse = zAppInfoResponse export const zGetMessagesQuery = z.object({ conversation_id: z.string(), - first_id: z.string().nullish(), + first_id: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), }) @@ -2293,14 +2293,14 @@ export const zGetWorkflowByTaskIdEventsQuery = z.object({ export const zGetWorkflowByTaskIdEventsResponse = z.record(z.string(), z.unknown()) export const zGetWorkflowsLogsQuery = z.object({ - created_at__after: z.string().nullish(), - created_at__before: z.string().nullish(), - created_by_account: z.string().nullish(), - created_by_end_user_session_id: z.string().nullish(), - keyword: z.string().nullish(), + created_at__after: z.string().optional(), + created_at__before: z.string().optional(), + created_by_account: z.string().optional(), + created_by_end_user_session_id: z.string().optional(), + keyword: z.string().optional(), limit: z.int().gte(1).lte(100).optional().default(20), page: z.int().gte(1).lte(99999).optional().default(1), - status: z.enum(['failed', 'stopped', 'succeeded']).nullish(), + status: z.enum(['failed', 'stopped', 'succeeded']).optional(), }) /** diff --git a/packages/contracts/openapi-ts.api.config.ts b/packages/contracts/openapi-ts.api.config.ts index fc6ff748111..9aae8ab0042 100644 --- a/packages/contracts/openapi-ts.api.config.ts +++ b/packages/contracts/openapi-ts.api.config.ts @@ -431,21 +431,6 @@ const isNullSchema = (schema: SwaggerSchema) => { return schema.type === 'null' } -const resolveSchemaRef = ( - schema: SwaggerSchema | undefined, - schemas: Record, -): SwaggerSchema | undefined => { - const ref = schema?.$ref - if (!ref) - return schema - - const refName = schemaNameFromRef(ref) - if (!refName) - return schema - - return schemas[refName] ?? schema -} - const withoutNullableWrapper = (schema: SwaggerSchema | undefined): SwaggerSchema => { if (!schema) return {} @@ -461,95 +446,6 @@ const withoutNullableWrapper = (schema: SwaggerSchema | undefined): SwaggerSchem } } -const queryParameterFromSchema = ( - name: string, - schema: SwaggerSchema | undefined, - required: boolean, -): SwaggerParameter => { - const querySchema = withoutNullableWrapper(schema) - const parameter: SwaggerParameter = { - in: 'query', - name, - required, - schema: querySchema, - } - - if (querySchema.description) - parameter.description = querySchema.description - - return parameter -} - -const mergeQueryParameter = ( - parameters: SwaggerParameter[], - queryParameter: SwaggerParameter, -) => { - const existingIndex = parameters.findIndex((parameter) => { - return parameter.in === 'query' && parameter.name === queryParameter.name - }) - - if (existingIndex === -1) { - parameters.push(queryParameter) - return - } - - const existingParameter = parameters[existingIndex] - if (!existingParameter) { - parameters.push(queryParameter) - return - } - - parameters[existingIndex] = { - ...existingParameter, - ...queryParameter, - description: queryParameter.description ?? existingParameter.description, - required: Boolean(existingParameter.required) || Boolean(queryParameter.required), - } -} - -const normalizeGetBodyParameters = ( - operation: SwaggerOperation, - schemas: Record, -) => { - const bodyParameters: SwaggerParameter[] = [] - const normalizedParameters: SwaggerParameter[] = [] - - for (const parameter of operation.parameters ?? []) { - if (parameter.in === 'body') { - bodyParameters.push(parameter) - continue - } - - normalizedParameters.push(parameter) - } - - const requestBodySchema = getRequestBodySchema(operation) - if (requestBodySchema) { - bodyParameters.push({ - in: 'body', - name: 'payload', - required: Boolean(operation.requestBody?.required), - schema: requestBodySchema, - }) - } - - for (const parameter of bodyParameters) { - const schema = resolveSchemaRef(parameter.schema, schemas) - const properties = schema?.properties ?? {} - const required = new Set(schema?.required ?? []) - - for (const [name, propertySchema] of Object.entries(properties)) { - mergeQueryParameter( - normalizedParameters, - queryParameterFromSchema(name, propertySchema, required.has(name)), - ) - } - } - - operation.parameters = normalizedParameters - delete operation.requestBody -} - const normalizeResponses = (operation: SwaggerOperation) => { const responses = operation.responses ??= {} @@ -710,8 +606,6 @@ const normalizeOperations = (document: SwaggerDocument, surface: string) => { const swaggerOperation = operation as SwaggerOperation swaggerOperation.operationId = operationId(method, routePath) - if (method === 'get') - normalizeGetBodyParameters(swaggerOperation, schemas) normalizeResponses(swaggerOperation) const hasPossiblyInaccurateTypes = hasPossiblyInaccurateGeneratedContractTypes(swaggerOperation, schemas, { method,