Merge remote-tracking branch 'origin/main' into feat/collaboration

This commit is contained in:
lyzno1 2025-10-15 10:02:55 +08:00
commit 0395d1f91f
No known key found for this signature in database
17 changed files with 85 additions and 41 deletions

View File

@ -189,6 +189,11 @@ class ToolInvokeMessage(BaseModel):
data: Mapping[str, Any] = Field(..., description="Detailed log data") data: Mapping[str, Any] = Field(..., description="Detailed log data")
metadata: Mapping[str, Any] = Field(default_factory=dict, description="The metadata of the log") metadata: Mapping[str, Any] = Field(default_factory=dict, description="The metadata of the log")
@field_validator("metadata", mode="before")
@classmethod
def _normalize_metadata(cls, value: Mapping[str, Any] | None) -> Mapping[str, Any]:
return value or {}
class RetrieverResourceMessage(BaseModel): class RetrieverResourceMessage(BaseModel):
retriever_resources: list[RetrievalSourceMetadata] = Field(..., description="retriever resources") retriever_resources: list[RetrievalSourceMetadata] = Field(..., description="retriever resources")
context: str = Field(..., description="context") context: str = Field(..., description="context")
@ -376,6 +381,11 @@ class ToolEntity(BaseModel):
def set_parameters(cls, v, validation_info: ValidationInfo) -> list[ToolParameter]: def set_parameters(cls, v, validation_info: ValidationInfo) -> list[ToolParameter]:
return v or [] return v or []
@field_validator("output_schema", mode="before")
@classmethod
def _normalize_output_schema(cls, value: Mapping[str, object] | None) -> Mapping[str, object]:
return value or {}
class OAuthSchema(BaseModel): class OAuthSchema(BaseModel):
client_schema: list[ProviderConfig] = Field( client_schema: list[ProviderConfig] = Field(

View File

@ -88,7 +88,6 @@ dependencies = [
"sendgrid~=6.12.3", "sendgrid~=6.12.3",
"flask-restx~=1.3.0", "flask-restx~=1.3.0",
"packaging~=23.2", "packaging~=23.2",
"weaviate-client==4.17.0",
] ]
# Before adding new dependency, consider place it in # Before adding new dependency, consider place it in
# alphabet order (a-z) and suitable group. # alphabet order (a-z) and suitable group.

View File

@ -75,10 +75,7 @@
</head> </head>
<body> <body>
<div class="container"> <div class="container">
<div class="header"> <div class="header"></div>
<!-- Optional: Add a logo or a header image here -->
<img src="https://assets.dify.ai/images/logo.png" alt="Dify Logo">
</div>
<div class="content"> <div class="content">
<p class="content1">Dear {{ to }},</p> <p class="content1">Dear {{ to }},</p>
<p class="content2">{{ inviter_name }} is pleased to invite you to join our workspace on {{application_title}}, a platform specifically designed for LLM application development. On {{application_title}}, you can explore, create, and collaborate to build and operate AI applications.</p> <p class="content2">{{ inviter_name }} is pleased to invite you to join our workspace on {{application_title}}, a platform specifically designed for LLM application development. On {{application_title}}, you can explore, create, and collaborate to build and operate AI applications.</p>

View File

@ -110,19 +110,6 @@ class TestAlibabaCloudMySQLVector(unittest.TestCase):
assert mock_cursor.execute.call_count >= 3 # CREATE TABLE + 2 indexes assert mock_cursor.execute.call_count >= 3 # CREATE TABLE + 2 indexes
mock_redis.set.assert_called_once() mock_redis.set.assert_called_once()
def test_config_validation(self):
"""Test configuration validation."""
# Test missing required fields
with pytest.raises(ValueError):
AlibabaCloudMySQLVectorConfig(
host="", # Empty host should raise error
port=3306,
user="test",
password="test",
database="test",
max_connection=5,
)
@patch( @patch(
"core.rag.datasource.vdb.alibabacloud_mysql.alibabacloud_mysql_vector.mysql.connector.pooling.MySQLConnectionPool" "core.rag.datasource.vdb.alibabacloud_mysql.alibabacloud_mysql_vector.mysql.connector.pooling.MySQLConnectionPool"
) )
@ -718,5 +705,29 @@ class TestAlibabaCloudMySQLVector(unittest.TestCase):
mock_cursor.fetchone.side_effect = [{"VERSION()": "8.0.36"}, {"vector_support": True}] mock_cursor.fetchone.side_effect = [{"VERSION()": "8.0.36"}, {"vector_support": True}]
@pytest.mark.parametrize(
"invalid_config_override",
[
{"host": ""}, # Test empty host
{"port": 0}, # Test invalid port
{"max_connection": 0}, # Test invalid max_connection
],
)
def test_config_validation_parametrized(invalid_config_override):
"""Test configuration validation for various invalid inputs using parametrize."""
config = {
"host": "localhost",
"port": 3306,
"user": "test",
"password": "test",
"database": "test",
"max_connection": 5,
}
config.update(invalid_config_override)
with pytest.raises(ValueError):
AlibabaCloudMySQLVectorConfig(**config)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -0,0 +1,29 @@
from core.tools.entities.common_entities import I18nObject
from core.tools.entities.tool_entities import ToolEntity, ToolIdentity, ToolInvokeMessage
def _make_identity() -> ToolIdentity:
return ToolIdentity(
author="author",
name="tool",
label=I18nObject(en_US="Label"),
provider="builtin",
)
def test_log_message_metadata_none_defaults_to_empty_dict():
log_message = ToolInvokeMessage.LogMessage(
id="log-1",
label="Log entry",
status=ToolInvokeMessage.LogMessage.LogStatus.START,
data={},
metadata=None,
)
assert log_message.metadata == {}
def test_tool_entity_output_schema_none_defaults_to_empty_dict():
entity = ToolEntity(identity=_make_identity(), output_schema=None)
assert entity.output_schema == {}

4
api/uv.lock generated
View File

@ -1,5 +1,5 @@
version = 1 version = 1
revision = 3 revision = 2
requires-python = ">=3.11, <3.13" requires-python = ">=3.11, <3.13"
resolution-markers = [ resolution-markers = [
"python_full_version >= '3.12.4' and platform_python_implementation != 'PyPy' and sys_platform == 'linux'", "python_full_version >= '3.12.4' and platform_python_implementation != 'PyPy' and sys_platform == 'linux'",
@ -1383,7 +1383,6 @@ dependencies = [
{ name = "transformers" }, { name = "transformers" },
{ name = "unstructured", extra = ["docx", "epub", "md", "ppt", "pptx"] }, { name = "unstructured", extra = ["docx", "epub", "md", "ppt", "pptx"] },
{ name = "weave" }, { name = "weave" },
{ name = "weaviate-client" },
{ name = "webvtt-py" }, { name = "webvtt-py" },
{ name = "yarl" }, { name = "yarl" },
] ]
@ -1575,7 +1574,6 @@ requires-dist = [
{ name = "transformers", specifier = "~=4.56.1" }, { name = "transformers", specifier = "~=4.56.1" },
{ name = "unstructured", extras = ["docx", "epub", "md", "ppt", "pptx"], specifier = "~=0.16.1" }, { name = "unstructured", extras = ["docx", "epub", "md", "ppt", "pptx"], specifier = "~=0.16.1" },
{ name = "weave", specifier = "~=0.51.0" }, { name = "weave", specifier = "~=0.51.0" },
{ name = "weaviate-client", specifier = "==4.17.0" },
{ name = "webvtt-py", specifier = "~=0.5.1" }, { name = "webvtt-py", specifier = "~=0.5.1" },
{ name = "yarl", specifier = "~=1.18.3" }, { name = "yarl", specifier = "~=1.18.3" },
] ]

View File

@ -767,8 +767,8 @@ The text generation application offers non-session support and is ideal for tran
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -764,8 +764,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -728,8 +728,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -1599,8 +1599,8 @@ Chat applications support session persistence, allowing previous chat history to
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -1586,8 +1586,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Col> <Col>
<CodeGroup <CodeGroup
title="リクエスト" title="リクエスト"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -1579,8 +1579,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx'
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -1025,8 +1025,8 @@ Workflow applications offers non-session support and is ideal for translation, a
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -1021,8 +1021,8 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -1012,8 +1012,8 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
<Col> <Col>
<CodeGroup <CodeGroup
title="Request" title="Request"
tag="POST" tag="GET"
label="/meta" label="/site"
targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\ targetCode={`curl -X GET '${props.appDetail.api_base_url}/site' \\
-H 'Authorization: Bearer {api_key}'`} -H 'Authorization: Bearer {api_key}'`}
/> />

View File

@ -20,7 +20,7 @@ const translation = {
save: '保存', save: '保存',
yes: '是', yes: '是',
no: '否', no: '否',
deleteConfirmTitle: '删除?', deleteConfirmTitle: '删除',
confirmAction: '请确认您的操作。', confirmAction: '请确认您的操作。',
saveAndEnable: '保存并启用', saveAndEnable: '保存并启用',
edit: '编辑', edit: '编辑',

View File

@ -2,7 +2,7 @@
"name": "dify-web", "name": "dify-web",
"version": "1.9.1", "version": "1.9.1",
"private": true, "private": true,
"packageManager": "pnpm@10.18.2", "packageManager": "pnpm@10.18.3+sha512.bbd16e6d7286fd7e01f6b3c0b3c932cda2965c06a908328f74663f10a9aea51f1129eea615134bf992831b009eabe167ecb7008b597f40ff9bc75946aadfb08d",
"engines": { "engines": {
"node": ">=v22.11.0" "node": ">=v22.11.0"
}, },