Skip to content

Commit aa5d6a4

Browse files
Patch: Fix file size limit, MIME type uses library (#3781)
1 parent b1b558b commit aa5d6a4

File tree

2 files changed

+31
-64
lines changed

2 files changed

+31
-64
lines changed

src/google/adk/plugins/save_files_as_artifacts_plugin.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
from ..agents.invocation_context import InvocationContext
2828
from .base_plugin import BasePlugin
29+
import mimetypes
2930

3031
logger = logging.getLogger('google_adk.' + __name__)
3132

@@ -108,9 +109,10 @@ async def on_user_message_callback(
108109
# Check if file exceeds Files API limit (2GB)
109110
if file_size > _MAX_FILES_API_SIZE_BYTES:
110111
file_size_gb = file_size / (1024 * 1024 * 1024)
112+
max_size_gb = _MAX_FILES_API_SIZE_BYTES / (1024 * 1024 * 1024)
111113
error_message = (
112114
f'File {display_name} ({file_size_gb:.2f} GB) exceeds the'
113-
' maximum supported size of 2GB. Please upload a smaller file.'
115+
f' maximum supported size of {max_size_gb:.2f} GB. Please upload a smaller file.'
114116
)
115117
logger.warning(error_message)
116118
new_parts.append(types.Part(text=f'[Upload Error: {error_message}]'))
@@ -215,15 +217,7 @@ async def _upload_to_files_api(
215217
file_extension = os.path.splitext(inline_data.display_name)[1]
216218
elif inline_data.mime_type:
217219
# Simple mime type to extension mapping
218-
mime_to_ext = {
219-
'application/pdf': '.pdf',
220-
'image/png': '.png',
221-
'image/jpeg': '.jpg',
222-
'image/gif': '.gif',
223-
'text/plain': '.txt',
224-
'application/json': '.json',
225-
}
226-
file_extension = mime_to_ext.get(inline_data.mime_type, '')
220+
file_extension = mimetypes.guess_extension(inline_data.mime_type) or ''
227221

228222
# Create temporary file
229223
with tempfile.NamedTemporaryFile(

tests/unittests/plugins/test_save_files_as_artifacts.py

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -495,60 +495,33 @@ async def test_files_api_upload_failure(self):
495495
assert "huge_file.pdf" in result.parts[0].text
496496
assert "API quota exceeded" in result.parts[0].text
497497

498-
@pytest.mark.asyncio
499-
async def test_file_exceeds_files_api_limit(self):
500-
"""Test that files exceeding 2GB limit are rejected with clear error."""
501-
# Create a file larger than 2GB (simulated with a descriptor that reports large size)
502-
# Create a mock object that behaves like bytes but reports 2GB+ size
503-
large_data = b"x" * 1000 # Small actual data for testing
504-
505-
# Create inline_data with the small data
506-
inline_data = types.Blob(
507-
display_name="huge_video.mp4",
508-
data=large_data,
509-
mime_type="video/mp4",
510-
)
511-
512-
user_message = types.Content(parts=[types.Part(inline_data=inline_data)])
513-
514-
# Patch the file size check to simulate a 2GB+ file
515-
original_callback = self.plugin.on_user_message_callback
516-
517-
async def patched_callback(*, invocation_context, user_message):
518-
# Temporarily replace the data length check
519-
for part in user_message.parts:
520-
if part.inline_data:
521-
# Simulate 2GB + 1 byte size
522-
file_size_over_limit = (2 * 1024 * 1024 * 1024) + 1
523-
# Manually inject the check that would happen in the real code
524-
if file_size_over_limit > (2 * 1024 * 1024 * 1024):
525-
file_size_gb = file_size_over_limit / (1024 * 1024 * 1024)
526-
display_name = part.inline_data.display_name or "unknown"
527-
error_message = (
528-
f"File {display_name} ({file_size_gb:.2f} GB) exceeds the"
529-
" maximum supported size of 2GB. Please upload a smaller file."
530-
)
531-
return types.Content(
532-
role="user",
533-
parts=[types.Part(text=f"[Upload Error: {error_message}]")],
498+
@pytest.mark.asyncio
499+
async def test_file_exceeds_files_api_limit(self):
500+
"""Test that files exceeding 2GB limit are rejected with clear error."""
501+
# Use a small file for the test
502+
large_data = b"x" * 1000
503+
inline_data = types.Blob(
504+
display_name="huge_video.mp4",
505+
data=large_data,
506+
mime_type="video/mp4",
507+
)
508+
user_message = types.Content(parts=[types.Part(inline_data=inline_data)])
509+
510+
# Patch the size limit to be smaller than the file data
511+
with patch(
512+
"google.adk.plugins.save_files_as_artifacts_plugin._MAX_FILES_API_SIZE_BYTES", 500
513+
):
514+
result = await self.plugin.on_user_message_callback(
515+
invocation_context=self.mock_context, user_message=user_message
534516
)
535-
return await original_callback(
536-
invocation_context=invocation_context, user_message=user_message
537-
)
538-
539-
self.plugin.on_user_message_callback = patched_callback
540-
541-
result = await self.plugin.on_user_message_callback(
542-
invocation_context=self.mock_context, user_message=user_message
543-
)
544517

545-
# Should not attempt any upload
546-
self.mock_context.artifact_service.save_artifact.assert_not_called()
518+
# Should not attempt any upload
519+
self.mock_context.artifact_service.save_artifact.assert_not_called()
547520

548-
# Should return error message about 2GB limit
549-
assert result is not None
550-
assert len(result.parts) == 1
551-
assert "[Upload Error:" in result.parts[0].text
552-
assert "huge_video.mp4" in result.parts[0].text
553-
assert "2.00 GB" in result.parts[0].text
554-
assert "exceeds the maximum supported size" in result.parts[0].text
521+
# Should return error message about the limit
522+
assert result is not None
523+
assert len(result.parts) == 1
524+
assert "[Upload Error:" in result.parts[0].text
525+
assert "huge_video.mp4" in result.parts[0].text
526+
# Note: This assertion will depend on fixing the hardcoded "2GB" in the error message.
527+
assert "exceeds the maximum supported size" in result.parts[0].text

0 commit comments

Comments
 (0)