Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cleanup and rearrange unclassified configs into feature config groups #7586

Merged
merged 11 commits into from
Aug 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 4 additions & 33 deletions api/configs/app_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from pydantic import Field, computed_field
from pydantic_settings import SettingsConfigDict

from configs.deploy import DeploymentConfig
Expand All @@ -24,8 +23,6 @@ class DifyConfig(
# **Before using, please contact [email protected] by email to inquire about licensing matters.**
EnterpriseFeatureConfig,
):
DEBUG: bool = Field(default=False, description='whether to enable debug mode.')

model_config = SettingsConfigDict(
# read from dotenv format config file
env_file='.env',
Expand All @@ -35,33 +32,7 @@ class DifyConfig(
extra='ignore',
)

CODE_MAX_NUMBER: int = 9223372036854775807
CODE_MIN_NUMBER: int = -9223372036854775808
CODE_MAX_DEPTH: int = 5
CODE_MAX_PRECISION: int = 20
CODE_MAX_STRING_LENGTH: int = 80000
CODE_MAX_STRING_ARRAY_LENGTH: int = 30
CODE_MAX_OBJECT_ARRAY_LENGTH: int = 30
CODE_MAX_NUMBER_ARRAY_LENGTH: int = 1000

HTTP_REQUEST_MAX_CONNECT_TIMEOUT: int = 300
HTTP_REQUEST_MAX_READ_TIMEOUT: int = 600
HTTP_REQUEST_MAX_WRITE_TIMEOUT: int = 600
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: int = 1024 * 1024 * 10

@computed_field
def HTTP_REQUEST_NODE_READABLE_MAX_BINARY_SIZE(self) -> str:
return f'{self.HTTP_REQUEST_NODE_MAX_BINARY_SIZE / 1024 / 1024:.2f}MB'

HTTP_REQUEST_NODE_MAX_TEXT_SIZE: int = 1024 * 1024

@computed_field
def HTTP_REQUEST_NODE_READABLE_MAX_TEXT_SIZE(self) -> str:
return f'{self.HTTP_REQUEST_NODE_MAX_TEXT_SIZE / 1024 / 1024:.2f}MB'

SSRF_PROXY_HTTP_URL: str | None = None
SSRF_PROXY_HTTPS_URL: str | None = None

MODERATION_BUFFER_SIZE: int = Field(default=300, description='The buffer size for moderation.')

MAX_VARIABLE_SIZE: int = Field(default=5 * 1024, description='The maximum size of a variable. default is 5KB.')
# Before adding any config,
# please consider to arrange it in the proper config group of existed or added
# for better readability and maintainability.
# Thanks for your concentration and consideration.
5 changes: 5 additions & 0 deletions api/configs/deploy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ class DeploymentConfig(BaseSettings):
default='langgenius/dify',
)

DEBUG: bool = Field(
description='whether to enable debug mode.',
default=False,
)

TESTING: bool = Field(
description='',
default=False,
Expand Down
86 changes: 82 additions & 4 deletions api/configs/feature/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import Optional

from pydantic import AliasChoices, Field, NonNegativeInt, PositiveInt, computed_field
from pydantic import AliasChoices, Field, NegativeInt, NonNegativeInt, PositiveInt, computed_field
from pydantic_settings import BaseSettings

from configs.feature.hosted_service import HostedServiceConfig
Expand Down Expand Up @@ -52,6 +52,46 @@ class CodeExecutionSandboxConfig(BaseSettings):
default='dify-sandbox',
)

CODE_MAX_NUMBER: PositiveInt = Field(
description='max depth for code execution',
default=9223372036854775807,
)

CODE_MIN_NUMBER: NegativeInt = Field(
description='',
default=-9223372036854775807,
)

CODE_MAX_DEPTH: PositiveInt = Field(
description='max depth for code execution',
default=5,
)

CODE_MAX_PRECISION: PositiveInt = Field(
description='max precision digits for float type in code execution',
default=20,
)

CODE_MAX_STRING_LENGTH: PositiveInt = Field(
description='max string length for code execution',
default=80000,
)

CODE_MAX_STRING_ARRAY_LENGTH: PositiveInt = Field(
description='',
default=30,
)

CODE_MAX_OBJECT_ARRAY_LENGTH: PositiveInt = Field(
description='',
default=30,
)

CODE_MAX_NUMBER_ARRAY_LENGTH: PositiveInt = Field(
description='',
default=1000,
)


