Coverage for src/local_deep_research/error_handling/error_messages.py: 100%

14 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-22 21:20 +0000

1"""Authored research failure messages shared by reports and API responses.""" 

2 

3# Regex classification is advisory: inspect a short prefix of provider error 

4# text, which can otherwise contain entire response bodies. Even a 4 KiB 

5# prefix takes seconds on repeated partial matches of the multi-span patterns. 

6MAX_ERROR_CLASSIFICATION_CHARS = 1024 

7 

8TYPED_RESEARCH_ERROR_MESSAGES = { 

9 "ollama_unavailable": "Ollama AI service is unavailable.", 

10 "model_not_found": "The configured LLM model was not found.", 

11 "connection_error": "Could not connect to the configured LLM server.", 

12 "api_error": "The language model API rejected the request.", 

13 "openai_connection_refused": "Could not connect to the configured LLM endpoint.", 

14 "openai_timeout": "The configured LLM endpoint timed out.", 

15 "openai_auth": "Authentication with the LLM provider failed.", 

16 "openai_permission_denied": "The LLM provider denied access to the model.", 

17 "openai_model_not_found": "The configured model was not found at the LLM endpoint.", 

18 "openai_bad_request": "The LLM endpoint rejected the request.", 

19 "openai_unknown": "The configured LLM provider returned an error.", 

20 "openai_rate_limit": "The LLM provider rate-limited the request.", 

21} 

22 

23_SAFE_WORKER_MESSAGES = frozenset(TYPED_RESEARCH_ERROR_MESSAGES.values()) | { 

24 # Keep authored messages from older saved reports recognizable. 

25 "The configured LLM server timed out.", 

26 "The LLM server rejected the request.", 

27 "Ollama AI service is unavailable. Please check that Ollama is running properly on your system.", 

28 "Required Ollama model not found. Please pull the model first.", 

29 "Connection error with LLM service. Please check that your AI service is running.", 

30 "Authentication with the configured LLM provider failed.", 

31 "The configured LLM provider denied access to the model.", 

32 "The configured model was not found on the LLM server.", 

33 "There was a problem with the LLM configuration.", 

34 "There was a problem with the search engine configuration.", 

35 "Egress policy could not verify this run, so it was refused (fail-closed).", 

36} 

37 

38 

39def get_known_research_error_message(error_message: object) -> str | None: 

40 """Return authored guidance, or None when the stored text is untrusted. 

41 

42 A worker message is safe only when it matches exactly: appended provider 

43 details must not pass through. Policy refusals carry an internal reason 

44 suffix, so replace those with fixed text rather than returning the input. 

45 """ 

46 if not isinstance(error_message, str): 

47 return None 

48 message = error_message.removeprefix("Research failed: ") 

49 if message in _SAFE_WORKER_MESSAGES: 

50 return message 

51 if message.startswith("Egress policy refused this run: a sensitive source"): 

52 return ( 

53 "Egress policy refused this run: a sensitive source would " 

54 "reach an exposing destination." 

55 ) 

56 if message.startswith("Egress policy refused this run"): 

57 return "Egress policy refused this run." 

58 return None