From 50c75d9e68baf07373b2b3c12b05caa1a465b675 Mon Sep 17 00:00:00 2001 From: Mouse Date: Wed, 6 May 2026 01:50:37 -0700 Subject: [PATCH] feat: harden HTTP provider plain-text response handling --- promptlens/providers/http.py | 18 ++++++++++++++---- tests/test_http_provider_response_parsing.py | 6 ++++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/promptlens/providers/http.py b/promptlens/providers/http.py index f1828e2..be7033d 100644 --- a/promptlens/providers/http.py +++ b/promptlens/providers/http.py @@ -5,6 +5,7 @@ from typing import Any, Dict, List, Optional import aiohttp +from aiohttp import ContentTypeError from promptlens.models.config import ProviderConfig from promptlens.models.result import ModelResponse @@ -59,6 +60,11 @@ def _extract_content(data: Dict[str, Any]) -> str: return "" + @staticmethod + def _extract_content_from_text_response(text: str) -> str: + """Extract usable content from plain-text HTTP responses.""" + return text.strip() + def __init__(self, config: ProviderConfig) -> None: """Initialize the HTTP provider. @@ -119,10 +125,14 @@ async def _make_request() -> ModelResponse: timeout=aiohttp.ClientTimeout(total=self.config.timeout), ) as response: response.raise_for_status() - data = await response.json() - - # Extract content (try common response formats) - content = self._extract_content(data) + try: + data = await response.json() + content = self._extract_content(data) + except ContentTypeError: + text = await response.text() + content = self._extract_content_from_text_response(text) + + # Extracted content from JSON shape or plain text body. # Local models typically don't provide token counts or cost return ModelResponse( diff --git a/tests/test_http_provider_response_parsing.py b/tests/test_http_provider_response_parsing.py index 0949b6e..8d82f20 100644 --- a/tests/test_http_provider_response_parsing.py +++ b/tests/test_http_provider_response_parsing.py @@ -57,3 +57,9 @@ def test_extract_content_returns_empty_for_unknown_shape() -> None: provider = _provider() assert provider._extract_content({"foo": "bar"}) == "" + + +def test_extract_content_from_text_response_strips_whitespace() -> None: + provider = _provider() + + assert provider._extract_content_from_text_response(" hello world\n") == "hello world"