class EndpointConfig(BaseSettings):
"""
Expand Down Expand Up @@ -157,6 +197,41 @@ def CONSOLE_CORS_ALLOW_ORIGINS(self) -> list[str]:
def WEB_API_CORS_ALLOW_ORIGINS(self) -> list[str]:
return self.inner_WEB_API_CORS_ALLOW_ORIGINS.split(',')

HTTP_REQUEST_MAX_CONNECT_TIMEOUT: NonNegativeInt = Field(
description='',
default=300,
)

HTTP_REQUEST_MAX_READ_TIMEOUT: NonNegativeInt = Field(
description='',
default=600,
)

HTTP_REQUEST_MAX_WRITE_TIMEOUT: NonNegativeInt = Field(
description='',
default=600,
)

HTTP_REQUEST_NODE_MAX_BINARY_SIZE: PositiveInt = Field(
description='',
default=10 * 1024 * 1024,
)

HTTP_REQUEST_NODE_MAX_TEXT_SIZE: PositiveInt = Field(
description='',
default=1 * 1024 * 1024,
)

SSRF_PROXY_HTTP_URL: Optional[str] = Field(
description='HTTP URL for SSRF proxy',
default=None,
)

SSRF_PROXY_HTTPS_URL: Optional[str] = Field(
description='HTTPS URL for SSRF proxy',
default=None,
)


class InnerAPIConfig(BaseSettings):
"""
Expand Down Expand Up @@ -255,6 +330,11 @@ class WorkflowConfig(BaseSettings):
default=5,
)

MAX_VARIABLE_SIZE: PositiveInt = Field(
description='The maximum size in bytes of a variable. default to 5KB.',
default=5 * 1024,
)


class OAuthConfig(BaseSettings):
"""
Expand Down Expand Up @@ -291,8 +371,7 @@ class ModerationConfig(BaseSettings):
Moderation in app configs.
"""

