3
3
4
4
from pydantic import BaseModel
5
5
6
+ from configs import dify_config
6
7
from core .plugin .entities .plugin import GenericProviderID , ToolProviderID
7
8
from core .plugin .entities .plugin_daemon import PluginBasicBooleanResponse , PluginToolProviderEntity
8
9
from core .plugin .impl .base import BasePluginClient
9
10
from core .tools .entities .tool_entities import ToolInvokeMessage , ToolParameter
10
11
11
12
13
+ class FileChunk :
14
+ """
15
+ Only used for internal processing.
16
+ """
17
+
18
+ __slots__ = ("bytes_written" , "total_length" , "data" )
19
+
20
+ bytes_written : int
21
+ total_length : int
22
+ data : bytearray
23
+
24
+ def __init__ (self , total_length : int ):
25
+ self .bytes_written = 0
26
+ self .total_length = total_length
27
+ self .data = bytearray (total_length )
28
+
29
+ def write_blob (self , blob_data ):
30
+ blob_data_length = len (blob_data )
31
+ if blob_data_length == 0 :
32
+ return
33
+
34
+ # Validate write boundaries
35
+ expected_final_size = self .bytes_written + blob_data_length
36
+ if expected_final_size > self .total_length :
37
+ raise ValueError (f"Chunk would exceed file size ({ expected_final_size } > { self .total_length } )" )
38
+
39
+ start_pos = self .bytes_written
40
+ self .data [start_pos : start_pos + blob_data_length ] = blob_data
41
+ self .bytes_written += blob_data_length
42
+
43
+
12
44
class PluginToolManager (BasePluginClient ):
13
45
def fetch_tool_providers (self , tenant_id : str ) -> list [PluginToolProviderEntity ]:
14
46
"""
@@ -111,20 +143,6 @@ def invoke(
111
143
},
112
144
)
113
145
114
- class FileChunk :
115
- """
116
- Only used for internal processing.
117
- """
118
-
119
- bytes_written : int
120
- total_length : int
121
- data : bytearray
122
-
123
- def __init__ (self , total_length : int ):
124
- self .bytes_written = 0
125
- self .total_length = total_length
126
- self .data = bytearray (total_length )
127
-
128
146
files : dict [str , FileChunk ] = {}
129
147
for resp in response :
130
148
if resp .type == ToolInvokeMessage .MessageType .BLOB_CHUNK :
@@ -134,36 +152,33 @@ def __init__(self, total_length: int):
134
152
total_length = resp .message .total_length
135
153
blob_data = resp .message .blob
136
154
is_end = resp .message .end
155
+ blob_data_length = len (blob_data )
156
+
157
+ # Pre-check conditions to avoid unnecessary processing
158
+ file_size_limit = dify_config .TOOL_FILE_SIZE_LIMIT
159
+ chunk_size_limit = dify_config .TOOL_FILE_CHUNK_SIZE_LIMIT
160
+ if total_length > file_size_limit :
161
+ raise ValueError (f"File size { total_length } exceeds limit of { file_size_limit } bytes" )
162
+
163
+ if blob_data_length > chunk_size_limit :
164
+ raise ValueError (f"Chunk size { blob_data_length } exceeds limit of { chunk_size_limit } bytes" )
137
165
138
166
# Initialize buffer for this file if it doesn't exist
139
167
if chunk_id not in files :
140
168
files [chunk_id ] = FileChunk (total_length )
169
+ file_chunk = files [chunk_id ]
141
170
142
171
# If this is the final chunk, yield a complete blob message
143
172
if is_end :
144
173
yield ToolInvokeMessage (
145
174
type = ToolInvokeMessage .MessageType .BLOB ,
146
- message = ToolInvokeMessage .BlobMessage (blob = files [ chunk_id ] .data ),
175
+ message = ToolInvokeMessage .BlobMessage (blob = bytes ( file_chunk .data ) ),
147
176
meta = resp .meta ,
148
177
)
178
+ del files [chunk_id ]
149
179
else :
150
- # Check if file is too large (30MB limit)
151
- if files [chunk_id ].bytes_written + len (blob_data ) > 30 * 1024 * 1024 :
152
- # Delete the file if it's too large
153
- del files [chunk_id ]
154
- # Skip yielding this message
155
- raise ValueError ("File is too large which reached the limit of 30MB" )
156
-
157
- # Check if single chunk is too large (8KB limit)
158
- if len (blob_data ) > 8192 :
159
- # Skip yielding this message
160
- raise ValueError ("File chunk is too large which reached the limit of 8KB" )
161
-
162
- # Append the blob data to the buffer
163
- files [chunk_id ].data [
164
- files [chunk_id ].bytes_written : files [chunk_id ].bytes_written + len (blob_data )
165
- ] = blob_data
166
- files [chunk_id ].bytes_written += len (blob_data )
180
+ # Write the blob data to the file chunk
181
+ file_chunk .write_blob (blob_data )
167
182
else :
168
183
yield resp
169
184
0 commit comments