diff --git a/llm/models.py b/llm/models.py index 1c149127b..de66cf8de 100644 --- a/llm/models.py +++ b/llm/models.py @@ -91,7 +91,7 @@ def resolve_type(self): if self.path: return mimetype_from_path(self.path) if self.url: - response = httpx.head(self.url) + response = httpx.head(self.url, follow_redirects=True) response.raise_for_status() return response.headers.get("content-type") if self.content: @@ -105,7 +105,7 @@ def content_bytes(self): if self.path: content = Path(self.path).read_bytes() elif self.url: - response = httpx.get(self.url) + response = httpx.get(self.url, follow_redirects=True) response.raise_for_status() content = response.content return content diff --git a/tests/test_attachments.py b/tests/test_attachments.py index d523e4745..edcdb9321 100644 --- a/tests/test_attachments.py +++ b/tests/test_attachments.py @@ -97,3 +97,33 @@ def test_attachment_no_file_descriptor_leak(tmp_path): # File descriptor count should not have grown significantly assert _count_open_fds() <= baseline + 5 + + +def test_attachment_content_bytes_follows_redirects(httpx_mock): + httpx_mock.add_response( + url="https://example.com/redirected.png", + status_code=301, + headers={"Location": "https://example.com/actual.png"}, + ) + httpx_mock.add_response( + url="https://example.com/actual.png", + content=TINY_PNG, + ) + attachment = llm.Attachment(url="https://example.com/redirected.png") + assert attachment.content_bytes() == TINY_PNG + + +def test_attachment_resolve_type_follows_redirects(httpx_mock): + httpx_mock.add_response( + method="HEAD", + url="https://example.com/redirected.png", + status_code=301, + headers={"Location": "https://example.com/actual.png"}, + ) + httpx_mock.add_response( + method="HEAD", + url="https://example.com/actual.png", + headers={"content-type": "image/png"}, + ) + attachment = llm.Attachment(url="https://example.com/redirected.png") + assert attachment.resolve_type() == "image/png"