Skip to main content

gproxy_protocol/transform/gemini/model_list/claude/
utils.rs

1use http::StatusCode;
2
3use crate::claude::types::{BetaError, BetaErrorResponse, BetaModelInfo};
4use crate::gemini::types::{GeminiApiError, GeminiApiErrorResponse, GeminiModelInfo};
5
6fn ensure_models_prefix(value: &str) -> String {
7    if value.starts_with("models/") {
8        value.to_string()
9    } else {
10        format!("models/{value}")
11    }
12}
13
14fn gemini_status_from_claude_error(error: &BetaError) -> Option<String> {
15    let status = match error {
16        BetaError::InvalidRequest(_) => "INVALID_ARGUMENT",
17        BetaError::Authentication(_) => "UNAUTHENTICATED",
18        BetaError::Billing(_) => "FAILED_PRECONDITION",
19        BetaError::Permission(_) => "PERMISSION_DENIED",
20        BetaError::NotFound(_) => "NOT_FOUND",
21        BetaError::RateLimit(_) => "RESOURCE_EXHAUSTED",
22        BetaError::GatewayTimeout(_) => "DEADLINE_EXCEEDED",
23        BetaError::Api(_) => "INTERNAL",
24        BetaError::Overloaded(_) => "UNAVAILABLE",
25    };
26    Some(status.to_string())
27}
28
29fn claude_error_message(error: &BetaError) -> String {
30    match error {
31        BetaError::InvalidRequest(err) => err.message.clone(),
32        BetaError::Authentication(err) => err.message.clone(),
33        BetaError::Billing(err) => err.message.clone(),
34        BetaError::Permission(err) => err.message.clone(),
35        BetaError::NotFound(err) => err.message.clone(),
36        BetaError::RateLimit(err) => err.message.clone(),
37        BetaError::GatewayTimeout(err) => err.message.clone(),
38        BetaError::Api(err) => err.message.clone(),
39        BetaError::Overloaded(err) => err.message.clone(),
40    }
41}
42
43pub fn gemini_model_info_from_claude_model(model: BetaModelInfo) -> GeminiModelInfo {
44    GeminiModelInfo {
45        name: ensure_models_prefix(&model.id),
46        base_model_id: Some(model.id),
47        version: None,
48        display_name: if model.display_name.is_empty() {
49            None
50        } else {
51            Some(model.display_name)
52        },
53        description: None,
54        input_token_limit: None,
55        output_token_limit: None,
56        supported_generation_methods: None,
57        thinking: None,
58        temperature: None,
59        max_temperature: None,
60        top_p: None,
61        top_k: None,
62    }
63}
64
65pub fn gemini_error_response_from_claude(
66    status_code: StatusCode,
67    body: BetaErrorResponse,
68) -> GeminiApiErrorResponse {
69    GeminiApiErrorResponse {
70        error: GeminiApiError {
71            code: i32::from(status_code.as_u16()),
72            message: claude_error_message(&body.error),
73            status: gemini_status_from_claude_error(&body.error),
74            details: None,
75        },
76    }
77}