Surface deep research probe errors (#1086)
Co-authored-by: ghreprimand <203024559+ghreprimand@users.noreply.github.com>
This commit is contained in:
@@ -30,6 +30,24 @@ def _bounded_int(value, *, default: int, minimum: int, maximum: int) -> int:
|
||||
return max(minimum, min(maximum, n))
|
||||
|
||||
|
||||
def _format_probe_failure(model: str, exc: Exception) -> str:
|
||||
"""Turn a failed research model probe into a user-facing message."""
|
||||
detail = getattr(exc, "detail", None)
|
||||
status = getattr(exc, "status_code", None)
|
||||
err = str(detail if detail is not None else exc).strip()
|
||||
|
||||
if status in {401, 403} or "401" in err or "API key" in err or "Unauthorized" in err:
|
||||
return f"Model '{model}' requires an API key. Check your endpoint configuration."
|
||||
|
||||
if status and err:
|
||||
return f"Model '{model}' probe failed: {err}"
|
||||
|
||||
if err:
|
||||
return f"Cannot reach model '{model}' — {err}"
|
||||
|
||||
return f"Cannot reach model '{model}' — check that the endpoint is running and accessible."
|
||||
|
||||
|
||||
class ResearchHandler:
|
||||
"""Handles research service operations with iterative deep research."""
|
||||
|
||||
@@ -634,14 +652,7 @@ class ResearchHandler:
|
||||
logger.info(f"Endpoint probe OK: {model}")
|
||||
except Exception as e:
|
||||
logger.error(f"Probe failed for {model}: {e}")
|
||||
err = str(e)
|
||||
if "401" in err or "API key" in err or "Unauthorized" in err:
|
||||
raise RuntimeError(
|
||||
f"Model '{model}' requires an API key. Check your endpoint configuration."
|
||||
) from e
|
||||
raise RuntimeError(
|
||||
f"Cannot reach model '{model}' — check that the endpoint is running and accessible."
|
||||
) from e
|
||||
raise RuntimeError(_format_probe_failure(model, e)) from e
|
||||
|
||||
async def call_research_service(
|
||||
self,
|
||||
|
||||
61
tests/test_research_probe_errors.py
Normal file
61
tests/test_research_probe_errors.py
Normal file
@@ -0,0 +1,61 @@
|
||||
"""Regression tests for Deep Research model probe error messages.
|
||||
|
||||
Deep Research probes the selected model before starting a long run. When the
|
||||
upstream returned a concrete model/API error, the probe used to collapse it into
|
||||
"Cannot reach model", hiding the real issue from the UI.
|
||||
"""
|
||||
import pytest
|
||||
from fastapi import HTTPException
|
||||
|
||||
from src.research_handler import ResearchHandler, _format_probe_failure
|
||||
|
||||
|
||||
def test_probe_failure_preserves_upstream_model_errors():
|
||||
exc = HTTPException(
|
||||
status_code=400,
|
||||
detail="OpenAI returned HTTP 400: Unsupported parameter: temperature",
|
||||
)
|
||||
|
||||
msg = _format_probe_failure("o3-mini", exc)
|
||||
|
||||
assert msg == (
|
||||
"Model 'o3-mini' probe failed: "
|
||||
"OpenAI returned HTTP 400: Unsupported parameter: temperature"
|
||||
)
|
||||
|
||||
|
||||
def test_probe_failure_keeps_api_key_guidance():
|
||||
exc = HTTPException(status_code=401, detail="OpenAI authentication failed")
|
||||
|
||||
assert _format_probe_failure("gpt-4o", exc) == (
|
||||
"Model 'gpt-4o' requires an API key. Check your endpoint configuration."
|
||||
)
|
||||
|
||||
|
||||
def test_probe_failure_keeps_reachability_guidance_for_plain_errors():
|
||||
msg = _format_probe_failure("local-model", RuntimeError("connection refused"))
|
||||
|
||||
assert msg == "Cannot reach model 'local-model' — connection refused"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_probe_endpoint_surfaces_http_exception_detail(monkeypatch):
|
||||
async def _raise(*args, **kwargs):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="OpenAI returned HTTP 400: max_tokens is not supported",
|
||||
)
|
||||
|
||||
monkeypatch.setattr("src.llm_core.llm_call_async", _raise)
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
await ResearchHandler._probe_endpoint(
|
||||
"https://api.openai.com/v1/chat/completions",
|
||||
"o3-mini",
|
||||
{"Authorization": "Bearer test"},
|
||||
)
|
||||
|
||||
msg = str(excinfo.value)
|
||||
assert "Model 'o3-mini' probe failed" in msg
|
||||
assert "max_tokens is not supported" in msg
|
||||
assert "Cannot reach model" not in msg
|
||||
Reference in New Issue
Block a user