mirror of
https://github.com/langgenius/dify.git
synced 2026-11-13 23:06:40 +08:00
refactor: fix OpenAPI contract generation schemas (#37387)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
7cf75c3cc5
commit
5d77c0af08
222 files changed
+15425
-10146
No files matched your search
@@ -20,6 +20,7 @@ openapi_ns = Namespace("openapi", description="User-scoped operations", path="/"
|
||||
|
||||
# Register response/query models BEFORE importing controller modules so that
|
||||
# @openapi_ns.response / @openapi_ns.expect decorators can resolve model names.
|
||||
from controllers.common.fields import EventStreamResponse
|
||||
from controllers.common.schema import register_enum_models, register_response_schema_models, register_schema_models
|
||||
from controllers.openapi._models import (
|
||||
AccountPayload,
|
||||
@@ -42,8 +43,10 @@ from controllers.openapi._models import (
|
||||
DeviceMutateRequest,
|
||||
DeviceMutateResponse,
|
||||
DevicePollRequest,
|
||||
DeviceTokenResponse,
|
||||
FormSubmitResponse,
|
||||
HealthResponse,
|
||||
HumanInputFormDefinitionResponse,
|
||||
MemberActionResponse,
|
||||
MemberInvitePayload,
|
||||
MemberInviteResponse,
|
||||
@@ -92,6 +95,7 @@ register_schema_models(
|
||||
register_response_schema_models(
|
||||
openapi_ns,
|
||||
ErrorBody,
|
||||
EventStreamResponse,
|
||||
TagItem,
|
||||
UsageInfo,
|
||||
MessageMetadata,
|
||||
@@ -120,7 +124,9 @@ register_response_schema_models(
|
||||
MemberActionResponse,
|
||||
TaskStopResponse,
|
||||
FormSubmitResponse,
|
||||
HumanInputFormDefinitionResponse,
|
||||
DeviceCodeResponse,
|
||||
DeviceTokenResponse,
|
||||
DeviceLookupResponse,
|
||||
DeviceMutateResponse,
|
||||
FileResponse,
|
||||
|
||||
@@ -87,12 +87,8 @@ class AppDescribeInfo(AppInfoResponse):
|
||||
|
||||
class AppDescribeResponse(BaseModel):
|
||||
info: AppDescribeInfo | None = None
|
||||
# `parameters` (the app-config blob) and `input_schema` (a Draft 2020-12 JSON Schema derived
|
||||
# per-app) are deliberately open JSON, not under-annotated. The `x-dify-opaque` marker tells the
|
||||
# contract generator's readiness detector to treat them as intentional, so the route is not
|
||||
# flagged "annotations incomplete". CLI/web consume them as opaque objects either way.
|
||||
parameters: dict[str, Any] | None = Field(default=None, json_schema_extra={"x-dify-opaque": True})
|
||||
input_schema: dict[str, Any] | None = Field(default=None, json_schema_extra={"x-dify-opaque": True})
|
||||
parameters: dict[str, Any] | None = Field(default=None)
|
||||
input_schema: dict[str, Any] | None = Field(default=None)
|
||||
|
||||
|
||||
class ChatMessageResponse(BaseModel):
|
||||
@@ -150,6 +146,18 @@ class WorkspacePayload(BaseModel):
|
||||
role: str
|
||||
|
||||
|
||||
class DeviceTokenResponse(BaseModel):
|
||||
token: str
|
||||
expires_at: str
|
||||
subject_type: Literal["account", "external_sso"]
|
||||
account: AccountPayload | None = None
|
||||
workspaces: list[WorkspacePayload] = []
|
||||
default_workspace_id: str | None = None
|
||||
token_id: str
|
||||
subject_email: str | None = None
|
||||
subject_issuer: str | None = None
|
||||
|
||||
|
||||
class AccountResponse(BaseModel):
|
||||
subject_type: str
|
||||
subject_email: str | None = None
|
||||
@@ -292,7 +300,7 @@ class AppListQuery(BaseModel):
|
||||
class AppRunRequest(BaseModel):
|
||||
inputs: dict[str, Any]
|
||||
query: str | None = None
|
||||
files: list[dict[str, Any]] | None = None
|
||||
files: list[dict[str, Any]] | None = Field(default=None)
|
||||
conversation_id: UUIDStrOrEmpty | None = None
|
||||
auto_generate_name: bool = True
|
||||
workflow_id: str | None = None
|
||||
@@ -469,3 +477,11 @@ class FormSubmitResponse(BaseModel):
|
||||
than an under-annotated open object."""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
|
||||
class HumanInputFormDefinitionResponse(BaseModel):
|
||||
form_content: str
|
||||
inputs: list[dict[str, Any]] = Field(default_factory=list)
|
||||
resolved_default_values: dict[str, str]
|
||||
user_actions: list[dict[str, Any]] = Field(default_factory=list)
|
||||
expiration_time: int | None = None
|
||||
@@ -18,6 +18,7 @@ from werkzeug.exceptions import (
|
||||
)
|
||||
|
||||
import services
|
||||
from controllers.common.fields import EventStreamResponse
|
||||
from controllers.openapi import openapi_ns
|
||||
from controllers.openapi._audit import emit_app_run
|
||||
from controllers.openapi._contract import accepts, returns
|
||||
@@ -136,7 +137,7 @@ _DISPATCH: dict[AppMode, Callable[[App, Any, AppRunRequest], Any]] = {
|
||||
@openapi_ns.route("/apps/<string:app_id>/run")
|
||||
class AppRunApi(Resource):
|
||||
@auth_router.guard(scope=Scope.APPS_RUN)
|
||||
@openapi_ns.response(200, "Run result (SSE stream)")
|
||||
@openapi_ns.response(200, "Run result (SSE stream)", openapi_ns.models[EventStreamResponse.__name__])
|
||||
@accepts(body=AppRunRequest)
|
||||
def post(self, app_id: str, *, auth_data: AuthData, body: AppRunRequest):
|
||||
app_model, caller, caller_kind = auth_data.require_app_context()
|
||||
|
||||
@@ -18,7 +18,7 @@ from controllers.common.human_input import HumanInputFormSubmitPayload, stringif
|
||||
from controllers.common.schema import register_schema_models
|
||||
from controllers.openapi import openapi_ns
|
||||
from controllers.openapi._contract import accepts, returns
|
||||
from controllers.openapi._models import FormSubmitResponse
|
||||
from controllers.openapi._models import FormSubmitResponse, HumanInputFormDefinitionResponse
|
||||
from controllers.openapi.auth.composition import auth_router
|
||||
from controllers.openapi.auth.data import AuthData
|
||||
from core.workflow.human_input_policy import HumanInputSurface, is_recipient_type_allowed_for_surface
|
||||
@@ -57,7 +57,7 @@ def _ensure_form_is_allowed_for_openapi(form) -> None:
|
||||
|
||||
@openapi_ns.route("/apps/<string:app_id>/form/human_input/<string:form_token>")
|
||||
class OpenApiWorkflowHumanInputFormApi(Resource):
|
||||
@openapi_ns.response(200, "Form definition")
|
||||
@openapi_ns.response(200, "Form definition", openapi_ns.models[HumanInputFormDefinitionResponse.__name__])
|
||||
@auth_router.guard(scope=Scope.APPS_RUN)
|
||||
def get(self, app_id: str, form_token: str, *, auth_data: AuthData):
|
||||
app_model, caller, caller_kind = auth_data.require_app_context()
|
||||
|
||||
@@ -42,6 +42,7 @@ from controllers.openapi._models import (
|
||||
DeviceMutateRequest,
|
||||
DeviceMutateResponse,
|
||||
DevicePollRequest,
|
||||
DeviceTokenResponse,
|
||||
WorkspacePayload,
|
||||
)
|
||||
from extensions.ext_database import db
|
||||
@@ -130,6 +131,7 @@ class OAuthDeviceTokenApi(Resource):
|
||||
"""RFC 8628 poll."""
|
||||
|
||||
@openapi_ns.expect(openapi_ns.models[DevicePollRequest.__name__])
|
||||
@openapi_ns.response(200, "Device token", openapi_ns.models[DeviceTokenResponse.__name__])
|
||||
def post(self):
|
||||
payload = _validate_json(DevicePollRequest)
|
||||
device_code = payload.device_code
|
||||
|
||||
@@ -13,9 +13,12 @@ from collections.abc import Generator
|
||||
|
||||
from flask import Response, request
|
||||
from flask_restx import Resource
|
||||
from pydantic import BaseModel, Field
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from werkzeug.exceptions import NotFound, UnprocessableEntity
|
||||
|
||||
from controllers.common.fields import EventStreamResponse
|
||||
from controllers.common.schema import query_params_from_model
|
||||
from controllers.openapi import openapi_ns
|
||||
from controllers.openapi.auth.composition import auth_router
|
||||
from controllers.openapi.auth.data import AuthData
|
||||
@@ -34,9 +37,15 @@ from repositories.factory import DifyAPIRepositoryFactory
|
||||
from services.workflow_event_snapshot_service import build_workflow_event_stream
|
||||
|
||||
|
||||
class WorkflowEventsQuery(BaseModel):
|
||||
include_state_snapshot: bool = Field(default=False, description="Whether to include workflow state snapshots")
|
||||
continue_on_pause: bool = Field(default=False, description="Whether to keep the event stream open on pause")
|
||||
|
||||
|
||||
@openapi_ns.route("/apps/<string:app_id>/tasks/<string:task_id>/events")
|
||||
class OpenApiWorkflowEventsApi(Resource):
|
||||
@openapi_ns.response(200, "SSE event stream")
|
||||
@openapi_ns.doc(params=query_params_from_model(WorkflowEventsQuery))
|
||||
@openapi_ns.response(200, "SSE event stream", openapi_ns.models[EventStreamResponse.__name__])
|
||||
@auth_router.guard(scope=Scope.APPS_RUN)
|
||||
def get(self, app_id: str, task_id: str, *, auth_data: AuthData):
|
||||
app_model, caller, caller_kind = auth_data.require_app_context()
|
||||
|
||||
Reference in new issue
Block a user