gemini_adk_rs/utils/
variant.rs

1/// The backend variant for Google LLM access.
2#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3pub enum GoogleLlmVariant {
4    /// Vertex AI (enterprise, project-based).
5    VertexAi,
6    /// Gemini API (API-key based, consumer).
7    GeminiApi,
8}
9
10/// Determine the Google LLM variant from the environment.
11///
12/// Reads the `GOOGLE_GENAI_USE_VERTEXAI` environment variable.
13/// Returns [`GoogleLlmVariant::VertexAi`] when the variable is set to a
14/// truthy value (`"true"`, `"1"`, case-insensitive), and
15/// [`GoogleLlmVariant::GeminiApi`] otherwise (including when the variable
16/// is unset).
17pub fn get_google_llm_variant() -> GoogleLlmVariant {
18    classify(std::env::var("GOOGLE_GENAI_USE_VERTEXAI").ok().as_deref())
19}
20
21/// The rule itself, separated from where the value comes from.
22///
23/// This exists so the rule can be tested without touching the process
24/// environment. Environment variables are global mutable state shared by every
25/// thread in the test binary, and `cargo test` runs tests in parallel: a set of
26/// tests that each set the same variable and then read it back will pass
27/// locally for months and fail on a busier machine, having read a value another
28/// test wrote microseconds earlier.
29fn classify(value: Option<&str>) -> GoogleLlmVariant {
30    match value {
31        Some(value) => {
32            let lower = value.to_lowercase();
33            if lower == "true" || lower == "1" {
34                GoogleLlmVariant::VertexAi
35            } else {
36                GoogleLlmVariant::GeminiApi
37            }
38        }
39        None => GoogleLlmVariant::GeminiApi,
40    }
41}
42
43#[cfg(test)]
44#[allow(
45    unsafe_code,
46    reason = "tests exercise env-driven platform detection and must mutate the process environment"
47)]
48mod tests {
49    use super::*;
50
51    /// The rule, exhaustively, with no global state involved.
52    ///
53    /// These replace seven tests that each set `GOOGLE_GENAI_USE_VERTEXAI` and
54    /// read it back. That worked whenever the scheduler happened to keep them
55    /// apart and failed when it did not — on CI, `vertex_ai_true_lowercase`
56    /// asserted `VertexAi` and got `GeminiApi`, having read the value a
57    /// concurrent test had just written. The helper's own comment argued it was
58    /// safe "because each test uses a unique value"; the values were unique but
59    /// the *variable* was one, shared by every thread in the binary.
60    #[test]
61    fn truthy_values_select_vertex() {
62        for value in ["true", "TRUE", "True", "1"] {
63            assert_eq!(
64                classify(Some(value)),
65                GoogleLlmVariant::VertexAi,
66                "{value:?} should select Vertex"
67            );
68        }
69    }
70
71    #[test]
72    fn everything_else_selects_the_gemini_api() {
73        for value in ["false", "0", "", "yes", "vertex", "TRUEISH"] {
74            assert_eq!(
75                classify(Some(value)),
76                GoogleLlmVariant::GeminiApi,
77                "{value:?} should select the Gemini API"
78            );
79        }
80    }
81
82    #[test]
83    fn an_unset_variable_selects_the_gemini_api() {
84        assert_eq!(classify(None), GoogleLlmVariant::GeminiApi);
85    }
86
87    /// One test that the wiring reads the variable at all.
88    ///
89    /// Deliberately the only test in this module that touches the environment,
90    /// which is what makes it safe: with a single writer there is nobody to
91    /// race. It asserts the plumbing, not the rule — the rule is covered above.
92    #[test]
93    fn the_variable_is_the_one_that_is_read() {
94        let restore = std::env::var("GOOGLE_GENAI_USE_VERTEXAI").ok();
95        unsafe { std::env::set_var("GOOGLE_GENAI_USE_VERTEXAI", "true") };
96        let observed = get_google_llm_variant();
97        match restore {
98            Some(value) => unsafe { std::env::set_var("GOOGLE_GENAI_USE_VERTEXAI", value) },
99            None => unsafe { std::env::remove_var("GOOGLE_GENAI_USE_VERTEXAI") },
100        }
101        assert_eq!(observed, GoogleLlmVariant::VertexAi);
102    }
103}