diff --git a/api/controllers/common/fields.py b/api/controllers/common/fields.py index 393f36cbc9d..7faa2cf8542 100644 --- a/api/controllers/common/fields.py +++ b/api/controllers/common/fields.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Any +from typing import Any, Literal from pydantic import BaseModel, ConfigDict, Field, RootModel, computed_field @@ -52,6 +52,11 @@ class AudioTranscriptResponse(ResponseModel): text: str +class ValidationResultResponse(ResponseModel): + result: Literal["success", "error"] + error: str | None = None + + class SimpleResultMessageResponse(ResponseModel): result: str message: str diff --git a/api/controllers/console/workspace/model_providers.py b/api/controllers/console/workspace/model_providers.py index 3bafa2ab6a6..adebe1a4a91 100644 --- a/api/controllers/console/workspace/model_providers.py +++ b/api/controllers/console/workspace/model_providers.py @@ -5,7 +5,7 @@ from flask import request, send_file from flask_restx import Resource from pydantic import BaseModel, Field, field_validator -from controllers.common.fields import BinaryFileResponse, SimpleResultResponse +from controllers.common.fields import SimpleResultResponse, ValidationResultResponse 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 ( @@ -22,8 +22,7 @@ from extensions.ext_database import db from fields.base import ResponseModel from graphon.model_runtime.entities.model_entities import ModelType from graphon.model_runtime.errors.validate import CredentialsValidateFailedError -from graphon.model_runtime.utils.encoders import jsonable_encoder -from libs.helper import uuid_value +from libs.helper import dump_response, uuid_value from libs.login import login_required from models import Account from services.billing_service import BillingService @@ -92,13 +91,8 @@ class ModelProviderListResponse(ResponseModel): data: list[ProviderResponse] -class ProviderCredentialResponse(ResponseModel): - credentials: dict[str, Any] | None = Field(default=None) - - -class ProviderCredentialValidateResponse(ResponseModel): - result: Literal["success", "error"] - error: str | None = None +class ProviderCredentialsResponse(ResponseModel): + credentials: dict[str, Any] | None = None class ModelProviderPaymentCheckoutUrlResponse(ResponseModel): @@ -118,19 +112,20 @@ register_schema_models( ) register_response_schema_models( console_ns, - BinaryFileResponse, SimpleResultResponse, ModelProviderListResponse, + ProviderCredentialsResponse, + ValidationResultResponse, ModelProviderPaymentCheckoutUrlResponse, - ProviderCredentialResponse, - ProviderCredentialValidateResponse, ) @console_ns.route("/workspaces/current/model-providers") class ModelProviderListApi(Resource): @console_ns.doc(params=query_params_from_model(ParserModelList)) - @console_ns.response(200, "Success", console_ns.models[ModelProviderListResponse.__name__]) + @console_ns.response( + 200, "Model providers retrieved successfully", console_ns.models[ModelProviderListResponse.__name__] + ) @setup_required @login_required @account_initialization_required @@ -142,13 +137,17 @@ class ModelProviderListApi(Resource): model_provider_service = ModelProviderService() provider_list = model_provider_service.get_provider_list(tenant_id=tenant_id, model_type=args.model_type) - return jsonable_encoder({"data": provider_list}) + return ModelProviderListResponse(data=provider_list).model_dump(mode="json") @console_ns.route("/workspaces/current/model-providers//credentials") class ModelProviderCredentialApi(Resource): @console_ns.doc(params=query_params_from_model(ParserCredentialId)) - @console_ns.response(200, "Success", console_ns.models[ProviderCredentialResponse.__name__]) + @console_ns.response( + 200, + "Provider credentials retrieved successfully", + console_ns.models[ProviderCredentialsResponse.__name__], + ) @setup_required @login_required @account_initialization_required @@ -163,7 +162,7 @@ class ModelProviderCredentialApi(Resource): tenant_id=tenant_id, provider=provider, credential_id=args.credential_id ) - return {"credentials": credentials} + return ProviderCredentialsResponse(credentials=credentials).model_dump(mode="json") @console_ns.expect(console_ns.models[ParserCredentialCreate.__name__]) @console_ns.response(201, "Credential created successfully", console_ns.models[SimpleResultResponse.__name__]) @@ -189,7 +188,7 @@ class ModelProviderCredentialApi(Resource): except CredentialsValidateFailedError as ex: raise ValueError(str(ex)) - return {"result": "success"}, 201 + return SimpleResultResponse(result="success").model_dump(mode="json"), 201 @console_ns.expect(console_ns.models[ParserCredentialUpdate.__name__]) @console_ns.response(200, "Credential updated successfully", console_ns.models[SimpleResultResponse.__name__]) @@ -216,7 +215,7 @@ class ModelProviderCredentialApi(Resource): except CredentialsValidateFailedError as ex: raise ValueError(str(ex)) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.expect(console_ns.models[ParserCredentialDelete.__name__]) @console_ns.response(204, "Credential deleted successfully") @@ -258,7 +257,7 @@ class ModelProviderCredentialSwitchApi(Resource): provider=provider, credential_id=args.credential_id, ) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.route("/workspaces/current/model-providers//credentials/validate") @@ -266,8 +265,8 @@ class ModelProviderValidateApi(Resource): @console_ns.expect(console_ns.models[ParserCredentialValidate.__name__]) @console_ns.response( 200, - "Credential validation result", - console_ns.models[ProviderCredentialValidateResponse.__name__], + "Provider credentials validated successfully", + console_ns.models[ValidationResultResponse.__name__], ) @setup_required @login_required @@ -292,12 +291,10 @@ class ModelProviderValidateApi(Resource): result = False error = str(ex) - response = {"result": "success" if result else "error"} - if not result: - response["error"] = error or "Unknown error" + return ValidationResultResponse(result="error", error=error or "Unknown error").model_dump(mode="json") - return response + return ValidationResultResponse(result="success").model_dump(mode="json") @console_ns.route("/workspaces//model-providers///") @@ -306,8 +303,9 @@ class ModelProviderIconApi(Resource): Get model provider icon """ - @console_ns.response(200, "Success", console_ns.models[BinaryFileResponse.__name__]) + @console_ns.response(200, "Model provider icon") def get(self, tenant_id: str, provider: str, icon_type: str, lang: str): + # response-contract:ignore binary send_file response model_provider_service = ModelProviderService() icon, mimetype = model_provider_service.get_model_provider_icon( tenant_id=tenant_id, @@ -339,12 +337,16 @@ class PreferredProviderTypeUpdateApi(Resource): tenant_id=tenant_id, provider=provider, preferred_provider_type=args.preferred_provider_type ) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.route("/workspaces/current/model-providers//checkout-url") class ModelProviderPaymentCheckoutUrlApi(Resource): - @console_ns.response(200, "Success", console_ns.models[ModelProviderPaymentCheckoutUrlResponse.__name__]) + @console_ns.response( + 200, + "Model provider checkout URL retrieved successfully", + console_ns.models[ModelProviderPaymentCheckoutUrlResponse.__name__], + ) @setup_required @login_required @account_initialization_required @@ -360,4 +362,4 @@ class ModelProviderPaymentCheckoutUrlApi(Resource): account_id=current_user.id, prefilled_email=current_user.email, ) - return data + return dump_response(ModelProviderPaymentCheckoutUrlResponse, data) diff --git a/api/controllers/console/workspace/models.py b/api/controllers/console/workspace/models.py index 0f735a7479e..b3c7833a070 100644 --- a/api/controllers/console/workspace/models.py +++ b/api/controllers/console/workspace/models.py @@ -5,7 +5,7 @@ from flask import request from flask_restx import Resource from pydantic import BaseModel, Field, field_validator -from controllers.common.fields import SimpleResultResponse +from controllers.common.fields import SimpleResultResponse, ValidationResultResponse from controllers.common.schema import ( query_params_from_model, register_enum_models, @@ -28,7 +28,6 @@ from extensions.ext_database import db from fields.base import ResponseModel from graphon.model_runtime.entities.model_entities import ModelType, ParameterRule from graphon.model_runtime.errors.validate import CredentialsValidateFailedError -from graphon.model_runtime.utils.encoders import jsonable_encoder from libs.helper import uuid_value from libs.login import login_required from models import Account @@ -63,7 +62,7 @@ class ParserDeleteModels(BaseModel): class LoadBalancingPayload(BaseModel): - configs: list[dict[str, Any]] | None = Field(default=None) + configs: list[dict[str, Any]] | None = None enabled: bool | None = None @@ -140,33 +139,38 @@ class DefaultModelDataResponse(ResponseModel): data: DefaultModelResponse | None = None -class ModelWithProviderListResponse(ResponseModel): +class ProviderModelListResponse(ResponseModel): data: list[ModelWithProviderEntityResponse] -class ProviderWithModelsDataResponse(ResponseModel): +class AvailableModelListResponse(ResponseModel): data: list[ProviderWithModelsResponse] -class ModelCredentialLoadBalancingResponse(ResponseModel): +class ModelLoadBalancingConfigResponse(ResponseModel): + id: str + name: str + credentials: dict[str, Any] + credential_id: str | None = None enabled: bool - configs: list[dict[str, Any]] = Field(default_factory=list) + in_cooldown: bool + ttl: int + + +class ModelLoadBalancingResponse(ResponseModel): + enabled: bool + configs: list[ModelLoadBalancingConfigResponse] class ModelCredentialResponse(ResponseModel): - credentials: dict[str, Any] = Field(default_factory=dict) + credentials: dict[str, Any] current_credential_id: str | None = None current_credential_name: str | None = None - load_balancing: ModelCredentialLoadBalancingResponse + load_balancing: ModelLoadBalancingResponse available_credentials: list[CredentialConfiguration] -class ModelCredentialValidateResponse(ResponseModel): - result: str - error: str | None = None - - -class ModelParameterRulesResponse(ResponseModel): +class ModelParameterRuleListResponse(ResponseModel): data: list[ParameterRule] @@ -187,12 +191,12 @@ register_schema_models( register_response_schema_models( console_ns, SimpleResultResponse, + ValidationResultResponse, DefaultModelDataResponse, - ModelWithProviderListResponse, - ProviderWithModelsDataResponse, + ProviderModelListResponse, ModelCredentialResponse, - ModelCredentialValidateResponse, - ModelParameterRulesResponse, + ModelParameterRuleListResponse, + AvailableModelListResponse, ) register_enum_models(console_ns, ModelType) @@ -201,7 +205,9 @@ register_enum_models(console_ns, ModelType) @console_ns.route("/workspaces/current/default-model") class DefaultModelApi(Resource): @console_ns.doc(params=query_params_from_model(ParserGetDefault)) - @console_ns.response(200, "Success", console_ns.models[DefaultModelDataResponse.__name__]) + @console_ns.response( + 200, "Default model retrieved successfully", console_ns.models[DefaultModelDataResponse.__name__] + ) @setup_required @login_required @account_initialization_required @@ -214,7 +220,7 @@ class DefaultModelApi(Resource): tenant_id=tenant_id, model_type=args.model_type ) - return jsonable_encoder({"data": default_model_entity}) + return DefaultModelDataResponse(data=default_model_entity).model_dump(mode="json") @console_ns.expect(console_ns.models[ParserPostDefault.__name__]) @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) @@ -247,12 +253,14 @@ class DefaultModelApi(Resource): ) raise ex - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.route("/workspaces/current/model-providers//models") class ModelProviderModelApi(Resource): - @console_ns.response(200, "Success", console_ns.models[ModelWithProviderListResponse.__name__]) + @console_ns.response( + 200, "Provider models retrieved successfully", console_ns.models[ProviderModelListResponse.__name__] + ) @setup_required @login_required @account_initialization_required @@ -261,10 +269,10 @@ class ModelProviderModelApi(Resource): model_provider_service = ModelProviderService() models = model_provider_service.get_models_by_provider(tenant_id=tenant_id, provider=provider) - return jsonable_encoder({"data": models}) + return ProviderModelListResponse(data=models).model_dump(mode="json") @console_ns.expect(console_ns.models[ParserPostModels.__name__]) - @console_ns.response(200, "Success", console_ns.models[SimpleResultResponse.__name__]) + @console_ns.response(200, "Model updated successfully", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required @@ -310,7 +318,7 @@ class ModelProviderModelApi(Resource): tenant_id=tenant_id, provider=provider, model=args.model, model_type=args.model_type ) - return {"result": "success"}, 200 + return SimpleResultResponse(result="success").model_dump(mode="json"), 200 @console_ns.expect(console_ns.models[ParserDeleteModels.__name__]) @console_ns.response(204, "Model deleted successfully") @@ -334,7 +342,11 @@ class ModelProviderModelApi(Resource): @console_ns.route("/workspaces/current/model-providers//models/credentials") class ModelProviderModelCredentialApi(Resource): @console_ns.doc(params=query_params_from_model(ParserGetCredentials)) - @console_ns.response(200, "Success", console_ns.models[ModelCredentialResponse.__name__]) + @console_ns.response( + 200, + "Model credentials retrieved successfully", + console_ns.models[ModelCredentialResponse.__name__], + ) @setup_required @login_required @account_initialization_required @@ -379,22 +391,23 @@ class ModelProviderModelCredentialApi(Resource): model=args.model, ) - return jsonable_encoder( - { - "credentials": current_credential.get("credentials") if current_credential else {}, - "current_credential_id": current_credential.get("current_credential_id") - if current_credential - else None, - "current_credential_name": current_credential.get("current_credential_name") - if current_credential - else None, - "load_balancing": {"enabled": is_load_balancing_enabled, "configs": load_balancing_configs}, - "available_credentials": available_credentials, - } - ) + credentials: dict[str, Any] = {} + # TODO: make this throw error when type mismatches? + if current_credential and isinstance(current_credential.get("credentials"), dict): + credentials = cast(dict[str, Any], current_credential["credentials"]) + + return ModelCredentialResponse( + credentials=credentials, + current_credential_id=current_credential.get("current_credential_id") if current_credential else None, + current_credential_name=current_credential.get("current_credential_name") if current_credential else None, + load_balancing=ModelLoadBalancingResponse.model_validate( + {"enabled": is_load_balancing_enabled, "configs": load_balancing_configs} + ), + available_credentials=available_credentials, + ).model_dump(mode="json") @console_ns.expect(console_ns.models[ParserCreateCredential.__name__]) - @console_ns.response(201, "Credential created successfully", console_ns.models[SimpleResultResponse.__name__]) + @console_ns.response(201, "Model credential created successfully", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required @@ -424,10 +437,10 @@ class ModelProviderModelCredentialApi(Resource): ) raise ValueError(str(ex)) - return {"result": "success"}, 201 + return SimpleResultResponse(result="success").model_dump(mode="json"), 201 @console_ns.expect(console_ns.models[ParserUpdateCredential.__name__]) - @console_ns.response(200, "Credential updated successfully", console_ns.models[SimpleResultResponse.__name__]) + @console_ns.response(200, "Model credential updated successfully", console_ns.models[SimpleResultResponse.__name__]) @setup_required @login_required @is_admin_or_owner_required @@ -452,7 +465,7 @@ class ModelProviderModelCredentialApi(Resource): except CredentialsValidateFailedError as ex: raise ValueError(str(ex)) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.expect(console_ns.models[ParserDeleteCredential.__name__]) @console_ns.response(204, "Credential deleted successfully") @@ -498,7 +511,7 @@ class ModelProviderModelCredentialSwitchApi(Resource): model=args.model, credential_id=args.credential_id, ) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.route( @@ -520,7 +533,7 @@ class ModelProviderModelEnableApi(Resource): tenant_id=tenant_id, provider=provider, model=args.model, model_type=args.model_type ) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") @console_ns.route( @@ -542,7 +555,7 @@ class ModelProviderModelDisableApi(Resource): tenant_id=tenant_id, provider=provider, model=args.model, model_type=args.model_type ) - return {"result": "success"} + return SimpleResultResponse(result="success").model_dump(mode="json") class ParserValidate(BaseModel): @@ -559,8 +572,8 @@ class ModelProviderModelValidateApi(Resource): @console_ns.expect(console_ns.models[ParserValidate.__name__]) @console_ns.response( 200, - "Credential validation result", - console_ns.models[ModelCredentialValidateResponse.__name__], + "Model credentials validated successfully", + console_ns.models[ValidationResultResponse.__name__], ) @setup_required @login_required @@ -586,18 +599,20 @@ class ModelProviderModelValidateApi(Resource): result = False error = str(ex) - response = {"result": "success" if result else "error"} - if not result: - response["error"] = error or "" + return ValidationResultResponse(result="error", error=error or "").model_dump(mode="json") - return response + return ValidationResultResponse(result="success").model_dump(mode="json") @console_ns.route("/workspaces/current/model-providers//models/parameter-rules") class ModelProviderModelParameterRuleApi(Resource): @console_ns.doc(params=query_params_from_model(ParserParameter)) - @console_ns.response(200, "Success", console_ns.models[ModelParameterRulesResponse.__name__]) + @console_ns.response( + 200, + "Model parameter rules retrieved successfully", + console_ns.models[ModelParameterRuleListResponse.__name__], + ) @setup_required @login_required @account_initialization_required @@ -610,12 +625,14 @@ class ModelProviderModelParameterRuleApi(Resource): tenant_id=tenant_id, provider=provider, model=args.model ) - return jsonable_encoder({"data": parameter_rules}) + return ModelParameterRuleListResponse(data=parameter_rules).model_dump(mode="json") @console_ns.route("/workspaces/current/models/model-types/") class ModelProviderAvailableModelApi(Resource): - @console_ns.response(200, "Success", console_ns.models[ProviderWithModelsDataResponse.__name__]) + @console_ns.response( + 200, "Available models retrieved successfully", console_ns.models[AvailableModelListResponse.__name__] + ) @setup_required @login_required @account_initialization_required @@ -624,4 +641,4 @@ class ModelProviderAvailableModelApi(Resource): model_provider_service = ModelProviderService() models = model_provider_service.get_models_by_model_type(tenant_id=tenant_id, model_type=model_type) - return jsonable_encoder({"data": models}) + return AvailableModelListResponse(data=models).model_dump(mode="json") diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py index c7644af2b48..d87c1a99b0a 100644 --- a/api/controllers/console/workspace/plugin.py +++ b/api/controllers/console/workspace/plugin.py @@ -31,7 +31,15 @@ from controllers.console.wraps import ( with_current_user_id, ) from core.helper.position_helper import is_filtered -from core.plugin.entities.plugin import PluginCategory, PluginInstallationSource +from core.plugin.entities.bundle import PluginBundleDependency +from core.plugin.entities.parameters import PluginParameterOption +from core.plugin.entities.plugin import ( + PluginCategory, + PluginDeclaration, + PluginEntity, + PluginInstallationSource, +) +from core.plugin.entities.plugin_daemon import PluginDecodeResponse, PluginInstallTask, PluginInstallTaskStartResponse from core.plugin.impl.exc import PluginDaemonClientSideError from core.plugin.plugin_service import PluginService from core.tools.builtin_tool.providers._positions import BuiltinToolProviderSort @@ -299,12 +307,12 @@ class PluginCategoryListResponse(ResponseModel): has_more: bool -class PluginDaemonOperationResponse(RootModel[Any]): - root: Any +class PluginBundleUploadResponse(RootModel[list[PluginBundleDependency]]): + pass class PluginListResponse(ResponseModel): - plugins: Any + plugins: list[PluginEntity] total: int @@ -334,15 +342,15 @@ class PluginInstallationsResponse(ResponseModel): class PluginManifestResponse(ResponseModel): - manifest: Any + manifest: PluginDeclaration class PluginTasksResponse(ResponseModel): - tasks: Any + tasks: list[PluginInstallTask] class PluginTaskResponse(ResponseModel): - task: Any + task: PluginInstallTask class PluginPermissionResponse(ResponseModel): @@ -351,7 +359,7 @@ class PluginPermissionResponse(ResponseModel): class PluginDynamicOptionsResponse(ResponseModel): - options: Any + options: list[PluginParameterOption] class PluginOperationSuccessResponse(ResponseModel): @@ -398,10 +406,12 @@ register_response_schema_models( PluginCategoryBuiltinToolResponse, PluginCategoryInstalledPluginResponse, PluginCategoryListResponse, - PluginDaemonOperationResponse, + PluginBundleUploadResponse, + PluginDecodeResponse, PluginDebuggingKeyResponse, PluginDynamicOptionsResponse, PluginInstallationsResponse, + PluginInstallTaskStartResponse, PluginListResponse, PluginManifestResponse, PluginOperationSuccessResponse, @@ -635,7 +645,7 @@ class PluginAssetApi(Resource): @console_ns.route("/workspaces/current/plugin/upload/pkg") class PluginUploadFromPkgApi(Resource): - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginDecodeResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -656,7 +666,7 @@ class PluginUploadFromPkgApi(Resource): @console_ns.route("/workspaces/current/plugin/upload/github") class PluginUploadFromGithubApi(Resource): @console_ns.expect(console_ns.models[ParserGithubUpload.__name__]) - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginDecodeResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -676,7 +686,7 @@ class PluginUploadFromGithubApi(Resource): @console_ns.route("/workspaces/current/plugin/upload/bundle") class PluginUploadFromBundleApi(Resource): - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginBundleUploadResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -697,7 +707,7 @@ class PluginUploadFromBundleApi(Resource): @console_ns.route("/workspaces/current/plugin/install/pkg") class PluginInstallFromPkgApi(Resource): @console_ns.expect(console_ns.models[ParserPluginIdentifiers.__name__]) - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginInstallTaskStartResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -718,7 +728,7 @@ class PluginInstallFromPkgApi(Resource): @console_ns.route("/workspaces/current/plugin/install/github") class PluginInstallFromGithubApi(Resource): @console_ns.expect(console_ns.models[ParserGithubInstall.__name__]) - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginInstallTaskStartResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -745,7 +755,7 @@ class PluginInstallFromGithubApi(Resource): @console_ns.route("/workspaces/current/plugin/install/marketplace") class PluginInstallFromMarketplaceApi(Resource): @console_ns.expect(console_ns.models[ParserPluginIdentifiers.__name__]) - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginInstallTaskStartResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -891,7 +901,7 @@ class PluginDeleteInstallTaskItemApi(Resource): @console_ns.route("/workspaces/current/plugin/upgrade/marketplace") class PluginUpgradeFromMarketplaceApi(Resource): @console_ns.expect(console_ns.models[ParserMarketplaceUpgrade.__name__]) - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginInstallTaskStartResponse.__name__]) @setup_required @login_required @account_initialization_required @@ -914,7 +924,7 @@ class PluginUpgradeFromMarketplaceApi(Resource): @console_ns.route("/workspaces/current/plugin/upgrade/github") class PluginUpgradeFromGithubApi(Resource): @console_ns.expect(console_ns.models[ParserGithubUpgrade.__name__]) - @console_ns.response(200, "Success", console_ns.models[PluginDaemonOperationResponse.__name__]) + @console_ns.response(200, "Success", console_ns.models[PluginInstallTaskStartResponse.__name__]) @setup_required @login_required @account_initialization_required diff --git a/api/openapi/markdown/console-openapi.md b/api/openapi/markdown/console-openapi.md index 7822f330d84..bc9e7a626eb 100644 --- a/api/openapi/markdown/console-openapi.md +++ b/api/openapi/markdown/console-openapi.md @@ -9956,7 +9956,7 @@ Increment snippet use count by 1 | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [DefaultModelDataResponse](#defaultmodeldataresponse)
| +| 200 | Default model retrieved successfully | **application/json**: [DefaultModelDataResponse](#defaultmodeldataresponse)
| ### [POST] /workspaces/current/default-model #### Request Body @@ -10255,7 +10255,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ModelProviderListResponse](#modelproviderlistresponse)
| +| 200 | Model providers retrieved successfully | **application/json**: [ModelProviderListResponse](#modelproviderlistresponse)
| ### [GET] /workspaces/current/model-providers/{provider}/checkout-url #### Parameters @@ -10268,7 +10268,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ModelProviderPaymentCheckoutUrlResponse](#modelproviderpaymentcheckouturlresponse)
| +| 200 | Model provider checkout URL retrieved successfully | **application/json**: [ModelProviderPaymentCheckoutUrlResponse](#modelproviderpaymentcheckouturlresponse)
| ### [DELETE] /workspaces/current/model-providers/{provider}/credentials #### Parameters @@ -10301,7 +10301,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ProviderCredentialResponse](#providercredentialresponse)
| +| 200 | Provider credentials retrieved successfully | **application/json**: [ProviderCredentialsResponse](#providercredentialsresponse)
| ### [POST] /workspaces/current/model-providers/{provider}/credentials #### Parameters @@ -10377,7 +10377,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Credential validation result | **application/json**: [ProviderCredentialValidateResponse](#providercredentialvalidateresponse)
| +| 200 | Provider credentials validated successfully | **application/json**: [ValidationResultResponse](#validationresultresponse)
| ### [DELETE] /workspaces/current/model-providers/{provider}/models #### Parameters @@ -10409,7 +10409,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ModelWithProviderListResponse](#modelwithproviderlistresponse)
| +| 200 | Provider models retrieved successfully | **application/json**: [ProviderModelListResponse](#providermodellistresponse)
| ### [POST] /workspaces/current/model-providers/{provider}/models #### Parameters @@ -10428,7 +10428,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [SimpleResultResponse](#simpleresultresponse)
| +| 200 | Model updated successfully | **application/json**: [SimpleResultResponse](#simpleresultresponse)
| ### [DELETE] /workspaces/current/model-providers/{provider}/models/credentials #### Parameters @@ -10464,7 +10464,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ModelCredentialResponse](#modelcredentialresponse)
| +| 200 | Model credentials retrieved successfully | **application/json**: [ModelCredentialResponse](#modelcredentialresponse)
| ### [POST] /workspaces/current/model-providers/{provider}/models/credentials #### Parameters @@ -10483,7 +10483,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 201 | Credential created successfully | **application/json**: [SimpleResultResponse](#simpleresultresponse)
| +| 201 | Model credential created successfully | **application/json**: [SimpleResultResponse](#simpleresultresponse)
| ### [PUT] /workspaces/current/model-providers/{provider}/models/credentials #### Parameters @@ -10502,7 +10502,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Credential updated successfully | **application/json**: [SimpleResultResponse](#simpleresultresponse)
| +| 200 | Model credential updated successfully | **application/json**: [SimpleResultResponse](#simpleresultresponse)
| ### [POST] /workspaces/current/model-providers/{provider}/models/credentials/switch #### Parameters @@ -10540,7 +10540,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Credential validation result | **application/json**: [ModelCredentialValidateResponse](#modelcredentialvalidateresponse)
| +| 200 | Model credentials validated successfully | **application/json**: [ValidationResultResponse](#validationresultresponse)
| ### [PATCH] /workspaces/current/model-providers/{provider}/models/disable #### Parameters @@ -10631,7 +10631,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ModelParameterRulesResponse](#modelparameterrulesresponse)
| +| 200 | Model parameter rules retrieved successfully | **application/json**: [ModelParameterRuleListResponse](#modelparameterrulelistresponse)
| ### [POST] /workspaces/current/model-providers/{provider}/preferred-provider-type #### Parameters @@ -10663,7 +10663,7 @@ Update a plugin endpoint | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [ProviderWithModelsDataResponse](#providerwithmodelsdataresponse)
| +| 200 | Available models retrieved successfully | **application/json**: [AvailableModelListResponse](#availablemodellistresponse)
| ### [GET] /workspaces/current/permission **Get workspace permission settings** @@ -10774,7 +10774,7 @@ Returns permission flags that control workspace features like member invitations | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginInstallTaskStartResponse](#plugininstalltaskstartresponse)
| ### [POST] /workspaces/current/plugin/install/marketplace #### Request Body @@ -10787,7 +10787,7 @@ Returns permission flags that control workspace features like member invitations | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginInstallTaskStartResponse](#plugininstalltaskstartresponse)
| ### [POST] /workspaces/current/plugin/install/pkg #### Request Body @@ -10800,7 +10800,7 @@ Returns permission flags that control workspace features like member invitations | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginInstallTaskStartResponse](#plugininstalltaskstartresponse)
| ### [GET] /workspaces/current/plugin/list #### Parameters @@ -11007,7 +11007,7 @@ Returns permission flags that control workspace features like member invitations | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginInstallTaskStartResponse](#plugininstalltaskstartresponse)
| ### [POST] /workspaces/current/plugin/upgrade/marketplace #### Request Body @@ -11020,14 +11020,14 @@ Returns permission flags that control workspace features like member invitations | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginInstallTaskStartResponse](#plugininstalltaskstartresponse)
| ### [POST] /workspaces/current/plugin/upload/bundle #### Responses | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginBundleUploadResponse](#pluginbundleuploadresponse)
| ### [POST] /workspaces/current/plugin/upload/github #### Request Body @@ -11040,14 +11040,14 @@ Returns permission flags that control workspace features like member invitations | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginDecodeResponse](#plugindecoderesponse)
| ### [POST] /workspaces/current/plugin/upload/pkg #### Responses | Code | Description | Schema | | ---- | ----------- | ------ | -| 200 | Success | **application/json**: [PluginDaemonOperationResponse](#plugindaemonoperationresponse)
| +| 200 | Success | **application/json**: [PluginDecodeResponse](#plugindecoderesponse)
| ### [GET] /workspaces/current/plugin/{category}/list #### Parameters @@ -12526,9 +12526,9 @@ Returns permission flags that control workspace features like member invitations #### Responses -| Code | Description | Schema | -| ---- | ----------- | ------ | -| 200 | Success | **application/json**: [BinaryFileResponse](#binaryfileresponse)
| +| Code | Description | +| ---- | ----------- | +| 200 | Model provider icon | --- ## default @@ -12552,6 +12552,22 @@ Default namespace --- ### Schemas +#### AIModelEntity + +Model class for AI model. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| deprecated | boolean | | No | +| features | [ [ModelFeature](#modelfeature) ] | | No | +| fetch_from | [FetchFrom](#fetchfrom) | | Yes | +| label | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | Yes | +| model | string | | Yes | +| model_properties | object | | Yes | +| model_type | [ModelType](#modeltype) | | Yes | +| parameter_rules | [ [ParameterRule](#parameterrule) ],
**Default:** | | No | +| pricing | [PriceConfig](#priceconfig) | | No | + #### AIModelEntityResponse | Name | Type | Description | Required | @@ -14594,6 +14610,27 @@ Soft lifecycle state for Agent records. | ---- | ---- | ----------- | -------- | | AgentStatus | string | Soft lifecycle state for Agent records. | | +#### AgentStrategyProviderEntity + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| identity | [AgentStrategyProviderIdentity](#agentstrategyprovideridentity) | | Yes | +| plugin_id | string | The id of the plugin | No | + +#### AgentStrategyProviderIdentity + +Inherits from ToolProviderIdentity, without any additional fields. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| author | string | The author of the tool | Yes | +| description | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The description of the tool | Yes | +| icon | string | The icon of the tool | Yes | +| icon_dark | string | The dark icon of the tool | No | +| label | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The label of the tool | Yes | +| name | string | The name of the tool | Yes | +| tags | [ [ToolLabelEnum](#toollabelenum) ] | The tags of the tool | No | + #### AgentSuggestedQuestionsAfterAnswerFeatureConfig | Name | Type | Description | Required | @@ -15316,6 +15353,12 @@ AppMCPServer Status Enum | ---- | ---- | ----------- | -------- | | text | string | | Yes | +#### AuthorizedCategory + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| AuthorizedCategory | string | | | + #### AutoDisableLogsResponse | Name | Type | Description | Required | @@ -15323,6 +15366,12 @@ AppMCPServer Status Enum | count | integer | | Yes | | document_ids | [ string ] | | Yes | +#### AvailableModelListResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | [ [ProviderWithModelsResponse](#providerwithmodelsresponse) ] | | Yes | + #### AvatarUrlResponse | Name | Type | Description | Required | @@ -16824,6 +16873,36 @@ Model class for provider custom model configuration. | plugin_unique_identifier | string | | Yes | | provider | string | | Yes | +#### DatasourceProviderEntity + +Datasource provider entity + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| credentials_schema | [ [ProviderConfig](#providerconfig) ] | | No | +| identity | [DatasourceProviderIdentity](#datasourceprovideridentity) | | Yes | +| oauth_schema | [OAuthSchema](#oauthschema) | | No | +| provider_type | [DatasourceProviderType](#datasourceprovidertype) | | Yes | + +#### DatasourceProviderIdentity + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| author | string | The author of the tool | Yes | +| description | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The description of the tool | Yes | +| icon | string | The icon of the tool | Yes | +| label | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The label of the tool | Yes | +| name | string | The name of the tool | Yes | +| tags | [ [ToolLabelEnum](#toollabelenum) ] | The tags of the tool | No | + +#### DatasourceProviderType + +Enum class for datasource provider + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| DatasourceProviderType | string | Enum class for datasource provider | | + #### DatasourceUpdateNamePayload | Name | Type | Description | Required | @@ -17267,6 +17346,12 @@ Request payload for bulk downloading documents as a zip archive. | ---- | ---- | ----------- | -------- | | EmptyObjectResponse | object | | | +#### Endpoint + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | + #### EndpointCreatePayload | Name | Type | Description | Required | @@ -17275,6 +17360,16 @@ Request payload for bulk downloading documents as a zip archive. | plugin_unique_identifier | string | | Yes | | settings | object | | Yes | +#### EndpointDeclaration + +declaration of an endpoint + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| hidden | boolean | | No | +| method | string | | Yes | +| path | string | | Yes | + #### EndpointDeclarationResponse | Name | Type | Description | Required | @@ -17365,6 +17460,15 @@ Request payload for bulk downloading documents as a zip archive. | ---- | ---- | ----------- | -------- | | EndpointProviderConfigScope | string | | | +#### EndpointProviderDeclaration + +declaration of an endpoint group + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| endpoints | [ [EndpointDeclaration](#endpointdeclaration) ] | | No | +| settings | [ [ProviderConfig](#providerconfig) ] | | No | + #### EndpointProviderDeclarationResponse | Name | Type | Description | Required | @@ -17448,6 +17552,17 @@ Request payload for bulk downloading documents as a zip archive. | output_schema | object | The output schema of the trigger | Yes | | parameters | [ [EventParameter](#eventparameter) ] | The parameters of the trigger | Yes | +#### EventEntity + +The configuration of an event + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| description | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The description of the event | Yes | +| identity | [EventIdentity](#eventidentity) | | Yes | +| output_schema | object | The output schema that this event produces | No | +| parameters | [ [EventParameter](#eventparameter) ] | The parameters of the event | No | + #### EventIdentity The identity of the event @@ -18662,6 +18777,13 @@ Enum class for large language model mode. | first_id | string | The ID of the first chat record on the current page. Omit this value to fetch the latest messages; for subsequent pages, use the first message ID from the current list to fetch older messages. | No | | limit | integer,
**Default:** 20 | Number of chat history messages to return per request. | No | +#### Meta + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| minimum_dify_version | string | | No | +| version | string | | No | + #### MetadataArgs | Name | Type | Description | Required | @@ -18700,6 +18822,18 @@ Metadata operation data | ---- | ---- | ----------- | -------- | | name | string | New metadata field name. | Yes | +#### Model + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | +| llm | boolean | | No | +| moderation | boolean | | No | +| rerank | boolean | | No | +| speech2text | boolean | | No | +| text_embedding | boolean | | No | +| tts | boolean | | No | + #### ModelConfig | Name | Type | Description | Required | @@ -18737,22 +18871,15 @@ Metadata operation data | text_to_speech | object | Text to speech configuration | No | | tools | [ object ] | Available tools | No | -#### ModelCredentialLoadBalancingResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| configs | [ object ] | | No | -| enabled | boolean | | Yes | - #### ModelCredentialResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | available_credentials | [ [CredentialConfiguration](#credentialconfiguration) ] | | Yes | -| credentials | object | | No | +| credentials | object | | Yes | | current_credential_id | string | | No | | current_credential_name | string | | No | -| load_balancing | [ModelCredentialLoadBalancingResponse](#modelcredentialloadbalancingresponse) | | Yes | +| load_balancing | [ModelLoadBalancingResponse](#modelloadbalancingresponse) | | Yes | #### ModelCredentialSchema @@ -18763,13 +18890,6 @@ Model class for model credential schema. | credential_form_schemas | [ [CredentialFormSchema](#credentialformschema) ] | | Yes | | model | [FieldModelSchema](#fieldmodelschema) | | Yes | -#### ModelCredentialValidateResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| error | string | | No | -| result | string | | Yes | - #### ModelFeature Enum class for llm feature. @@ -18778,7 +18898,26 @@ Enum class for llm feature. | ---- | ---- | ----------- | -------- | | ModelFeature | string | Enum class for llm feature. | | -#### ModelParameterRulesResponse +#### ModelLoadBalancingConfigResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| credential_id | string | | No | +| credentials | object | | Yes | +| enabled | boolean | | Yes | +| id | string | | Yes | +| in_cooldown | boolean | | Yes | +| name | string | | Yes | +| ttl | integer | | Yes | + +#### ModelLoadBalancingResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| configs | [ [ModelLoadBalancingConfigResponse](#modelloadbalancingconfigresponse) ] | | Yes | +| enabled | boolean | | Yes | + +#### ModelParameterRuleListResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | @@ -18844,12 +18983,6 @@ Model with provider entity. | provider | [SimpleProviderEntityResponse](#simpleproviderentityresponse) | | Yes | | status | [ModelStatus](#modelstatus) | | Yes | -#### ModelWithProviderListResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| data | [ [ModelWithProviderEntityResponse](#modelwithproviderentityresponse) ] | | Yes | - #### MoreLikeThisQuery | Name | Type | Description | Required | @@ -18871,6 +19004,12 @@ Model with provider entity. | new_app_id | string | | Yes | | permission_keys | [ string ] | | No | +#### Node + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | + #### NodeIdQuery | Name | Type | Description | Required | @@ -19575,6 +19714,16 @@ Enum class for parameter type. | node_title | string | | Yes | | pause_type | [HumanInputPauseTypeResponse](#humaninputpausetyperesponse) | | Yes | +#### Permission + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| endpoint | [Endpoint](#endpoint) | | No | +| model | [Model](#model) | | No | +| node | [Node](#node) | | No | +| storage | [Storage](#storage) | | No | +| tool | [Tool](#tool) | | No | + #### PermissionCatalogGroup | Name | Type | Description | Required | @@ -19704,6 +19853,25 @@ Shared permission levels for resources (datasets, credentials, etc.) | upgrade_mode | [TenantPluginAutoUpgradeMode](#tenantpluginautoupgrademode) | | Yes | | upgrade_time_of_day | integer | | Yes | +#### PluginBundleDependency + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| type | [PluginBundleDependencyType](#pluginbundledependencytype) | | Yes | +| value | [Github](#github)
[Marketplace](#marketplace)
[Package](#package) | | Yes | + +#### PluginBundleDependencyType + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| PluginBundleDependencyType | string | | | + +#### PluginBundleUploadResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| PluginBundleUploadResponse | array | | | + #### PluginCategory | Name | Type | Description | Required | @@ -19778,12 +19946,6 @@ Shared permission levels for resources (datasets, credentials, etc.) | has_more | boolean | | Yes | | plugins | [ [PluginCategoryInstalledPluginResponse](#plugincategoryinstalledpluginresponse) ] | | Yes | -#### PluginDaemonOperationResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| PluginDaemonOperationResponse | | | | - #### PluginDebuggingKeyResponse | Name | Type | Description | Required | @@ -19792,6 +19954,32 @@ Shared permission levels for resources (datasets, credentials, etc.) | key | string | | Yes | | port | integer | | Yes | +#### PluginDeclaration + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| agent_strategy | [AgentStrategyProviderEntity](#agentstrategyproviderentity) | | No | +| author | string | | Yes | +| category | [PluginCategory](#plugincategory) | | Yes | +| created_at | dateTime | | Yes | +| datasource | [DatasourceProviderEntity](#datasourceproviderentity) | | No | +| description | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | | Yes | +| endpoint | [EndpointProviderDeclaration](#endpointproviderdeclaration) | | No | +| icon | string | | Yes | +| icon_dark | string | | No | +| label | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | | Yes | +| meta | [Meta](#meta) | | Yes | +| model | [ProviderEntity](#providerentity) | | No | +| name | string | | Yes | +| plugins | [Plugins](#plugins) | | Yes | +| repo | string | | No | +| resource | [PluginResourceRequirements](#pluginresourcerequirements) | | Yes | +| tags | [ string ] | | No | +| tool | [ToolProviderEntity](#toolproviderentity) | | No | +| trigger | [TriggerProviderEntity](#triggerproviderentity) | | No | +| verified | boolean | | No | +| version | string | | Yes | + #### PluginDeclarationResponse | Name | Type | Description | Required | @@ -19818,6 +20006,14 @@ Shared permission levels for resources (datasets, credentials, etc.) | verified | boolean | | No | | version | string | | Yes | +#### PluginDecodeResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| manifest | [PluginDeclaration](#plugindeclaration) | | Yes | +| unique_identifier | string | The unique identifier of the plugin. | Yes | +| verification | [PluginVerification](#pluginverification) | Basic verification information | No | + #### PluginDependency | Name | Type | Description | Required | @@ -19836,7 +20032,66 @@ Shared permission levels for resources (datasets, credentials, etc.) | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| options | | | Yes | +| options | [ [PluginParameterOption](#pluginparameteroption) ] | | Yes | + +#### PluginEntity + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| checksum | string | | Yes | +| created_at | dateTime | | Yes | +| declaration | [PluginDeclaration](#plugindeclaration) | | Yes | +| endpoints_active | integer | | Yes | +| endpoints_setups | integer | | Yes | +| id | string | | Yes | +| installation_id | string | | Yes | +| meta | object | | Yes | +| name | string | | Yes | +| plugin_id | string | | Yes | +| plugin_unique_identifier | string | | Yes | +| runtime_type | string | | Yes | +| source | [PluginInstallationSource](#plugininstallationsource) | | Yes | +| tenant_id | string | | Yes | +| updated_at | dateTime | | Yes | +| version | string | | Yes | + +#### PluginInstallTask + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| completed_plugins | integer | The number of plugins that have been installed. | Yes | +| created_at | dateTime | | Yes | +| id | string | | Yes | +| plugins | [ [PluginInstallTaskPluginStatus](#plugininstalltaskpluginstatus) ] | The status of the plugins. | Yes | +| status | [PluginInstallTaskStatus](#plugininstalltaskstatus) | The status of the install task. | Yes | +| total_plugins | integer | The total number of plugins to be installed. | Yes | +| updated_at | dateTime | | Yes | + +#### PluginInstallTaskPluginStatus + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| icon | string | The icon of the plugin. | Yes | +| labels | [I18nObject](#i18nobject) | The labels of the plugin. | Yes | +| message | string | The message of the install task. | Yes | +| plugin_id | string | The plugin ID of the install task. | Yes | +| plugin_unique_identifier | string | The plugin unique identifier of the install task. | Yes | +| source | string | The installation source of the plugin | No | +| status | [PluginInstallTaskStatus](#plugininstalltaskstatus) | The status of the install task. | Yes | + +#### PluginInstallTaskStartResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| all_installed | boolean | Whether all plugins are installed. | Yes | +| task | [PluginInstallTask](#plugininstalltask) | The install task. | No | +| task_id | string | The ID of the install task. | Yes | + +#### PluginInstallTaskStatus + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| PluginInstallTaskStatus | string | | | #### PluginInstallationItemResponse @@ -19886,7 +20141,7 @@ Shared permission levels for resources (datasets, credentials, etc.) | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| plugins | | | Yes | +| plugins | [ [PluginEntity](#pluginentity) ] | | Yes | | total | integer | | Yes | #### PluginManagerModel @@ -19899,7 +20154,7 @@ Shared permission levels for resources (datasets, credentials, etc.) | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| manifest | | | Yes | +| manifest | [PluginDeclaration](#plugindeclaration) | | Yes | #### PluginOAuthAuthorizationUrlResponse @@ -19960,17 +20215,32 @@ Shared permission levels for resources (datasets, credentials, etc.) | ---- | ---- | ----------- | -------- | | readme | string | | Yes | +#### PluginResourceRequirements + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| memory | integer | | Yes | +| permission | [Permission](#permission) | | No | + #### PluginTaskResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| task | | | Yes | +| task | [PluginInstallTask](#plugininstalltask) | | Yes | #### PluginTasksResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| tasks | | | Yes | +| tasks | [ [PluginInstallTask](#plugininstalltask) ] | | Yes | + +#### PluginVerification + +Verification of the plugin. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| authorized_category | [AuthorizedCategory](#authorizedcategory) | The authorized category of the plugin. | Yes | #### PluginVersionsResponse @@ -19978,6 +20248,16 @@ Shared permission levels for resources (datasets, credentials, etc.) | ---- | ---- | ----------- | -------- | | versions | object | | Yes | +#### Plugins + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| datasources | [ string ] | | No | +| endpoints | [ string ] | | No | +| models | [ string ] | | No | +| tools | [ string ] | | No | +| triggers | [ string ] | | No | + #### PreProcessingRule | Name | Type | Description | Required | @@ -19993,6 +20273,17 @@ Shared permission levels for resources (datasets, credentials, etc.) | content | string | | Yes | | summary | string | | No | +#### PriceConfig + +Model class for pricing info. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| currency | string | | Yes | +| input | string | | Yes | +| output | string | | No | +| unit | string | | Yes | + #### PriceConfigResponse Serialized pricing info with codegen-safe decimal string patterns. @@ -20049,12 +20340,6 @@ Model class for common provider settings like credentials | ---- | ---- | ----------- | -------- | | ProviderConfigType | string | | | -#### ProviderCredentialResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| credentials | object | | No | - #### ProviderCredentialSchema Model class for provider credential schema. @@ -20063,12 +20348,36 @@ Model class for provider credential schema. | ---- | ---- | ----------- | -------- | | credential_form_schemas | [ [CredentialFormSchema](#credentialformschema) ] | | Yes | -#### ProviderCredentialValidateResponse +#### ProviderCredentialsResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | -| error | string | | No | -| result | string,
**Available values:** "error", "success" | *Enum:* `"error"`, `"success"` | Yes | +| credentials | object | | No | + +#### ProviderEntity + +Runtime-native provider schema. + +`provider` is the canonical runtime identifier. `provider_name` is a +compatibility alias for callers that still resolve providers by short name and +is empty when no alias exists. + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| background | string | | No | +| configurate_methods | [ [ConfigurateMethod](#configuratemethod) ] | | Yes | +| description | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | No | +| help | [ProviderHelpEntity](#providerhelpentity) | | No | +| icon_small | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | No | +| icon_small_dark | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | No | +| label | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | Yes | +| model_credential_schema | [ModelCredentialSchema](#modelcredentialschema) | | No | +| models | [ [AIModelEntity](#aimodelentity) ] | | No | +| position | object | | No | +| provider | string | | Yes | +| provider_credential_schema | [ProviderCredentialSchema](#providercredentialschema) | | No | +| provider_name | string | | No | +| supported_model_types | [ [ModelType](#modeltype) ] | | Yes | #### ProviderEntityResponse @@ -20100,6 +20409,12 @@ Model class for provider help. | title | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | Yes | | url | [graphon__model_runtime__entities__common_entities__I18nObject](#graphon__model_runtime__entities__common_entities__i18nobject) | | Yes | +#### ProviderModelListResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| data | [ [ModelWithProviderEntityResponse](#modelwithproviderentityresponse) ] | | Yes | + #### ProviderModelWithStatusEntity Model class for model response. @@ -20157,12 +20472,6 @@ Model class for provider response. | ---- | ---- | ----------- | -------- | | ProviderType | string | | | -#### ProviderWithModelsDataResponse - -| Name | Type | Description | Required | -| ---- | ---- | ----------- | -------- | -| data | [ [ProviderWithModelsResponse](#providerwithmodelsresponse) ] | | Yes | - #### ProviderWithModelsResponse Model class for provider with models response. @@ -21204,6 +21513,13 @@ Query parameters for listing snippet published workflows. | paused | integer | | Yes | | success | integer | | Yes | +#### Storage + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | +| size | integer,
**Default:** 1048576 | | No | + #### StringListSource | Name | Type | Description | Required | @@ -21561,6 +21877,12 @@ Available voices | ---- | ---- | ----------- | -------- | | data | [ [TokensPerSecondStatisticItem](#tokenspersecondstatisticitem) ] | | Yes | +#### Tool + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| enabled | boolean | | No | + #### ToolApiEntity | Name | Type | Description | Required | @@ -21596,6 +21918,12 @@ Tool label | label | [I18nObject](#i18nobject) | The label of the tool | Yes | | name | string | The name of the tool | Yes | +#### ToolLabelEnum + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| ToolLabelEnum | string | | | + #### ToolLabelListResponse | Name | Type | Description | Required | @@ -21706,6 +22034,27 @@ removes TOOLS_SELECTOR from PluginParameterType | ---- | ---- | ----------- | -------- | | ToolProviderCredentialListResponse | array | | | +#### ToolProviderEntity + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| credentials_schema | [ [ProviderConfig](#providerconfig) ] | | No | +| identity | [ToolProviderIdentity](#toolprovideridentity) | | Yes | +| oauth_schema | [OAuthSchema](#oauthschema) | | No | +| plugin_id | string | | No | + +#### ToolProviderIdentity + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| author | string | The author of the tool | Yes | +| description | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The description of the tool | Yes | +| icon | string | The icon of the tool | Yes | +| icon_dark | string | The dark icon of the tool | No | +| label | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The label of the tool | Yes | +| name | string | The name of the tool | Yes | +| tags | [ [ToolLabelEnum](#toollabelenum) ] | The tags of the tool | No | + #### ToolProviderListQuery | Name | Type | Description | Required | @@ -22020,12 +22369,37 @@ Enum class for tool provider | supported_creation_methods | [ [TriggerCreationMethod](#triggercreationmethod) ] | Supported creation methods for the trigger provider. like 'OAUTH', 'APIKEY', 'MANUAL'. | No | | tags | [ string ] | The tags of the trigger provider | No | +#### TriggerProviderEntity + +The configuration of a trigger provider + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| events | [ [EventEntity](#evententity) ] | The events of the trigger provider | No | +| identity | [TriggerProviderIdentity](#triggerprovideridentity) | | Yes | +| subscription_constructor | [SubscriptionConstructor](#subscriptionconstructor) | The subscription constructor of the trigger provider | No | +| subscription_schema | [ [ProviderConfig](#providerconfig) ] | The configuration schema stored in the subscription entity | No | + #### TriggerProviderErrorResponse | Name | Type | Description | Required | | ---- | ---- | ----------- | -------- | | error | string | | Yes | +#### TriggerProviderIdentity + +The identity of the trigger provider + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| author | string | The author of the trigger provider | Yes | +| description | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The description of the trigger provider | Yes | +| icon | string | The icon of the trigger provider | No | +| icon_dark | string | The dark icon of the trigger provider | No | +| label | [core__tools__entities__common_entities__I18nObject](#core__tools__entities__common_entities__i18nobject) | The label of the trigger provider | Yes | +| name | string | The name of the trigger provider | Yes | +| tags | [ string ] | The tags of the trigger provider | No | + #### TriggerProviderListResponse | Name | Type | Description | Required | @@ -22194,6 +22568,13 @@ User action configuration. | ---- | ---- | ----------- | -------- | | data | [ [UserSatisfactionRateStatisticItem](#usersatisfactionratestatisticitem) ] | | Yes | +#### ValidationResultResponse + +| Name | Type | Description | Required | +| ---- | ---- | ----------- | -------- | +| error | string | | No | +| result | string,
**Available values:** "error", "success" | *Enum:* `"error"`, `"success"` | Yes | + #### ValueSourceType ValueSourceType records whether the value comes from a static setting diff --git a/api/tests/unit_tests/controllers/console/workspace/test_model_providers.py b/api/tests/unit_tests/controllers/console/workspace/test_model_providers.py index 21055390362..af37c20edaa 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_model_providers.py +++ b/api/tests/unit_tests/controllers/console/workspace/test_model_providers.py @@ -1,10 +1,14 @@ -from unittest.mock import MagicMock, patch +from inspect import unwrap +from types import SimpleNamespace +from typing import cast +from unittest.mock import ANY, patch import pytest from flask import Flask from pydantic_core import ValidationError from werkzeug.exceptions import Forbidden +from configs import dify_config from controllers.console.workspace.model_providers import ( ModelProviderCredentialApi, ModelProviderCredentialSwitchApi, @@ -14,30 +18,126 @@ from controllers.console.workspace.model_providers import ( ModelProviderValidateApi, PreferredProviderTypeUpdateApi, ) +from graphon.model_runtime.entities.common_entities import I18nObject +from graphon.model_runtime.entities.model_entities import ModelType +from graphon.model_runtime.entities.provider_entities import ConfigurateMethod from graphon.model_runtime.errors.validate import CredentialsValidateFailedError +from models import Account +from models.provider import ProviderType +from services.entities.model_provider_entities import ( + CustomConfigurationResponse, + CustomConfigurationStatus, + ProviderResponse, + SystemConfigurationResponse, +) VALID_UUID = "123e4567-e89b-12d3-a456-426614174000" INVALID_UUID = "123" -from inspect import unwrap +def make_account() -> Account: + return cast(Account, SimpleNamespace(id="account-1", email="owner@example.com")) + + +def make_provider_response() -> ProviderResponse: + return ProviderResponse( + tenant_id="tenant1", + provider="openai", + label=I18nObject(en_US="OpenAI", zh_Hans="OpenAI"), + description=I18nObject(en_US="OpenAI models", zh_Hans="OpenAI models zh"), + icon_small=I18nObject(en_US="icon.svg", zh_Hans="icon.svg"), + icon_small_dark=I18nObject(en_US="icon-dark.svg", zh_Hans="icon-dark.svg"), + background="#ffffff", + supported_model_types=[ModelType.LLM, ModelType.TEXT_EMBEDDING], + configurate_methods=[ConfigurateMethod.PREDEFINED_MODEL, ConfigurateMethod.CUSTOMIZABLE_MODEL], + preferred_provider_type=ProviderType.CUSTOM, + custom_configuration=CustomConfigurationResponse( + status=CustomConfigurationStatus.ACTIVE, + current_credential_id=VALID_UUID, + current_credential_name="production", + available_credentials=[], + custom_models=[], + can_added_models=[], + ), + system_configuration=SystemConfigurationResponse( + enabled=True, + current_quota_type=None, + quota_configurations=[], + ), + ) + + +def expected_provider_payload() -> dict[str, object]: + icon_url_prefix = f"{dify_config.CONSOLE_API_URL}/console/api/workspaces/tenant1/model-providers/openai" + return { + "tenant_id": "tenant1", + "provider": "openai", + "label": {"zh_Hans": "OpenAI", "en_US": "OpenAI"}, + "description": {"zh_Hans": "OpenAI models zh", "en_US": "OpenAI models"}, + "icon_small": { + "zh_Hans": f"{icon_url_prefix}/icon_small/zh_Hans", + "en_US": f"{icon_url_prefix}/icon_small/en_US", + }, + "icon_small_dark": { + "zh_Hans": f"{icon_url_prefix}/icon_small_dark/zh_Hans", + "en_US": f"{icon_url_prefix}/icon_small_dark/en_US", + }, + "background": "#ffffff", + "help": None, + "supported_model_types": ["llm", "text-embedding"], + "configurate_methods": ["predefined-model", "customizable-model"], + "provider_credential_schema": None, + "model_credential_schema": None, + "preferred_provider_type": "custom", + "custom_configuration": { + "status": "active", + "current_credential_id": VALID_UUID, + "current_credential_name": "production", + "available_credentials": [], + "custom_models": [], + "can_added_models": [], + }, + "system_configuration": { + "enabled": True, + "current_quota_type": None, + "quota_configurations": [], + }, + } class TestModelProviderListApi: def test_get_success(self, app: Flask): api = ModelProviderListApi() method = unwrap(api.get) + provider = make_provider_response() with ( app.test_request_context("/?model_type=llm"), patch( "controllers.console.workspace.model_providers.ModelProviderService.get_provider_list", - return_value=[{"name": "openai"}], - ), + return_value=[provider], + ) as get_provider_list, ): result = method(api, "tenant1") - assert "data" in result + get_provider_list.assert_called_once_with(tenant_id="tenant1", model_type=ModelType.LLM) + assert result == {"data": [expected_provider_payload()]} + + def test_get_without_model_type_passes_none(self, app: Flask): + api = ModelProviderListApi() + method = unwrap(api.get) + + with ( + app.test_request_context("/"), + patch( + "controllers.console.workspace.model_providers.ModelProviderService.get_provider_list", + return_value=[], + ) as get_provider_list, + ): + result = method(api, "tenant1") + + get_provider_list.assert_called_once_with(tenant_id="tenant1", model_type=None) + assert result == {"data": []} class TestModelProviderCredentialApi: @@ -49,12 +149,41 @@ class TestModelProviderCredentialApi: app.test_request_context(f"/?credential_id={VALID_UUID}"), patch( "controllers.console.workspace.model_providers.ModelProviderService.get_provider_credential", - return_value={"key": "value"}, - ), + return_value={ + "api_key": "sk-test", + "endpoint": "https://api.example.com", + "nested": {"region": "us-east-1"}, + }, + ) as get_provider_credential, ): result = method(api, "tenant1", provider="openai") - assert "credentials" in result + get_provider_credential.assert_called_once_with( + tenant_id="tenant1", provider="openai", credential_id=VALID_UUID + ) + assert result == { + "credentials": { + "api_key": "sk-test", + "endpoint": "https://api.example.com", + "nested": {"region": "us-east-1"}, + } + } + + def test_get_current_credential_without_id(self, app: Flask): + api = ModelProviderCredentialApi() + method = unwrap(api.get) + + with ( + app.test_request_context("/"), + patch( + "controllers.console.workspace.model_providers.ModelProviderService.get_provider_credential", + return_value=None, + ) as get_provider_credential, + ): + result = method(api, "tenant1", provider="openai") + + get_provider_credential.assert_called_once_with(tenant_id="tenant1", provider="openai", credential_id=None) + assert result == {"credentials": None} def test_get_invalid_uuid(self, app: Flask): api = ModelProviderCredentialApi() @@ -75,11 +204,17 @@ class TestModelProviderCredentialApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.create_provider_credential", return_value=None, - ), + ) as create_provider_credential, ): result, status = method(api, "tenant1", provider="openai") - assert result["result"] == "success" + create_provider_credential.assert_called_once_with( + tenant_id="tenant1", + provider="openai", + credentials={"a": "b"}, + credential_name="test", + ) + assert result == {"result": "success"} assert status == 201 def test_post_create_validation_error(self, app: Flask): @@ -109,11 +244,18 @@ class TestModelProviderCredentialApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.update_provider_credential", return_value=None, - ), + ) as update_provider_credential, ): result = method(api, "tenant1", provider="openai") - assert result["result"] == "success" + update_provider_credential.assert_called_once_with( + tenant_id="tenant1", + provider="openai", + credentials={"a": "b"}, + credential_id=VALID_UUID, + credential_name=None, + ) + assert result == {"result": "success"} def test_put_invalid_uuid(self, app: Flask): api = ModelProviderCredentialApi() @@ -136,10 +278,13 @@ class TestModelProviderCredentialApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.remove_provider_credential", return_value=None, - ), + ) as remove_provider_credential, ): result, status = method(api, "tenant1", provider="openai") + remove_provider_credential.assert_called_once_with( + tenant_id="tenant1", provider="openai", credential_id=VALID_UUID + ) assert status == 204 assert result == "" @@ -156,11 +301,16 @@ class TestModelProviderCredentialSwitchApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.switch_active_provider_credential", return_value=None, - ), + ) as switch_active_provider_credential, ): result = method(api, "tenant1", provider="openai") - assert result["result"] == "success" + switch_active_provider_credential.assert_called_once_with( + tenant_id="tenant1", + provider="openai", + credential_id=VALID_UUID, + ) + assert result == {"result": "success"} def test_switch_invalid_uuid(self, app: Flask): api = ModelProviderCredentialSwitchApi() @@ -185,11 +335,14 @@ class TestModelProviderValidateApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.validate_provider_credentials", return_value=None, - ), + ) as validate_provider_credentials, ): result = method(api, "tenant1", provider="openai") - assert result["result"] == "success" + validate_provider_credentials.assert_called_once_with( + tenant_id="tenant1", provider="openai", credentials={"a": "b"} + ) + assert result == {"result": "success", "error": None} def test_validate_failure(self, app: Flask): api = ModelProviderValidateApi() @@ -206,7 +359,7 @@ class TestModelProviderValidateApi: ): result = method(api, "tenant1", provider="openai") - assert result["result"] == "error" + assert result == {"result": "error", "error": "bad"} class TestModelProviderIconApi: @@ -218,11 +371,14 @@ class TestModelProviderIconApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.get_model_provider_icon", return_value=(b"123", "image/png"), - ), + ) as get_model_provider_icon, ): response = api.get("t1", "openai", "logo", "en") + get_model_provider_icon.assert_called_once_with(tenant_id="t1", provider="openai", icon_type="logo", lang="en") assert response.mimetype == "image/png" + response.direct_passthrough = False + assert response.get_data() == b"123" def test_icon_not_found(self, app: Flask): api = ModelProviderIconApi() @@ -250,11 +406,14 @@ class TestPreferredProviderTypeUpdateApi: patch( "controllers.console.workspace.model_providers.ModelProviderService.switch_preferred_provider", return_value=None, - ), + ) as switch_preferred_provider, ): result = method(api, "tenant1", provider="openai") - assert result["result"] == "success" + switch_preferred_provider.assert_called_once_with( + tenant_id="tenant1", provider="openai", preferred_provider_type="custom" + ) + assert result == {"result": "success"} def test_invalid_enum(self, app: Flask): api = PreferredProviderTypeUpdateApi() @@ -272,22 +431,29 @@ class TestModelProviderPaymentCheckoutUrlApi: api = ModelProviderPaymentCheckoutUrlApi() method = unwrap(api.get) - user = MagicMock(id="u1", email="x@test.com") + user = make_account() with ( app.test_request_context("/"), patch( "controllers.console.workspace.model_providers.BillingService.is_tenant_owner_or_admin", return_value=None, - ), + ) as is_tenant_owner_or_admin, patch( "controllers.console.workspace.model_providers.BillingService.get_model_provider_payment_link", - return_value={"url": "x"}, - ), + return_value={"payment_link": "https://payment.example.com/provider"}, + ) as get_model_provider_payment_link, ): result = method(api, "tenant1", user, provider="anthropic") - assert "url" in result + is_tenant_owner_or_admin.assert_called_once_with(user, session=ANY) + get_model_provider_payment_link.assert_called_once_with( + provider_name="anthropic", + tenant_id="tenant1", + account_id="account-1", + prefilled_email="owner@example.com", + ) + assert result == {"payment_link": "https://payment.example.com/provider"} def test_invalid_provider(self, app: Flask): api = ModelProviderPaymentCheckoutUrlApi() @@ -295,13 +461,13 @@ class TestModelProviderPaymentCheckoutUrlApi: with app.test_request_context("/"): with pytest.raises(ValueError): - method(api, "tenant1", MagicMock(), provider="openai") + method(api, "tenant1", make_account(), provider="openai") def test_permission_denied(self, app: Flask): api = ModelProviderPaymentCheckoutUrlApi() method = unwrap(api.get) - user = MagicMock(id="u1", email="x@test.com") + user = make_account() with ( app.test_request_context("/"), diff --git a/api/tests/unit_tests/controllers/console/workspace/test_models.py b/api/tests/unit_tests/controllers/console/workspace/test_models.py index 3374c49caff..424c1ef1d75 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_models.py +++ b/api/tests/unit_tests/controllers/console/workspace/test_models.py @@ -32,7 +32,16 @@ class TestDefaultModelApi: ), patch("controllers.console.workspace.models.ModelProviderService") as service_mock, ): - service_mock.return_value.get_default_model_of_model_type.return_value = {"model": "gpt-4"} + service_mock.return_value.get_default_model_of_model_type.return_value = { + "model": "gpt-4", + "model_type": ModelType.LLM, + "provider": { + "tenant_id": "tenant1", + "provider": "openai", + "label": {"en_US": "OpenAI", "zh_Hans": "OpenAI"}, + "supported_model_types": [ModelType.LLM], + }, + } result = method(api, "tenant1") diff --git a/api/tests/unit_tests/controllers/console/workspace/test_plugin.py b/api/tests/unit_tests/controllers/console/workspace/test_plugin.py index bbe94fce635..889b4cb6c1a 100644 --- a/api/tests/unit_tests/controllers/console/workspace/test_plugin.py +++ b/api/tests/unit_tests/controllers/console/workspace/test_plugin.py @@ -42,8 +42,11 @@ from controllers.console.workspace.plugin import ( PluginUploadFromGithubApi, PluginUploadFromPkgApi, ) -from core.plugin.entities.plugin import PluginInstallation +from core.plugin.entities.parameters import PluginParameterOption +from core.plugin.entities.plugin import PluginDeclaration, PluginEntity, PluginInstallation +from core.plugin.entities.plugin_daemon import PluginInstallTask from core.plugin.impl.exc import PluginDaemonClientSideError +from core.plugin.plugin_service import PluginService from models.account import ( Account, TenantAccountRole, @@ -118,6 +121,215 @@ def _builtin_tool_provider_item() -> dict[str, Any]: } +def _plugin_declaration_payload() -> dict[str, Any]: + return { + "version": "1.2.3", + "author": "langgenius", + "name": "demo_plugin", + "description": {"en_US": "Demo plugin"}, + "icon": "icon.svg", + "icon_dark": None, + "label": {"en_US": "Demo Plugin"}, + "created_at": "2024-01-02T03:04:05", + "resource": {"memory": 268435456, "permission": None}, + "plugins": {"tools": ["provider/demo.yaml"]}, + "tags": ["search", "demo"], + "repo": "https://github.com/langgenius/demo", + "verified": True, + "meta": {"minimum_dify_version": "0.15.0", "version": "1.2.3"}, + } + + +def _expected_i18n(en_us: str) -> dict[str, str]: + return {"en_US": en_us, "zh_Hans": en_us, "pt_BR": en_us, "ja_JP": en_us} + + +def _expected_plugin_declaration_dump() -> dict[str, Any]: + return { + "version": "1.2.3", + "author": "langgenius", + "name": "demo_plugin", + "description": _expected_i18n("Demo plugin"), + "icon": "icon.svg", + "icon_dark": None, + "label": _expected_i18n("Demo Plugin"), + "category": "extension", + "created_at": "2024-01-02T03:04:05", + "resource": {"memory": 268435456, "permission": None}, + "plugins": { + "tools": ["provider/demo.yaml"], + "models": [], + "endpoints": [], + "datasources": [], + "triggers": [], + }, + "tags": ["search", "demo"], + "repo": "https://github.com/langgenius/demo", + "verified": True, + "tool": None, + "model": None, + "endpoint": None, + "agent_strategy": None, + "datasource": None, + "trigger": None, + "meta": {"minimum_dify_version": "0.15.0", "version": "1.2.3"}, + } + + +def _plugin_installation_payload() -> dict[str, Any]: + return { + "id": "installation-row-1", + "created_at": "2024-01-02T03:04:05", + "updated_at": "2024-01-03T04:05:06", + "tenant_id": "tenant-1", + "endpoints_setups": 2, + "endpoints_active": 1, + "runtime_type": "remote", + "source": "marketplace", + "meta": {"from": "marketplace"}, + "plugin_id": "langgenius/demo_plugin", + "plugin_unique_identifier": "langgenius/demo_plugin:1.2.3@sha256:abc", + "version": "1.2.3", + "checksum": "sha256:abc", + "declaration": _plugin_declaration_payload(), + } + + +def _plugin_entity_payload() -> dict[str, Any]: + return { + **_plugin_installation_payload(), + "name": "demo_plugin", + "installation_id": "installation-row-1", + } + + +def _plugin_declaration() -> PluginDeclaration: + return PluginDeclaration.model_validate(_plugin_declaration_payload()) + + +def _plugin_installation() -> PluginInstallation: + return PluginInstallation.model_validate(_plugin_installation_payload()) + + +def _plugin_entity() -> PluginEntity: + return PluginEntity.model_validate(_plugin_entity_payload()) + + +def _expected_plugin_installation_dump() -> dict[str, Any]: + return { + "id": "installation-row-1", + "created_at": "2024-01-02T03:04:05", + "updated_at": "2024-01-03T04:05:06", + "tenant_id": "tenant-1", + "endpoints_setups": 2, + "endpoints_active": 1, + "runtime_type": "remote", + "source": "marketplace", + "meta": {"from": "marketplace"}, + "plugin_id": "langgenius/demo_plugin", + "plugin_unique_identifier": "langgenius/demo_plugin:1.2.3@sha256:abc", + "version": "1.2.3", + "checksum": "sha256:abc", + "declaration": _expected_plugin_declaration_dump(), + } + + +def _expected_plugin_entity_dump() -> dict[str, Any]: + return { + **_expected_plugin_installation_dump(), + "name": "demo_plugin", + "installation_id": "installation-row-1", + } + + +def _plugin_task_payload() -> dict[str, Any]: + return { + "id": "task-1", + "created_at": "2024-02-03T04:05:06", + "updated_at": "2024-02-03T04:06:07", + "status": "running", + "total_plugins": 2, + "completed_plugins": 1, + "plugins": [ + { + "plugin_unique_identifier": "langgenius/demo_plugin:1.2.3@sha256:abc", + "plugin_id": "langgenius/demo_plugin", + "status": "success", + "message": "installed", + "icon": "icon.svg", + "labels": {"en_US": "Demo Plugin"}, + "source": "marketplace", + } + ], + } + + +def _plugin_task() -> PluginInstallTask: + return PluginInstallTask.model_validate(_plugin_task_payload()) + + +def _expected_plugin_task_dump() -> dict[str, Any]: + return { + "id": "task-1", + "created_at": "2024-02-03T04:05:06", + "updated_at": "2024-02-03T04:06:07", + "status": "running", + "total_plugins": 2, + "completed_plugins": 1, + "plugins": [ + { + "plugin_unique_identifier": "langgenius/demo_plugin:1.2.3@sha256:abc", + "plugin_id": "langgenius/demo_plugin", + "status": "success", + "message": "installed", + "icon": "icon.svg", + "labels": _expected_i18n("Demo Plugin"), + "source": "marketplace", + } + ], + } + + +def _latest_plugin_cache() -> PluginService.LatestPluginCache: + return PluginService.LatestPluginCache( + plugin_id="langgenius/demo_plugin", + version="1.3.0", + unique_identifier="langgenius/demo_plugin:1.3.0@sha256:def", + status="active", + deprecated_reason="", + alternative_plugin_id="", + ) + + +def _expected_latest_plugin_cache_dump() -> dict[str, str]: + return { + "plugin_id": "langgenius/demo_plugin", + "version": "1.3.0", + "unique_identifier": "langgenius/demo_plugin:1.3.0@sha256:def", + "status": "active", + "deprecated_reason": "", + "alternative_plugin_id": "", + } + + +def _dynamic_option() -> PluginParameterOption: + return PluginParameterOption.model_validate( + { + "value": 101, + "label": {"en_US": "Dataset 101"}, + "icon": None, + } + ) + + +def _expected_dynamic_option_dump() -> dict[str, Any]: + return { + "value": "101", + "label": _expected_i18n("Dataset 101"), + "icon": None, + } + + def _account(role: TenantAccountRole = TenantAccountRole.OWNER) -> Account: account = Account(name="Test User", email="u1@example.com") account.id = "u1" @@ -140,17 +352,24 @@ class TestPluginListLatestVersionsApi: api = PluginListLatestVersionsApi() method = unwrap(api.post) - payload = {"plugin_ids": ["p1"]} + payload = {"plugin_ids": ["langgenius/demo_plugin", "langgenius/missing_plugin"]} + versions = { + "langgenius/demo_plugin": _latest_plugin_cache(), + "langgenius/missing_plugin": None, + } with ( app.test_request_context("/", json=payload), - patch( - "controllers.console.workspace.plugin.PluginService.list_latest_versions", return_value={"p1": "1.0"} - ), + patch("controllers.console.workspace.plugin.PluginService.list_latest_versions", return_value=versions), ): result = method(api) - assert "versions" in result + assert result == { + "versions": { + "langgenius/demo_plugin": _expected_latest_plugin_cache_dump(), + "langgenius/missing_plugin": None, + } + } def test_daemon_error(self, app: Flask): api = PluginListLatestVersionsApi() @@ -202,18 +421,18 @@ class TestPluginListApi: api = PluginListApi() method = unwrap(api.get) - mock_list = MagicMock(list=[{"id": 1}], total=1) + plugins_with_total = MagicMock(list=[_plugin_entity()], total=1) with ( app.test_request_context("/?page=1&page_size=10"), patch( "controllers.console.workspace.plugin.PluginService.list_with_total", - return_value=mock_list, + return_value=plugins_with_total, ) as mock_list_with_total, ): result = method(api, "t1", "u1") - assert result["total"] == 1 + assert result == {"plugins": [_expected_plugin_entity_dump()], "total": 1} mock_list_with_total.assert_called_once_with("t1", "u1", 1, 10) @@ -454,12 +673,12 @@ class TestPluginFetchDynamicSelectOptionsApi: app.test_request_context("/?plugin_id=p&provider=x&action=y¶meter=z&provider_type=tool"), patch( "controllers.console.workspace.plugin.PluginParameterService.get_dynamic_select_options", - return_value=[1, 2], + return_value=[_dynamic_option()], ), ): result = method(api, "t1", user) - assert result["options"] == [1, 2] + assert result == {"options": [_expected_dynamic_option_dump()]} class TestPluginReadmeApi: @@ -481,29 +700,18 @@ class TestPluginListInstallationsFromIdsApi: api = PluginListInstallationsFromIdsApi() method = unwrap(api.post) - payload = {"plugin_ids": ["p1", "p2"]} + payload = {"plugin_ids": ["langgenius/demo_plugin"]} with ( app.test_request_context("/", json=payload), patch( "controllers.console.workspace.plugin.PluginService.list_installations_from_ids", - return_value=[PluginInstallation.model_validate(_plugin_category_list_item())], + return_value=[_plugin_installation()], ), ): result = method(api, "t1") - assert result["plugins"][0]["id"] == "entity-1" - assert result["plugins"][0]["plugin_id"] == "test-author/test-plugin" - assert result["plugins"][0]["plugin_unique_identifier"] == "test-author/test-plugin:1.0.0@checksum" - assert result["plugins"][0]["version"] == "1.0.0" - assert result["plugins"][0]["declaration"]["name"] == "test-plugin" - assert "name" not in result["plugins"][0] - assert "installation_id" not in result["plugins"][0] - assert "latest_version" not in result["plugins"][0] - assert "latest_unique_identifier" not in result["plugins"][0] - assert "status" not in result["plugins"][0] - assert "deprecated_reason" not in result["plugins"][0] - assert "alternative_plugin_id" not in result["plugins"][0] + assert result == {"plugins": [_expected_plugin_installation_dump()]} def test_daemon_error(self, app: Flask): api = PluginListInstallationsFromIdsApi() @@ -689,11 +897,14 @@ class TestPluginFetchMarketplacePkgApi: with ( app.test_request_context("/?plugin_unique_identifier=p"), - patch("controllers.console.workspace.plugin.PluginService.fetch_marketplace_pkg", return_value={"m": 1}), + patch( + "controllers.console.workspace.plugin.PluginService.fetch_marketplace_pkg", + return_value=_plugin_declaration(), + ), ): result = method(api, "t1") - assert "manifest" in result + assert result == {"manifest": _expected_plugin_declaration_dump()} def test_daemon_error(self, app: Flask): api = PluginFetchMarketplacePkgApi() @@ -715,8 +926,7 @@ class TestPluginFetchManifestApi: api = PluginFetchManifestApi() method = unwrap(api.get) - manifest = MagicMock() - manifest.model_dump.return_value = {"x": 1} + manifest = _plugin_declaration() with ( app.test_request_context("/?plugin_unique_identifier=p"), @@ -724,7 +934,7 @@ class TestPluginFetchManifestApi: ): result = method(api, "t1") - assert "manifest" in result + assert result == {"manifest": _expected_plugin_declaration_dump()} def test_daemon_error(self, app: Flask): api = PluginFetchManifestApi() @@ -748,11 +958,14 @@ class TestPluginFetchInstallTasksApi: with ( app.test_request_context("/?page=1&page_size=10"), - patch("controllers.console.workspace.plugin.PluginService.fetch_install_tasks", return_value=[{"id": 1}]), + patch( + "controllers.console.workspace.plugin.PluginService.fetch_install_tasks", + return_value=[_plugin_task()], + ), ): result = method(api, "t1") - assert "tasks" in result + assert result == {"tasks": [_expected_plugin_task_dump()]} def test_daemon_error(self, app: Flask): api = PluginFetchInstallTasksApi() @@ -776,11 +989,11 @@ class TestPluginFetchInstallTaskApi: with ( app.test_request_context("/"), - patch("controllers.console.workspace.plugin.PluginService.fetch_install_task", return_value={"id": "x"}), + patch("controllers.console.workspace.plugin.PluginService.fetch_install_task", return_value=_plugin_task()), ): result = method(api, "t1", "x") - assert "task" in result + assert result == {"task": _expected_plugin_task_dump()} def test_daemon_error(self, app: Flask): api = PluginFetchInstallTaskApi() @@ -989,12 +1202,12 @@ class TestPluginFetchDynamicSelectOptionsWithCredentialsApi: app.test_request_context("/", json=payload), patch( "controllers.console.workspace.plugin.PluginParameterService.get_dynamic_select_options_with_credentials", - return_value=[1], + return_value=[_dynamic_option()], ), ): result = method(api, "t1", user) - assert result["options"] == [1] + assert result == {"options": [_expected_dynamic_option_dump()]} def test_daemon_error(self, app: Flask, user): api = PluginFetchDynamicSelectOptionsWithCredentialsApi() diff --git a/e2e/features/agent-v2/support/seed.ts b/e2e/features/agent-v2/support/seed.ts index 716be7ec336..0ef68c9f5ac 100644 --- a/e2e/features/agent-v2/support/seed.ts +++ b/e2e/features/agent-v2/support/seed.ts @@ -7,8 +7,8 @@ import type { KnowledgeConfig, } from '@dify/contracts/api/console/datasets/types.gen' import type { + AvailableModelListResponse, ModelProviderListResponse, - ProviderWithModelsDataResponse, } from '@dify/contracts/api/console/workspaces/types.gen' import type { SeedContext, SeedResource, SeedTask } from '../../../support/seed' import type { UploadedConsoleFile } from './agent-drive' @@ -139,7 +139,7 @@ const findChatModel = async (config: StableModel, title: string) => { try { const response = await ctx.get(`/console/api/workspaces/current/models/model-types/${config.type}`) await expectApiResponseOK(response, `Check ${title}`) - const body = (await response.json()) as ProviderWithModelsDataResponse + const body = (await response.json()) as AvailableModelListResponse const provider = body.data.find(item => matchesProvider(item.provider, config.provider)) const model = provider?.models.find( item => diff --git a/packages/contracts/generated/api/console/workspaces/types.gen.ts b/packages/contracts/generated/api/console/workspaces/types.gen.ts index addd1fa452e..540c2993105 100644 --- a/packages/contracts/generated/api/console/workspaces/types.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/types.gen.ts @@ -217,7 +217,7 @@ export type ParserCredentialDelete = { credential_id: string } -export type ProviderCredentialResponse = { +export type ProviderCredentialsResponse = { credentials?: { [key: string]: unknown } | null @@ -248,7 +248,7 @@ export type ParserCredentialValidate = { } } -export type ProviderCredentialValidateResponse = { +export type ValidationResultResponse = { error?: string | null result: 'error' | 'success' } @@ -258,7 +258,7 @@ export type ParserDeleteModels = { model_type: ModelType } -export type ModelWithProviderListResponse = { +export type ProviderModelListResponse = { data: Array } @@ -278,12 +278,12 @@ export type ParserDeleteCredential = { export type ModelCredentialResponse = { available_credentials: Array - credentials?: { + credentials: { [key: string]: unknown } current_credential_id?: string | null current_credential_name?: string | null - load_balancing: ModelCredentialLoadBalancingResponse + load_balancing: ModelLoadBalancingResponse } export type ParserCreateCredential = { @@ -319,11 +319,6 @@ export type ParserValidate = { model_type: ModelType } -export type ModelCredentialValidateResponse = { - error?: string | null - result: string -} - export type LoadBalancingCredentialPayload = { credentials: { [key: string]: unknown @@ -337,7 +332,7 @@ export type LoadBalancingCredentialValidateResponse = { result: string } -export type ModelParameterRulesResponse = { +export type ModelParameterRuleListResponse = { data: Array } @@ -345,7 +340,7 @@ export type ParserPreferredProviderType = { preferred_provider_type: 'custom' | 'system' } -export type ProviderWithModelsDataResponse = { +export type AvailableModelListResponse = { data: Array } @@ -384,7 +379,7 @@ export type PluginDebuggingKeyResponse = { } export type PluginManifestResponse = { - manifest: unknown + manifest: PluginDeclaration } export type ParserGithubInstall = { @@ -394,14 +389,18 @@ export type ParserGithubInstall = { version: string } -export type PluginDaemonOperationResponse = unknown +export type PluginInstallTaskStartResponse = { + all_installed: boolean + task?: PluginInstallTask | null + task_id: string +} export type ParserPluginIdentifiers = { plugin_unique_identifiers: Array } export type PluginListResponse = { - plugins: unknown + plugins: Array total: number } @@ -420,7 +419,7 @@ export type PluginVersionsResponse = { } export type PluginDynamicOptionsResponse = { - options: unknown + options: Array } export type ParserDynamicOptionsWithCredentials = { @@ -449,11 +448,11 @@ export type PluginReadmeResponse = { } export type PluginTasksResponse = { - tasks: unknown + tasks: Array } export type PluginTaskResponse = { - task: unknown + task: PluginInstallTask } export type ParserUninstall = { @@ -473,12 +472,20 @@ export type ParserMarketplaceUpgrade = { original_plugin_unique_identifier: string } +export type PluginBundleUploadResponse = Array + export type ParserGithubUpload = { package: string repo: string version: string } +export type PluginDecodeResponse = { + manifest: PluginDeclaration + unique_identifier: string + verification?: PluginVerification | null +} + export type PluginCategoryListResponse = { builtin_tools: Array has_more: boolean @@ -1175,10 +1182,8 @@ export type CredentialConfiguration = { credential_name: string } -export type ModelCredentialLoadBalancingResponse = { - configs?: Array<{ - [key: string]: unknown - }> +export type ModelLoadBalancingResponse = { + configs: Array enabled: boolean } @@ -1230,6 +1235,61 @@ export type PluginAutoUpgradeSettingsResponseModel = { upgrade_time_of_day: number } +export type PluginDeclaration = { + agent_strategy?: AgentStrategyProviderEntity | null + author: string | null + category: PluginCategory + created_at: string + datasource?: DatasourceProviderEntity | null + description: CoreToolsEntitiesCommonEntitiesI18nObject + endpoint?: EndpointProviderDeclaration | null + icon: string + icon_dark?: string | null + label: CoreToolsEntitiesCommonEntitiesI18nObject + meta: Meta + model?: ProviderEntity | null + name: string + plugins: Plugins + repo?: string | null + resource: PluginResourceRequirements + tags?: Array + tool?: ToolProviderEntity | null + trigger?: TriggerProviderEntity | null + verified?: boolean + version: string +} + +export type PluginInstallTask = { + completed_plugins: number + created_at: string + id: string + plugins: Array + status: PluginInstallTaskStatus + total_plugins: number + updated_at: string +} + +export type PluginEntity = { + checksum: string + created_at: string + declaration: PluginDeclaration + endpoints_active: number + endpoints_setups: number + id: string + installation_id: string + meta: { + [key: string]: unknown + } + name: string + plugin_id: string + plugin_unique_identifier: string + runtime_type: string + source: PluginInstallationSource + tenant_id: string + updated_at: string + version: string +} + export type PluginInstallationItemResponse = { checksum: string created_at: string @@ -1258,10 +1318,25 @@ export type LatestPluginCache = { version: string } +export type PluginParameterOption = { + icon?: string | null + label: I18nObject + value: string +} + export type TenantPluginDebugPermission = 'admins' | 'everyone' | 'noone' export type TenantPluginInstallPermission = 'admins' | 'everyone' | 'noone' +export type PluginBundleDependency = { + type: PluginBundleDependencyType + value: Github | Marketplace | Package +} + +export type PluginVerification = { + authorized_category: AuthorizedCategory +} + export type PluginCategoryBuiltinToolProviderResponse = { allow_delete: boolean author: string @@ -1650,6 +1725,18 @@ export type ModelStatus | 'no-permission' | 'quota-exceeded' +export type ModelLoadBalancingConfigResponse = { + credential_id?: string | null + credentials: { + [key: string]: unknown + } + enabled: boolean + id: string + in_cooldown: boolean + name: string + ttl: number +} + export type GraphonModelRuntimeEntitiesCommonEntitiesI18nObject = { en_US: string zh_Hans?: string | null @@ -1678,6 +1765,103 @@ export type TenantPluginAutoUpgradeStrategySetting = 'disabled' | 'fix_only' | ' export type TenantPluginAutoUpgradeMode = 'all' | 'exclude' | 'partial' +export type AgentStrategyProviderEntity = { + identity: AgentStrategyProviderIdentity + plugin_id?: string | null +} + +export type PluginCategory + = | 'agent-strategy' + | 'datasource' + | 'extension' + | 'model' + | 'tool' + | 'trigger' + +export type DatasourceProviderEntity = { + credentials_schema?: Array + identity: DatasourceProviderIdentity + oauth_schema?: OAuthSchema | null + provider_type: DatasourceProviderType +} + +export type CoreToolsEntitiesCommonEntitiesI18nObject = { + en_US: string + ja_JP?: string | null + pt_BR?: string | null + zh_Hans?: string | null +} + +export type EndpointProviderDeclaration = { + endpoints?: Array | null + settings?: Array +} + +export type Meta = { + minimum_dify_version?: string | null + version?: string | null +} + +export type ProviderEntity = { + background?: string | null + configurate_methods: Array + description?: GraphonModelRuntimeEntitiesCommonEntitiesI18nObject | null + help?: ProviderHelpEntity | null + icon_small?: GraphonModelRuntimeEntitiesCommonEntitiesI18nObject | null + icon_small_dark?: GraphonModelRuntimeEntitiesCommonEntitiesI18nObject | null + label: GraphonModelRuntimeEntitiesCommonEntitiesI18nObject + model_credential_schema?: ModelCredentialSchema | null + models?: Array + position?: { + [key: string]: Array + } | null + provider: string + provider_credential_schema?: ProviderCredentialSchema | null + provider_name?: string + supported_model_types: Array +} + +export type Plugins = { + datasources?: Array | null + endpoints?: Array | null + models?: Array | null + tools?: Array | null + triggers?: Array | null +} + +export type PluginResourceRequirements = { + memory: number + permission?: Permission | null +} + +export type ToolProviderEntity = { + credentials_schema?: Array + identity: ToolProviderIdentity + oauth_schema?: OAuthSchema | null + plugin_id?: string | null +} + +export type TriggerProviderEntity = { + events?: Array + identity: TriggerProviderIdentity + subscription_constructor?: SubscriptionConstructor | null + subscription_schema?: Array +} + +export type PluginInstallTaskPluginStatus = { + icon: string + labels: I18nObject + message: string + plugin_id: string + plugin_unique_identifier: string + source?: string | null + status: PluginInstallTaskStatus +} + +export type PluginInstallTaskStatus = 'failed' | 'pending' | 'running' | 'success' + +export type PluginInstallationSource = 'github' | 'marketplace' | 'package' | 'remote' + export type PluginDeclarationResponse = { agent_strategy?: { [key: string]: unknown @@ -1718,14 +1902,9 @@ export type PluginDeclarationResponse = { version: string } -export type PluginInstallationSource = 'github' | 'marketplace' | 'package' | 'remote' +export type PluginBundleDependencyType = 'github' | 'marketplace' | 'package' -export type CoreToolsEntitiesCommonEntitiesI18nObject = { - en_US: string - ja_JP?: string | null - pt_BR?: string | null - zh_Hans?: string | null -} +export type AuthorizedCategory = 'community' | 'langgenius' | 'partner' export type PluginCategoryBuiltinToolResponse = { author: string @@ -1928,13 +2107,87 @@ export type QuotaConfiguration = { restrict_models?: Array } -export type PluginCategory - = | 'agent-strategy' - | 'datasource' - | 'extension' - | 'model' - | 'tool' - | 'trigger' +export type AgentStrategyProviderIdentity = { + author: string + description: CoreToolsEntitiesCommonEntitiesI18nObject + icon: string + icon_dark?: string | null + label: CoreToolsEntitiesCommonEntitiesI18nObject + name: string + tags?: Array | null +} + +export type DatasourceProviderIdentity = { + author: string + description: CoreToolsEntitiesCommonEntitiesI18nObject + icon: string + label: CoreToolsEntitiesCommonEntitiesI18nObject + name: string + tags?: Array | null +} + +export type DatasourceProviderType + = | 'local_file' + | 'online_document' + | 'online_drive' + | 'website_crawl' + +export type EndpointDeclaration = { + hidden?: boolean + method: string + path: string +} + +export type AiModelEntity = { + deprecated?: boolean + features?: Array | null + fetch_from: FetchFrom + label: GraphonModelRuntimeEntitiesCommonEntitiesI18nObject + model: string + model_properties: { + [key in ModelPropertyKey]?: unknown + } + model_type: ModelType + parameter_rules?: Array + pricing?: PriceConfig | null +} + +export type Permission = { + endpoint?: Endpoint | null + model?: Model | null + node?: Node | null + storage?: Storage | null + tool?: Tool | null +} + +export type ToolProviderIdentity = { + author: string + description: CoreToolsEntitiesCommonEntitiesI18nObject + icon: string + icon_dark?: string | null + label: CoreToolsEntitiesCommonEntitiesI18nObject + name: string + tags?: Array | null +} + +export type EventEntity = { + description: CoreToolsEntitiesCommonEntitiesI18nObject + identity: EventIdentity + output_schema?: { + [key: string]: unknown + } | null + parameters?: Array +} + +export type TriggerProviderIdentity = { + author: string + description: CoreToolsEntitiesCommonEntitiesI18nObject + icon?: string | null + icon_dark?: string | null + label: CoreToolsEntitiesCommonEntitiesI18nObject + name: string + tags?: Array +} export type ProviderEntityResponse = { background?: string | null @@ -1959,12 +2212,6 @@ export type PluginParameterAutoGenerate = { type: PluginParameterAutoGenerateType } -export type PluginParameterOption = { - icon?: string | null - label: I18nObject - value: string -} - export type PluginParameterTemplate = { enabled?: boolean } @@ -2055,6 +2302,59 @@ export type RestrictModel = { model_type: ModelType } +export type ToolLabelEnum + = | 'business' + | 'design' + | 'education' + | 'entertainment' + | 'finance' + | 'image' + | 'medical' + | 'news' + | 'other' + | 'productivity' + | 'rag' + | 'search' + | 'social' + | 'travel' + | 'utilities' + | 'videos' + | 'weather' + +export type PriceConfig = { + currency: string + input: string + output?: string | null + unit: string +} + +export type Endpoint = { + enabled?: boolean | null +} + +export type Model = { + enabled?: boolean | null + llm?: boolean | null + moderation?: boolean | null + rerank?: boolean | null + speech2text?: boolean | null + text_embedding?: boolean | null + tts?: boolean | null +} + +export type Node = { + enabled?: boolean | null +} + +export type Storage = { + enabled?: boolean | null + size?: number +} + +export type Tool = { + enabled?: boolean | null +} + export type PluginParameterAutoGenerateType = 'prompt_instruction' export type AccountWithRoleListResponseWritable = { @@ -2725,7 +3025,7 @@ export type GetWorkspacesCurrentModelProvidersByProviderCredentialsData = { } export type GetWorkspacesCurrentModelProvidersByProviderCredentialsResponses = { - 200: ProviderCredentialResponse + 200: ProviderCredentialsResponse } export type GetWorkspacesCurrentModelProvidersByProviderCredentialsResponse @@ -2789,7 +3089,7 @@ export type PostWorkspacesCurrentModelProvidersByProviderCredentialsValidateData } export type PostWorkspacesCurrentModelProvidersByProviderCredentialsValidateResponses = { - 200: ProviderCredentialValidateResponse + 200: ValidationResultResponse } export type PostWorkspacesCurrentModelProvidersByProviderCredentialsValidateResponse @@ -2821,7 +3121,7 @@ export type GetWorkspacesCurrentModelProvidersByProviderModelsData = { } export type GetWorkspacesCurrentModelProvidersByProviderModelsResponses = { - 200: ModelWithProviderListResponse + 200: ProviderModelListResponse } export type GetWorkspacesCurrentModelProvidersByProviderModelsResponse @@ -2938,7 +3238,7 @@ export type PostWorkspacesCurrentModelProvidersByProviderModelsCredentialsValida } export type PostWorkspacesCurrentModelProvidersByProviderModelsCredentialsValidateResponses = { - 200: ModelCredentialValidateResponse + 200: ValidationResultResponse } export type PostWorkspacesCurrentModelProvidersByProviderModelsCredentialsValidateResponse @@ -3025,7 +3325,7 @@ export type GetWorkspacesCurrentModelProvidersByProviderModelsParameterRulesData } export type GetWorkspacesCurrentModelProvidersByProviderModelsParameterRulesResponses = { - 200: ModelParameterRulesResponse + 200: ModelParameterRuleListResponse } export type GetWorkspacesCurrentModelProvidersByProviderModelsParameterRulesResponse @@ -3057,7 +3357,7 @@ export type GetWorkspacesCurrentModelsModelTypesByModelTypeData = { } export type GetWorkspacesCurrentModelsModelTypesByModelTypeResponses = { - 200: ProviderWithModelsDataResponse + 200: AvailableModelListResponse } export type GetWorkspacesCurrentModelsModelTypesByModelTypeResponse @@ -3193,7 +3493,7 @@ export type PostWorkspacesCurrentPluginInstallGithubData = { } export type PostWorkspacesCurrentPluginInstallGithubResponses = { - 200: PluginDaemonOperationResponse + 200: PluginInstallTaskStartResponse } export type PostWorkspacesCurrentPluginInstallGithubResponse @@ -3207,7 +3507,7 @@ export type PostWorkspacesCurrentPluginInstallMarketplaceData = { } export type PostWorkspacesCurrentPluginInstallMarketplaceResponses = { - 200: PluginDaemonOperationResponse + 200: PluginInstallTaskStartResponse } export type PostWorkspacesCurrentPluginInstallMarketplaceResponse @@ -3221,7 +3521,7 @@ export type PostWorkspacesCurrentPluginInstallPkgData = { } export type PostWorkspacesCurrentPluginInstallPkgResponses = { - 200: PluginDaemonOperationResponse + 200: PluginInstallTaskStartResponse } export type PostWorkspacesCurrentPluginInstallPkgResponse @@ -3470,7 +3770,7 @@ export type PostWorkspacesCurrentPluginUpgradeGithubData = { } export type PostWorkspacesCurrentPluginUpgradeGithubResponses = { - 200: PluginDaemonOperationResponse + 200: PluginInstallTaskStartResponse } export type PostWorkspacesCurrentPluginUpgradeGithubResponse @@ -3484,7 +3784,7 @@ export type PostWorkspacesCurrentPluginUpgradeMarketplaceData = { } export type PostWorkspacesCurrentPluginUpgradeMarketplaceResponses = { - 200: PluginDaemonOperationResponse + 200: PluginInstallTaskStartResponse } export type PostWorkspacesCurrentPluginUpgradeMarketplaceResponse @@ -3498,7 +3798,7 @@ export type PostWorkspacesCurrentPluginUploadBundleData = { } export type PostWorkspacesCurrentPluginUploadBundleResponses = { - 200: PluginDaemonOperationResponse + 200: PluginBundleUploadResponse } export type PostWorkspacesCurrentPluginUploadBundleResponse @@ -3512,7 +3812,7 @@ export type PostWorkspacesCurrentPluginUploadGithubData = { } export type PostWorkspacesCurrentPluginUploadGithubResponses = { - 200: PluginDaemonOperationResponse + 200: PluginDecodeResponse } export type PostWorkspacesCurrentPluginUploadGithubResponse @@ -3526,7 +3826,7 @@ export type PostWorkspacesCurrentPluginUploadPkgData = { } export type PostWorkspacesCurrentPluginUploadPkgResponses = { - 200: PluginDaemonOperationResponse + 200: PluginDecodeResponse } export type PostWorkspacesCurrentPluginUploadPkgResponse @@ -5246,7 +5546,9 @@ export type GetWorkspacesByTenantIdModelProvidersByProviderByIconTypeByLangData } export type GetWorkspacesByTenantIdModelProvidersByProviderByIconTypeByLangResponses = { - 200: BinaryFileResponse + 200: { + [key: string]: unknown + } } export type GetWorkspacesByTenantIdModelProvidersByProviderByIconTypeByLangResponse diff --git a/packages/contracts/generated/api/console/workspaces/zod.gen.ts b/packages/contracts/generated/api/console/workspaces/zod.gen.ts index 350e54b7a76..5a8a15faccf 100644 --- a/packages/contracts/generated/api/console/workspaces/zod.gen.ts +++ b/packages/contracts/generated/api/console/workspaces/zod.gen.ts @@ -164,9 +164,9 @@ export const zParserCredentialDelete = z.object({ }) /** - * ProviderCredentialResponse + * ProviderCredentialsResponse */ -export const zProviderCredentialResponse = z.object({ +export const zProviderCredentialsResponse = z.object({ credentials: z.record(z.string(), z.unknown()).nullish(), }) @@ -202,21 +202,13 @@ export const zParserCredentialValidate = z.object({ }) /** - * ProviderCredentialValidateResponse + * ValidationResultResponse */ -export const zProviderCredentialValidateResponse = z.object({ +export const zValidationResultResponse = z.object({ error: z.string().nullish(), result: z.enum(['error', 'success']), }) -/** - * ModelCredentialValidateResponse - */ -export const zModelCredentialValidateResponse = z.object({ - error: z.string().nullish(), - result: z.string(), -}) - /** * LoadBalancingCredentialValidateResponse */ @@ -263,13 +255,6 @@ export const zPluginDebuggingKeyResponse = z.object({ port: z.int(), }) -/** - * PluginManifestResponse - */ -export const zPluginManifestResponse = z.object({ - manifest: z.unknown(), -}) - /** * ParserGithubInstall */ @@ -280,11 +265,6 @@ export const zParserGithubInstall = z.object({ version: z.string(), }) -/** - * PluginDaemonOperationResponse - */ -export const zPluginDaemonOperationResponse = z.unknown() - /** * ParserPluginIdentifiers */ @@ -292,14 +272,6 @@ export const zParserPluginIdentifiers = z.object({ plugin_unique_identifiers: z.array(z.string()), }) -/** - * PluginListResponse - */ -export const zPluginListResponse = z.object({ - plugins: z.unknown(), - total: z.int(), -}) - /** * ParserLatest */ @@ -307,13 +279,6 @@ export const zParserLatest = z.object({ plugin_ids: z.array(z.string()), }) -/** - * PluginDynamicOptionsResponse - */ -export const zPluginDynamicOptionsResponse = z.object({ - options: z.unknown(), -}) - /** * ParserDynamicOptionsWithCredentials */ @@ -333,20 +298,6 @@ export const zPluginReadmeResponse = z.object({ readme: z.string(), }) -/** - * PluginTasksResponse - */ -export const zPluginTasksResponse = z.object({ - tasks: z.unknown(), -}) - -/** - * PluginTaskResponse - */ -export const zPluginTaskResponse = z.object({ - task: z.unknown(), -}) - /** * ParserUninstall */ @@ -1006,25 +957,6 @@ export const zCredentialConfiguration = z.object({ credential_name: z.string(), }) -/** - * ModelCredentialLoadBalancingResponse - */ -export const zModelCredentialLoadBalancingResponse = z.object({ - configs: z.array(z.record(z.string(), z.unknown())).optional(), - enabled: z.boolean(), -}) - -/** - * ModelCredentialResponse - */ -export const zModelCredentialResponse = z.object({ - available_credentials: z.array(zCredentialConfiguration), - credentials: z.record(z.string(), z.unknown()).optional(), - current_credential_id: z.string().nullish(), - current_credential_name: z.string().nullish(), - load_balancing: zModelCredentialLoadBalancingResponse, -}) - /** * TenantPluginAutoUpgradeCategory */ @@ -1428,6 +1360,22 @@ export const zI18nObject = z.object({ zh_Hans: z.string().nullish(), }) +/** + * PluginParameterOption + */ +export const zPluginParameterOption = z.object({ + icon: z.string().nullish(), + label: zI18nObject, + value: z.string(), +}) + +/** + * PluginDynamicOptionsResponse + */ +export const zPluginDynamicOptionsResponse = z.object({ + options: z.array(zPluginParameterOption), +}) + /** * ToolLabel * @@ -1661,6 +1609,38 @@ export const zModelStatus = z.enum([ 'quota-exceeded', ]) +/** + * ModelLoadBalancingConfigResponse + */ +export const zModelLoadBalancingConfigResponse = z.object({ + credential_id: z.string().nullish(), + credentials: z.record(z.string(), z.unknown()), + enabled: z.boolean(), + id: z.string(), + in_cooldown: z.boolean(), + name: z.string(), + ttl: z.int(), +}) + +/** + * ModelLoadBalancingResponse + */ +export const zModelLoadBalancingResponse = z.object({ + configs: z.array(zModelLoadBalancingConfigResponse), + enabled: z.boolean(), +}) + +/** + * ModelCredentialResponse + */ +export const zModelCredentialResponse = z.object({ + available_credentials: z.array(zCredentialConfiguration), + credentials: z.record(z.string(), z.unknown()), + current_credential_id: z.string().nullish(), + current_credential_name: z.string().nullish(), + load_balancing: zModelLoadBalancingResponse, +}) + /** * I18nObject * @@ -1708,9 +1688,9 @@ export const zParameterRule = z.object({ }) /** - * ModelParameterRulesResponse + * ModelParameterRuleListResponse */ -export const zModelParameterRulesResponse = z.object({ +export const zModelParameterRuleListResponse = z.object({ data: z.array(zParameterRule), }) @@ -1755,9 +1735,9 @@ export const zProviderWithModelsResponse = z.object({ }) /** - * ProviderWithModelsDataResponse + * AvailableModelListResponse */ -export const zProviderWithModelsDataResponse = z.object({ +export const zAvailableModelListResponse = z.object({ data: z.array(zProviderWithModelsResponse), }) @@ -1810,9 +1790,16 @@ export const zPluginAutoUpgradeFetchResponse = z.object({ }) /** - * PluginInstallationSource + * PluginCategory */ -export const zPluginInstallationSource = z.enum(['github', 'marketplace', 'package', 'remote']) +export const zPluginCategory = z.enum([ + 'agent-strategy', + 'datasource', + 'extension', + 'model', + 'tool', + 'trigger', +]) /** * I18nObject @@ -1826,6 +1813,116 @@ export const zCoreToolsEntitiesCommonEntitiesI18nObject = z.object({ zh_Hans: z.string().nullish(), }) +/** + * Meta + */ +export const zMeta = z.object({ + minimum_dify_version: z.string().nullish(), + version: z.string().nullish(), +}) + +/** + * Plugins + */ +export const zPlugins = z.object({ + datasources: z.array(z.string()).nullish(), + endpoints: z.array(z.string()).nullish(), + models: z.array(z.string()).nullish(), + tools: z.array(z.string()).nullish(), + triggers: z.array(z.string()).nullish(), +}) + +/** + * PluginInstallTaskStatus + */ +export const zPluginInstallTaskStatus = z.enum(['failed', 'pending', 'running', 'success']) + +/** + * PluginInstallTaskPluginStatus + */ +export const zPluginInstallTaskPluginStatus = z.object({ + icon: z.string(), + labels: zI18nObject, + message: z.string(), + plugin_id: z.string(), + plugin_unique_identifier: z.string(), + source: z.string().nullish(), + status: zPluginInstallTaskStatus, +}) + +/** + * PluginInstallTask + */ +export const zPluginInstallTask = z.object({ + completed_plugins: z.int(), + created_at: z.iso.datetime(), + id: z.string(), + plugins: z.array(zPluginInstallTaskPluginStatus), + status: zPluginInstallTaskStatus, + total_plugins: z.int(), + updated_at: z.iso.datetime(), +}) + +/** + * PluginInstallTaskStartResponse + */ +export const zPluginInstallTaskStartResponse = z.object({ + all_installed: z.boolean(), + task: zPluginInstallTask.nullish(), + task_id: z.string(), +}) + +/** + * PluginTasksResponse + */ +export const zPluginTasksResponse = z.object({ + tasks: z.array(zPluginInstallTask), +}) + +/** + * PluginTaskResponse + */ +export const zPluginTaskResponse = z.object({ + task: zPluginInstallTask, +}) + +/** + * PluginInstallationSource + */ +export const zPluginInstallationSource = z.enum(['github', 'marketplace', 'package', 'remote']) + +/** + * PluginBundleDependencyType + */ +export const zPluginBundleDependencyType = z.enum(['github', 'marketplace', 'package']) + +/** + * PluginBundleDependency + */ +export const zPluginBundleDependency = z.object({ + type: zPluginBundleDependencyType, + value: z.union([zGithub, zMarketplace, zPackage]), +}) + +/** + * PluginBundleUploadResponse + */ +export const zPluginBundleUploadResponse = z.array(zPluginBundleDependency) + +/** + * AuthorizedCategory + */ +export const zAuthorizedCategory = z.enum(['community', 'langgenius', 'partner']) + +/** + * PluginVerification + * + * Verification of the plugin. + */ +export const zPluginVerification = z.object({ + authorized_category: zAuthorizedCategory, +}) + /** * PluginCategoryBuiltinToolResponse */ @@ -2158,24 +2255,51 @@ export const zFieldModelSchema = z.object({ export const zProviderQuotaType = z.enum(['free', 'paid', 'trial']) /** - * PluginCategory + * DatasourceProviderType + * + * Enum class for datasource provider */ -export const zPluginCategory = z.enum([ - 'agent-strategy', - 'datasource', - 'extension', - 'model', - 'tool', - 'trigger', +export const zDatasourceProviderType = z.enum([ + 'local_file', + 'online_document', + 'online_drive', + 'website_crawl', ]) /** - * PluginParameterOption + * EndpointDeclaration + * + * declaration of an endpoint */ -export const zPluginParameterOption = z.object({ +export const zEndpointDeclaration = z.object({ + hidden: z.boolean().optional().default(false), + method: z.string(), + path: z.string(), +}) + +/** + * EndpointProviderDeclaration + * + * declaration of an endpoint group + */ +export const zEndpointProviderDeclaration = z.object({ + endpoints: z.array(zEndpointDeclaration).nullish(), + settings: z.array(zProviderConfig).optional(), +}) + +/** + * TriggerProviderIdentity + * + * The identity of the trigger provider + */ +export const zTriggerProviderIdentity = z.object({ + author: z.string(), + description: zCoreToolsEntitiesCommonEntitiesI18nObject, icon: z.string().nullish(), - label: zI18nObject, - value: z.string(), + icon_dark: z.string().nullish(), + label: zCoreToolsEntitiesCommonEntitiesI18nObject, + name: z.string(), + tags: z.array(z.string()).optional(), }) /** @@ -2312,9 +2436,9 @@ export const zModelWithProviderEntityResponse = z.object({ }) /** - * ModelWithProviderListResponse + * ProviderModelListResponse */ -export const zModelWithProviderListResponse = z.object({ +export const zProviderModelListResponse = z.object({ data: z.array(zModelWithProviderEntityResponse), }) @@ -2645,6 +2769,218 @@ export const zModelProviderListResponse = z.object({ data: z.array(zProviderResponse), }) +/** + * ToolLabelEnum + */ +export const zToolLabelEnum = z.enum([ + 'business', + 'design', + 'education', + 'entertainment', + 'finance', + 'image', + 'medical', + 'news', + 'other', + 'productivity', + 'rag', + 'search', + 'social', + 'travel', + 'utilities', + 'videos', + 'weather', +]) + +/** + * AgentStrategyProviderIdentity + * + * Inherits from ToolProviderIdentity, without any additional fields. + */ +export const zAgentStrategyProviderIdentity = z.object({ + author: z.string(), + description: zCoreToolsEntitiesCommonEntitiesI18nObject, + icon: z.string(), + icon_dark: z.string().nullish(), + label: zCoreToolsEntitiesCommonEntitiesI18nObject, + name: z.string(), + tags: z.array(zToolLabelEnum).nullish().default([]), +}) + +/** + * AgentStrategyProviderEntity + */ +export const zAgentStrategyProviderEntity = z.object({ + identity: zAgentStrategyProviderIdentity, + plugin_id: z.string().nullish(), +}) + +/** + * DatasourceProviderIdentity + */ +export const zDatasourceProviderIdentity = z.object({ + author: z.string(), + description: zCoreToolsEntitiesCommonEntitiesI18nObject, + icon: z.string(), + label: zCoreToolsEntitiesCommonEntitiesI18nObject, + name: z.string(), + tags: z.array(zToolLabelEnum).nullish().default([]), +}) + +/** + * DatasourceProviderEntity + * + * Datasource provider entity + */ +export const zDatasourceProviderEntity = z.object({ + credentials_schema: z.array(zProviderConfig).optional(), + identity: zDatasourceProviderIdentity, + oauth_schema: zOAuthSchema.nullish(), + provider_type: zDatasourceProviderType, +}) + +/** + * ToolProviderIdentity + */ +export const zToolProviderIdentity = z.object({ + author: z.string(), + description: zCoreToolsEntitiesCommonEntitiesI18nObject, + icon: z.string(), + icon_dark: z.string().nullish(), + label: zCoreToolsEntitiesCommonEntitiesI18nObject, + name: z.string(), + tags: z.array(zToolLabelEnum).nullish().default([]), +}) + +/** + * ToolProviderEntity + */ +export const zToolProviderEntity = z.object({ + credentials_schema: z.array(zProviderConfig).optional(), + identity: zToolProviderIdentity, + oauth_schema: zOAuthSchema.nullish(), + plugin_id: z.string().nullish(), +}) + +/** + * PriceConfig + * + * Model class for pricing info. + */ +export const zPriceConfig = z.object({ + currency: z.string(), + input: z.string().regex(/^(?![-+.]*$)[+-]?\d*(?:\.\d*)?$/), + output: z + .string() + .regex(/^(?![-+.]*$)[+-]?\d*(?:\.\d*)?$/) + .nullish(), + unit: z.string().regex(/^(?![-+.]*$)[+-]?\d*(?:\.\d*)?$/), +}) + +/** + * AIModelEntity + * + * Model class for AI model. + */ +export const zAiModelEntity = z.object({ + deprecated: z.boolean().optional().default(false), + features: z.array(zModelFeature).nullish(), + fetch_from: zFetchFrom, + label: zGraphonModelRuntimeEntitiesCommonEntitiesI18nObject, + model: z.string(), + model_properties: z.record(z.string(), z.unknown()), + model_type: zModelType, + parameter_rules: z.array(zParameterRule).optional().default([]), + pricing: zPriceConfig.nullish(), +}) + +/** + * ProviderEntity + * + * Runtime-native provider schema. + * + * `provider` is the canonical runtime identifier. `provider_name` is a + * compatibility alias for callers that still resolve providers by short name and + * is empty when no alias exists. + */ +export const zProviderEntity = z.object({ + background: z.string().nullish(), + configurate_methods: z.array(zConfigurateMethod), + description: zGraphonModelRuntimeEntitiesCommonEntitiesI18nObject.nullish(), + help: zProviderHelpEntity.nullish(), + icon_small: zGraphonModelRuntimeEntitiesCommonEntitiesI18nObject.nullish(), + icon_small_dark: zGraphonModelRuntimeEntitiesCommonEntitiesI18nObject.nullish(), + label: zGraphonModelRuntimeEntitiesCommonEntitiesI18nObject, + model_credential_schema: zModelCredentialSchema.nullish(), + models: z.array(zAiModelEntity).optional(), + position: z.record(z.string(), z.array(z.string())).nullish().default({}), + provider: z.string(), + provider_credential_schema: zProviderCredentialSchema.nullish(), + provider_name: z.string().optional().default(''), + supported_model_types: z.array(zModelType), +}) + +/** + * Endpoint + */ +export const zEndpoint = z.object({ + enabled: z.boolean().nullish().default(false), +}) + +/** + * Model + */ +export const zModel = z.object({ + enabled: z.boolean().nullish().default(false), + llm: z.boolean().nullish().default(false), + moderation: z.boolean().nullish().default(false), + rerank: z.boolean().nullish().default(false), + speech2text: z.boolean().nullish().default(false), + text_embedding: z.boolean().nullish().default(false), + tts: z.boolean().nullish().default(false), +}) + +/** + * Node + */ +export const zNode = z.object({ + enabled: z.boolean().nullish().default(false), +}) + +/** + * Storage + */ +export const zStorage = z.object({ + enabled: z.boolean().nullish().default(false), + size: z.int().gte(1024).lte(1073741824).optional().default(1048576), +}) + +/** + * Tool + */ +export const zTool = z.object({ + enabled: z.boolean().nullish().default(false), +}) + +/** + * Permission + */ +export const zPermission = z.object({ + endpoint: zEndpoint.nullish(), + model: zModel.nullish(), + node: zNode.nullish(), + storage: zStorage.nullish(), + tool: zTool.nullish(), +}) + +/** + * PluginResourceRequirements + */ +export const zPluginResourceRequirements = z.object({ + memory: z.int(), + permission: zPermission.nullish(), +}) + /** * PluginParameterAutoGenerateType */ @@ -2876,6 +3212,106 @@ export const zTriggerProviderApiEntity = z.object({ */ export const zTriggerProviderListResponse = z.array(zTriggerProviderApiEntity) +/** + * EventEntity + * + * The configuration of an event + */ +export const zEventEntity = z.object({ + description: zCoreToolsEntitiesCommonEntitiesI18nObject, + identity: zEventIdentity, + output_schema: z.record(z.string(), z.unknown()).nullish(), + parameters: z.array(zEventParameter).optional(), +}) + +/** + * TriggerProviderEntity + * + * The configuration of a trigger provider + */ +export const zTriggerProviderEntity = z.object({ + events: z.array(zEventEntity).optional(), + identity: zTriggerProviderIdentity, + subscription_constructor: zSubscriptionConstructor.nullish(), + subscription_schema: z.array(zProviderConfig).optional(), +}) + +/** + * PluginDeclaration + */ +export const zPluginDeclaration = z.object({ + agent_strategy: zAgentStrategyProviderEntity.nullish(), + author: z + .string() + .regex(/^[\w-]{1,64}$/) + .nullable(), + category: zPluginCategory, + created_at: z.iso.datetime(), + datasource: zDatasourceProviderEntity.nullish(), + description: zCoreToolsEntitiesCommonEntitiesI18nObject, + endpoint: zEndpointProviderDeclaration.nullish(), + icon: z.string(), + icon_dark: z.string().nullish(), + label: zCoreToolsEntitiesCommonEntitiesI18nObject, + meta: zMeta, + model: zProviderEntity.nullish(), + name: z.string().regex(/^[a-z0-9_-]{1,128}$/), + plugins: zPlugins, + repo: z.string().nullish(), + resource: zPluginResourceRequirements, + tags: z.array(z.string()).optional(), + tool: zToolProviderEntity.nullish(), + trigger: zTriggerProviderEntity.nullish(), + verified: z.boolean().optional().default(false), + version: z.string(), +}) + +/** + * PluginManifestResponse + */ +export const zPluginManifestResponse = z.object({ + manifest: zPluginDeclaration, +}) + +/** + * PluginDecodeResponse + */ +export const zPluginDecodeResponse = z.object({ + manifest: zPluginDeclaration, + unique_identifier: z.string(), + verification: zPluginVerification.nullish(), +}) + +/** + * PluginEntity + */ +export const zPluginEntity = z.object({ + checksum: z.string(), + created_at: z.iso.datetime(), + declaration: zPluginDeclaration, + endpoints_active: z.int(), + endpoints_setups: z.int(), + id: z.string(), + installation_id: z.string(), + meta: z.record(z.string(), z.unknown()), + name: z.string(), + plugin_id: z.string(), + plugin_unique_identifier: z.string(), + runtime_type: z.string(), + source: zPluginInstallationSource, + tenant_id: z.string(), + updated_at: z.iso.datetime(), + version: z.string(), +}) + +/** + * PluginListResponse + */ +export const zPluginListResponse = z.object({ + plugins: z.array(zPluginEntity), + total: z.int(), +}) + /** * AccountWithRoleResponse */ @@ -3033,7 +3469,7 @@ export const zGetWorkspacesCurrentDefaultModelQuery = z.object({ }) /** - * Success + * Default model retrieved successfully */ export const zGetWorkspacesCurrentDefaultModelResponse = zDefaultModelDataResponse @@ -3193,7 +3629,7 @@ export const zGetWorkspacesCurrentModelProvidersQuery = z.object({ }) /** - * Success + * Model providers retrieved successfully */ export const zGetWorkspacesCurrentModelProvidersResponse = zModelProviderListResponse @@ -3202,7 +3638,7 @@ export const zGetWorkspacesCurrentModelProvidersByProviderCheckoutUrlPath = z.ob }) /** - * Success + * Model provider checkout URL retrieved successfully */ export const zGetWorkspacesCurrentModelProvidersByProviderCheckoutUrlResponse = zModelProviderPaymentCheckoutUrlResponse @@ -3228,10 +3664,10 @@ export const zGetWorkspacesCurrentModelProvidersByProviderCredentialsQuery = z.o }) /** - * Success + * Provider credentials retrieved successfully */ export const zGetWorkspacesCurrentModelProvidersByProviderCredentialsResponse - = zProviderCredentialResponse + = zProviderCredentialsResponse export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsBody = zParserCredentialCreate @@ -3278,10 +3714,10 @@ export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsValidatePa }) /** - * Credential validation result + * Provider credentials validated successfully */ export const zPostWorkspacesCurrentModelProvidersByProviderCredentialsValidateResponse - = zProviderCredentialValidateResponse + = zValidationResultResponse export const zDeleteWorkspacesCurrentModelProvidersByProviderModelsBody = zParserDeleteModels @@ -3299,10 +3735,10 @@ export const zGetWorkspacesCurrentModelProvidersByProviderModelsPath = z.object( }) /** - * Success + * Provider models retrieved successfully */ export const zGetWorkspacesCurrentModelProvidersByProviderModelsResponse - = zModelWithProviderListResponse + = zProviderModelListResponse export const zPostWorkspacesCurrentModelProvidersByProviderModelsBody = zParserPostModels @@ -3311,7 +3747,7 @@ export const zPostWorkspacesCurrentModelProvidersByProviderModelsPath = z.object }) /** - * Success + * Model updated successfully */ export const zPostWorkspacesCurrentModelProvidersByProviderModelsResponse = zSimpleResultResponse @@ -3339,7 +3775,7 @@ export const zGetWorkspacesCurrentModelProvidersByProviderModelsCredentialsQuery }) /** - * Success + * Model credentials retrieved successfully */ export const zGetWorkspacesCurrentModelProvidersByProviderModelsCredentialsResponse = zModelCredentialResponse @@ -3352,7 +3788,7 @@ export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsPath }) /** - * Credential created successfully + * Model credential created successfully */ export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsResponse = zSimpleResultResponse @@ -3365,7 +3801,7 @@ export const zPutWorkspacesCurrentModelProvidersByProviderModelsCredentialsPath }) /** - * Credential updated successfully + * Model credential updated successfully */ export const zPutWorkspacesCurrentModelProvidersByProviderModelsCredentialsResponse = zSimpleResultResponse @@ -3393,10 +3829,10 @@ export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsVali ) /** - * Credential validation result + * Model credentials validated successfully */ export const zPostWorkspacesCurrentModelProvidersByProviderModelsCredentialsValidateResponse - = zModelCredentialValidateResponse + = zValidationResultResponse export const zPatchWorkspacesCurrentModelProvidersByProviderModelsDisableBody = zParserDeleteModels @@ -3460,10 +3896,10 @@ export const zGetWorkspacesCurrentModelProvidersByProviderModelsParameterRulesQu }) /** - * Success + * Model parameter rules retrieved successfully */ export const zGetWorkspacesCurrentModelProvidersByProviderModelsParameterRulesResponse - = zModelParameterRulesResponse + = zModelParameterRuleListResponse export const zPostWorkspacesCurrentModelProvidersByProviderPreferredProviderTypeBody = zParserPreferredProviderType @@ -3483,10 +3919,9 @@ export const zGetWorkspacesCurrentModelsModelTypesByModelTypePath = z.object({ }) /** - * Success + * Available models retrieved successfully */ -export const zGetWorkspacesCurrentModelsModelTypesByModelTypeResponse - = zProviderWithModelsDataResponse +export const zGetWorkspacesCurrentModelsModelTypesByModelTypeResponse = zAvailableModelListResponse /** * Success @@ -3556,21 +3991,22 @@ export const zPostWorkspacesCurrentPluginInstallGithubBody = zParserGithubInstal /** * Success */ -export const zPostWorkspacesCurrentPluginInstallGithubResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginInstallGithubResponse = zPluginInstallTaskStartResponse export const zPostWorkspacesCurrentPluginInstallMarketplaceBody = zParserPluginIdentifiers /** * Success */ -export const zPostWorkspacesCurrentPluginInstallMarketplaceResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginInstallMarketplaceResponse + = zPluginInstallTaskStartResponse export const zPostWorkspacesCurrentPluginInstallPkgBody = zParserPluginIdentifiers /** * Success */ -export const zPostWorkspacesCurrentPluginInstallPkgResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginInstallPkgResponse = zPluginInstallTaskStartResponse export const zGetWorkspacesCurrentPluginListQuery = z.object({ page: z.int().gte(1).optional().default(1), @@ -3706,31 +4142,32 @@ export const zPostWorkspacesCurrentPluginUpgradeGithubBody = zParserGithubUpgrad /** * Success */ -export const zPostWorkspacesCurrentPluginUpgradeGithubResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginUpgradeGithubResponse = zPluginInstallTaskStartResponse export const zPostWorkspacesCurrentPluginUpgradeMarketplaceBody = zParserMarketplaceUpgrade /** * Success */ -export const zPostWorkspacesCurrentPluginUpgradeMarketplaceResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginUpgradeMarketplaceResponse + = zPluginInstallTaskStartResponse /** * Success */ -export const zPostWorkspacesCurrentPluginUploadBundleResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginUploadBundleResponse = zPluginBundleUploadResponse export const zPostWorkspacesCurrentPluginUploadGithubBody = zParserGithubUpload /** * Success */ -export const zPostWorkspacesCurrentPluginUploadGithubResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginUploadGithubResponse = zPluginDecodeResponse /** * Success */ -export const zPostWorkspacesCurrentPluginUploadPkgResponse = zPluginDaemonOperationResponse +export const zPostWorkspacesCurrentPluginUploadPkgResponse = zPluginDecodeResponse export const zGetWorkspacesCurrentPluginByCategoryListPath = z.object({ category: z.string(), @@ -4782,7 +5219,9 @@ export const zGetWorkspacesByTenantIdModelProvidersByProviderByIconTypeByLangPat }) /** - * Success + * Model provider icon */ -export const zGetWorkspacesByTenantIdModelProvidersByProviderByIconTypeByLangResponse - = zBinaryFileResponse +export const zGetWorkspacesByTenantIdModelProvidersByProviderByIconTypeByLangResponse = z.record( + z.string(), + z.unknown(), +)