# todo: to be clarified in usage and unit
OUTPUT_MODERATION_BUFFER_SIZE: PositiveInt = Field(
MODERATION_BUFFER_SIZE: PositiveInt = Field(
description='buffer size for moderation',
default=300,
)
Expand Down Expand Up @@ -444,7 +523,6 @@ class CeleryBeatConfig(BaseSettings):


class PositionConfig(BaseSettings):

POSITION_PROVIDER_PINS: str = Field(
description='The heads of model providers',
default='',
Expand Down
43 changes: 20 additions & 23 deletions api/core/workflow/nodes/code/code_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,6 @@
from core.workflow.nodes.code.entities import CodeNodeData
from models.workflow import WorkflowNodeExecutionStatus

MAX_NUMBER = dify_config.CODE_MAX_NUMBER
MIN_NUMBER = dify_config.CODE_MIN_NUMBER
MAX_PRECISION = dify_config.CODE_MAX_PRECISION
MAX_DEPTH = dify_config.CODE_MAX_DEPTH
MAX_STRING_LENGTH = dify_config.CODE_MAX_STRING_LENGTH
MAX_STRING_ARRAY_LENGTH = dify_config.CODE_MAX_STRING_ARRAY_LENGTH
MAX_OBJECT_ARRAY_LENGTH = dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH
MAX_NUMBER_ARRAY_LENGTH = dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH


class CodeNode(BaseNode):
_node_data_cls = CodeNodeData
Expand Down Expand Up @@ -97,8 +88,9 @@ def _check_string(self, value: str, variable: str) -> str:
else:
raise ValueError(f"Output variable `{variable}` must be a string")

if len(value) > MAX_STRING_LENGTH:
raise ValueError(f'The length of output variable `{variable}` must be less than {MAX_STRING_LENGTH} characters')
if len(value) > dify_config.CODE_MAX_STRING_ARRAY_LENGTH:
raise ValueError(f'The length of output variable `{variable}` must be'
f' less than {dify_config.CODE_MAX_STRING_ARRAY_LENGTH} characters')

return value.replace('\x00', '')

Expand All @@ -115,13 +107,15 @@ def _check_number(self, value: Union[int, float], variable: str) -> Union[int, f
else:
raise ValueError(f"Output variable `{variable}` must be a number")

if value > MAX_NUMBER or value < MIN_NUMBER:
raise ValueError(f'Output variable `{variable}` is out of range, it must be between {MIN_NUMBER} and {MAX_NUMBER}.')
if value > dify_config.CODE_MAX_NUMBER or value < dify_config.CODE_MIN_NUMBER:
raise ValueError(f'Output variable `{variable}` is out of range,'
f' it must be between {dify_config.CODE_MIN_NUMBER} and {dify_config.CODE_MAX_NUMBER}.')

if isinstance(value, float):
# raise error if precision is too high
if len(str(value).split('.')[1]) > MAX_PRECISION:
raise ValueError(f'Output variable `{variable}` has too high precision, it must be less than {MAX_PRECISION} digits.')
if len(str(value).split('.')[1]) > dify_config.CODE_MAX_PRECISION:
raise ValueError(f'Output variable `{variable}` has too high precision,'
f' it must be less than {dify_config.CODE_MAX_PRECISION} digits.')

return value

Expand All @@ -134,8 +128,8 @@ def _transform_result(self, result: dict, output_schema: Optional[dict[str, Code
:param output_schema: output schema
:return:
"""
if depth > MAX_DEPTH:
raise ValueError("Depth limit reached, object too deep.")
if depth > dify_config.CODE_MAX_DEPTH:
raise ValueError(f"Depth limit ${dify_config.CODE_MAX_DEPTH} reached, object too deep.")

transformed_result = {}
if output_schema is None:
Expand Down Expand Up @@ -235,9 +229,10 @@ def _transform_result(self, result: dict, output_schema: Optional[dict[str, Code
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
)
else:
if len(result[output_name]) > MAX_NUMBER_ARRAY_LENGTH:
if len(result[output_name]) > dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH:
raise ValueError(
f'The length of output variable `{prefix}{dot}{output_name}` must be less than {MAX_NUMBER_ARRAY_LENGTH} elements.'
f'The length of output variable `{prefix}{dot}{output_name}` must be'
f' less than {dify_config.CODE_MAX_NUMBER_ARRAY_LENGTH} elements.'
)

transformed_result[output_name] = [
Expand All @@ -257,9 +252,10 @@ def _transform_result(self, result: dict, output_schema: Optional[dict[str, Code
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
)
else:
if len(result[output_name]) > MAX_STRING_ARRAY_LENGTH:
if len(result[output_name]) > dify_config.CODE_MAX_STRING_ARRAY_LENGTH:
raise ValueError(
f'The length of output variable `{prefix}{dot}{output_name}` must be less than {MAX_STRING_ARRAY_LENGTH} elements.'
f'The length of output variable `{prefix}{dot}{output_name}` must be'
f' less than {dify_config.CODE_MAX_STRING_ARRAY_LENGTH} elements.'
)

transformed_result[output_name] = [
Expand All @@ -279,9 +275,10 @@ def _transform_result(self, result: dict, output_schema: Optional[dict[str, Code
f'Output {prefix}{dot}{output_name} is not an array, got {type(result.get(output_name))} instead.'
)
else:
if len(result[output_name]) > MAX_OBJECT_ARRAY_LENGTH:
if len(result[output_name]) > dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH:
raise ValueError(
f'The length of output variable `{prefix}{dot}{output_name}` must be less than {MAX_OBJECT_ARRAY_LENGTH} elements.'
f'The length of output variable `{prefix}{dot}{output_name}` must be'
f' less than {dify_config.CODE_MAX_OBJECT_ARRAY_LENGTH} elements.'
)

for i, value in enumerate(result[output_name]):
Expand Down
23 changes: 8 additions & 15 deletions api/core/workflow/nodes/http_request/http_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@
)
from core.workflow.utils.variable_template_parser import VariableTemplateParser

MAX_BINARY_SIZE = dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE
READABLE_MAX_BINARY_SIZE = dify_config.HTTP_REQUEST_NODE_READABLE_MAX_BINARY_SIZE
MAX_TEXT_SIZE = dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE
READABLE_MAX_TEXT_SIZE = dify_config.HTTP_REQUEST_NODE_READABLE_MAX_TEXT_SIZE


class HttpExecutorResponse:
headers: dict[str, str]
Expand Down Expand Up @@ -237,16 +232,14 @@ def _validate_and_parse_response(self, response: httpx.Response) -> HttpExecutor
else:
raise ValueError(f'Invalid response type {type(response)}')

if executor_response.is_file:
if executor_response.size > MAX_BINARY_SIZE:
raise ValueError(
f'File size is too large, max size is {READABLE_MAX_BINARY_SIZE}, but current size is {executor_response.readable_size}.'
)
else:
if executor_response.size > MAX_TEXT_SIZE:
raise ValueError(
f'Text size is too large, max size is {READABLE_MAX_TEXT_SIZE}, but current size is {executor_response.readable_size}.'
)
threshold_size = dify_config.HTTP_REQUEST_NODE_MAX_BINARY_SIZE if executor_response.is_file \
else dify_config.HTTP_REQUEST_NODE_MAX_TEXT_SIZE
if executor_response.size > threshold_size:
raise ValueError(
f'{"File" if executor_response.is_file else "Text"} size is too large,'
f' max size is {threshold_size / 1024 / 1024:.2f} MB,'
f' but current size is {executor_response.readable_size}.'
)

return executor_response

Expand Down
9 changes: 5 additions & 4 deletions api/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pandas = { version = "~2.2.2", extras = ["performance", "excel"] }
psycopg2-binary = "~2.9.6"
pycryptodome = "3.19.1"
pydantic = "~2.8.2"
pydantic-settings = "~2.3.4"
pydantic-settings = "~2.4.0"
pydantic_extra_types = "~2.9.0"
pyjwt = "~2.8.0"
pypdfium2 = "~4.17.0"
Expand Down