fix(discord): preserve native document and video attachment support

Salvaged from PR #1115 onto current main by reusing the shared
Discord file-attachment helper for local video and document sends,
including file_name support for documents and regression coverage.
This commit is contained in:
halfprice06
2026-03-14 22:01:02 -07:00
committed by teknium1
parent 6761021fb4
commit 9a177d6f4b
2 changed files with 88 additions and 1 deletions

View File

@@ -669,6 +669,7 @@ class DiscordAdapter(BasePlatformAdapter):
chat_id: str,
file_path: str,
caption: Optional[str] = None,
file_name: Optional[str] = None,
) -> SendResult:
"""Send a local file as a Discord attachment."""
if not self._client:
@@ -680,7 +681,7 @@ class DiscordAdapter(BasePlatformAdapter):
if not channel:
return SendResult(success=False, error=f"Channel {chat_id} not found")
filename = os.path.basename(file_path)
filename = file_name or os.path.basename(file_path)
with open(file_path, "rb") as fh:
file = discord.File(fh, filename=filename)
msg = await channel.send(content=caption if caption else None, file=file)
@@ -1141,6 +1142,41 @@ class DiscordAdapter(BasePlatformAdapter):
exc_info=True,
)
return await super().send_image(chat_id, image_url, caption, reply_to)
async def send_video(
self,
chat_id: str,
video_path: str,
caption: Optional[str] = None,
reply_to: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> SendResult:
"""Send a local video file natively as a Discord attachment."""
try:
return await self._send_file_attachment(chat_id, video_path, caption)
except FileNotFoundError:
return SendResult(success=False, error=f"Video file not found: {video_path}")
except Exception as e: # pragma: no cover - defensive logging
logger.error("[%s] Failed to send local video, falling back to base adapter: %s", self.name, e, exc_info=True)
return await super().send_video(chat_id, video_path, caption, reply_to, metadata=metadata)
async def send_document(
self,
chat_id: str,
file_path: str,
caption: Optional[str] = None,
file_name: Optional[str] = None,
reply_to: Optional[str] = None,
metadata: Optional[Dict[str, Any]] = None,
) -> SendResult:
"""Send an arbitrary file natively as a Discord attachment."""
try:
return await self._send_file_attachment(chat_id, file_path, caption, file_name=file_name)
except FileNotFoundError:
return SendResult(success=False, error=f"File not found: {file_path}")
except Exception as e: # pragma: no cover - defensive logging
logger.error("[%s] Failed to send document, falling back to base adapter: %s", self.name, e, exc_info=True)
return await super().send_document(chat_id, file_path, caption, file_name, reply_to, metadata=metadata)
async def send_typing(self, chat_id: str, metadata=None) -> None:
"""Send typing indicator."""

View File

@@ -199,6 +199,57 @@ class TestDiscordSendImageFile:
assert result.message_id == "99"
mock_channel.send.assert_awaited_once()
def test_send_document_uploads_file_attachment(self, adapter, tmp_path):
"""send_document should upload a native Discord attachment."""
pdf = tmp_path / "sample.pdf"
pdf.write_bytes(b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n")
mock_channel = MagicMock()
mock_msg = MagicMock()
mock_msg.id = 100
mock_channel.send = AsyncMock(return_value=mock_msg)
adapter._client.get_channel = MagicMock(return_value=mock_channel)
with patch.object(discord_mod_ref, "File", MagicMock()) as file_cls:
result = _run(
adapter.send_document(
chat_id="67890",
file_path=str(pdf),
file_name="renamed.pdf",
metadata={"thread_id": "123"},
)
)
assert result.success
assert result.message_id == "100"
assert "file" in mock_channel.send.call_args.kwargs
assert file_cls.call_args.kwargs["filename"] == "renamed.pdf"
def test_send_video_uploads_file_attachment(self, adapter, tmp_path):
"""send_video should upload a native Discord attachment."""
video = tmp_path / "clip.mp4"
video.write_bytes(b"\x00\x00\x00\x18ftypmp42" + b"\x00" * 50)
mock_channel = MagicMock()
mock_msg = MagicMock()
mock_msg.id = 101
mock_channel.send = AsyncMock(return_value=mock_msg)
adapter._client.get_channel = MagicMock(return_value=mock_channel)
with patch.object(discord_mod_ref, "File", MagicMock()) as file_cls:
result = _run(
adapter.send_video(
chat_id="67890",
video_path=str(video),
metadata={"thread_id": "123"},
)
)
assert result.success
assert result.message_id == "101"
assert "file" in mock_channel.send.call_args.kwargs
assert file_cls.call_args.kwargs["filename"] == "clip.mp4"
def test_returns_error_when_file_missing(self, adapter):
result = _run(
adapter.send_image_file(chat_id="67890", image_path="/nonexistent.png")