kcode_gemini_api/
error.rs1use std::{error::Error as StdError, fmt};
2
3use crate::{LimitPeriod, Money};
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Debug)]
10pub enum Error {
11 InvalidApiKey,
13 InvalidInput(String),
15 Accounting(String),
17 Transport(String),
19 Provider {
21 status: u16,
23 code: Option<String>,
25 message: String,
27 },
28 Protocol(String),
30 SpendingLimitReached {
32 period: LimitPeriod,
34 limit: Money,
36 spent: Money,
38 },
39}
40
41impl fmt::Display for Error {
42 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 Self::InvalidApiKey => f.write_str("the Gemini API key is empty or invalid"),
45 Self::InvalidInput(message) => write!(f, "invalid Gemini request: {message}"),
46 Self::Accounting(message) => write!(f, "Gemini accounting failed: {message}"),
47 Self::Transport(message) => write!(f, "Gemini transport failed: {message}"),
48 Self::Provider {
49 status,
50 code,
51 message,
52 } => match code {
53 Some(code) => write!(f, "Gemini returned HTTP {status} ({code}): {message}"),
54 None => write!(f, "Gemini returned HTTP {status}: {message}"),
55 },
56 Self::Protocol(message) => write!(f, "invalid Gemini response: {message}"),
57 Self::SpendingLimitReached {
58 period,
59 limit,
60 spent,
61 } => write!(
62 f,
63 "Gemini {period} spending limit reached (spent {spent}, limit {limit})"
64 ),
65 }
66 }
67}
68
69impl StdError for Error {}
70
71pub(crate) fn transport(error: impl fmt::Display) -> Error {
72 let message = error.to_string();
73 Error::Transport(if message.to_ascii_lowercase().contains("timed out") {
74 "the request timed out".into()
75 } else {
76 "the service could not be reached".into()
77 })
78}
79
80pub(crate) fn clean_message(value: &str, limit: usize) -> String {
81 let value = value
82 .chars()
83 .map(|character| {
84 if character.is_control() {
85 ' '
86 } else {
87 character
88 }
89 })
90 .take(limit)
91 .collect::<String>()
92 .split_whitespace()
93 .collect::<Vec<_>>()
94 .join(" ");
95 if value.is_empty() {
96 "unknown error".into()
97 } else {
98 value
99 }
100}