Skip to main content

vtcode_core/llm/
error_display.rs

1//! LLM error display utilities with enhanced ANSI color support
2//!
3//! This module provides enhanced error display capabilities for LLM providers
4//! using standard console styling for consistent terminal output.
5
6use crate::ui::styled::Styles;
7use anstyle::Style;
8use vtcode_commons::color_policy;
9
10/// Internal helper to wrap text with style codes - reduces duplication
11#[inline]
12fn style_text(style: Style, text: &str) -> String {
13    if !color_policy::color_output_enabled() {
14        return text.to_string();
15    }
16    format!(
17        "{}{}{}",
18        Styles::render(&style),
19        text,
20        Styles::render_reset()
21    )
22}
23
24/// Get a styled error message with enhanced coloring
25#[cold]
26pub fn style_llm_error(message: &str) -> String {
27    style_text(Styles::error(), message)
28}
29
30/// Get a styled warning message with enhanced coloring
31#[cold]
32pub fn style_llm_warning(message: &str) -> String {
33    style_text(Styles::warning(), message)
34}
35
36/// Get a styled success message with enhanced coloring
37#[inline]
38pub fn style_llm_success(message: &str) -> String {
39    style_text(Styles::success(), message)
40}
41
42/// Get a styled provider name with enhanced coloring based on provider type
43pub fn style_provider_name(provider: &str) -> String {
44    let style = match provider.to_lowercase().as_str() {
45        "gemini" => Styles::info(),    // Deep blue for Gemini
46        "openai" => Styles::warning(), // Bright orange for OpenAI
47        "anthropic" => Styles::code(), // Anthropic's brand purple
48        _ => Styles::debug(),          // Default styling for other providers
49    };
50    style_text(style, provider)
51}
52
53/// Format an LLM error for display with enhanced coloring
54#[cold]
55pub fn format_llm_error(provider: &str, error: &str) -> String {
56    let provider_styled = style_provider_name(provider);
57    let error_styled = style_llm_error(error);
58    format!("{} {}", provider_styled, error_styled)
59}
60
61/// Format an LLM warning for display with enhanced coloring
62#[cold]
63pub fn format_llm_warning(provider: &str, warning: &str) -> String {
64    let provider_styled = style_provider_name(provider);
65    let warning_styled = style_llm_warning(warning);
66    format!("{} {}", provider_styled, warning_styled)
67}
68
69/// Format an LLM success message for display with enhanced coloring
70pub fn format_llm_success(provider: &str, message: &str) -> String {
71    let provider_styled = style_provider_name(provider);
72    let success_styled = style_llm_success(message);
73    format!("{} {}", provider_styled, success_styled)
74}
75
76/// Format a network error for display with enhanced coloring.
77/// This is a convenience wrapper for the common "Network error: {}" pattern.
78#[cold]
79pub fn format_network_error(provider: &str, error: &impl std::fmt::Display) -> String {
80    format_llm_error(provider, &format!("Network error: {}", error))
81}
82
83/// Format a parse error for display with enhanced coloring.
84/// This is a convenience wrapper for the common "Parse error: {}" pattern.
85#[cold]
86pub fn format_parse_error(provider: &str, error: &impl std::fmt::Display) -> String {
87    format_llm_error(provider, &format!("Parse error: {}", error))
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_style_llm_error() {
96        let result = style_llm_error("Test error");
97        assert!(!result.is_empty());
98    }
99
100    #[test]
101    fn test_style_llm_warning() {
102        let result = style_llm_warning("Test warning");
103        assert!(!result.is_empty());
104    }
105
106    #[test]
107    fn test_style_llm_success() {
108        let result = style_llm_success("Test success");
109        assert!(!result.is_empty());
110    }
111
112    #[test]
113    fn test_style_provider_name() {
114        let providers = vec![
115            "gemini",
116            "openai",
117            "anthropic",
118            "ollama",
119            "lmstudio",
120            "unknown",
121        ];
122        for provider in providers {
123            let result = style_provider_name(provider);
124            assert!(!result.is_empty());
125        }
126    }
127
128    #[test]
129    fn test_format_llm_error() {
130        let result = format_llm_error("gemini", "Connection failed");
131        assert!(result.contains("gemini"));
132        assert!(result.contains("Connection failed"));
133    }
134
135    #[test]
136    fn test_format_llm_warning() {
137        let result = format_llm_warning("openai", "Rate limit approaching");
138        assert!(result.contains("openai"));
139        assert!(result.contains("Rate limit approaching"));
140    }
141
142    #[test]
143    fn test_format_llm_success() {
144        let result = format_llm_success("anthropic", "Request completed");
145        assert!(result.contains("anthropic"));
146        assert!(result.contains("Request completed"));
147    }
148}