1use serde::{Deserialize, Serialize};
11
12#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
15#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
16pub struct AuthMetadata {
17 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub account_id: Option<String>,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub workspace_id: Option<String>,
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub organization_id: Option<String>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 pub user_id: Option<String>,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 pub plan: Option<String>,
27 #[serde(default)]
28 pub route_hints: AuthRouteHints,
29 #[serde(default, skip_serializing_if = "Option::is_none")]
30 pub provider_metadata: Option<ProviderAuthMetadata>,
31}
32
33#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
35#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
36pub struct AuthMetadataDefaults {
37 #[serde(default, skip_serializing_if = "Option::is_none")]
38 pub organization_id: Option<String>,
39 #[serde(default, skip_serializing_if = "Option::is_none")]
40 pub workspace_id: Option<String>,
41 #[serde(default)]
42 pub route_hints: AuthRouteHints,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub provider_metadata: Option<ProviderAuthMetadata>,
45}
46
47#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
49#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
50#[serde(tag = "provider", rename_all = "snake_case")]
51pub enum AuthRouteHints {
52 #[default]
53 None,
54 OpenAi(Box<OpenAiRouteHints>),
55 Anthropic(Box<AnthropicRouteHints>),
56 Google(Box<GoogleRouteHints>),
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
61#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
62#[serde(tag = "provider", rename_all = "snake_case")]
63pub enum ProviderAuthMetadata {
64 OpenAi(OpenAiAuthMetadata),
65 Anthropic(AnthropicAuthMetadata),
66 Google(GoogleAuthMetadata),
67}
68
69#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
74#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
75#[non_exhaustive]
76pub struct OpenAiRouteHints {}
77
78#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
79#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
80#[non_exhaustive]
81pub struct AnthropicRouteHints {}
82
83#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
84#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
85#[non_exhaustive]
86pub struct GoogleRouteHints {}
87
88#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
91#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
92pub struct OpenAiAuthMetadata {
93 #[serde(default, skip_serializing_if = "Option::is_none")]
95 pub plan_type: Option<String>,
96 #[serde(default, skip_serializing_if = "Option::is_none")]
98 pub user_id: Option<String>,
99 #[serde(default, skip_serializing_if = "Option::is_none")]
101 pub account_id: Option<String>,
102 #[serde(default, skip_serializing_if = "Option::is_none")]
104 pub is_fedramp: Option<bool>,
105 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub email: Option<String>,
108}
109
110#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
113#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
114pub struct AnthropicAuthMetadata {
115 #[serde(default, skip_serializing_if = "Option::is_none")]
117 pub subscription_tier: Option<String>,
118 #[serde(default, skip_serializing_if = "Option::is_none")]
120 pub aws_region: Option<String>,
121 #[serde(default, skip_serializing_if = "Option::is_none")]
123 pub vertex_project_id: Option<String>,
124 #[serde(default, skip_serializing_if = "Option::is_none")]
126 pub vertex_region: Option<String>,
127 #[serde(default, skip_serializing_if = "Option::is_none")]
129 pub foundry_deployment: Option<String>,
130}
131
132#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
134#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
135pub struct GoogleAuthMetadata {
136 #[serde(default, skip_serializing_if = "Option::is_none")]
138 pub account_email: Option<String>,
139 #[serde(default, skip_serializing_if = "Option::is_none")]
141 pub project_id: Option<String>,
142 #[serde(default, skip_serializing_if = "Option::is_none")]
144 pub region: Option<String>,
145 #[serde(default, skip_serializing_if = "Option::is_none")]
147 pub code_assist_tier: Option<String>,
148}
149
150#[cfg(test)]
151#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn auth_metadata_default_is_empty() {
157 let m = AuthMetadata::default();
158 assert!(m.account_id.is_none());
159 assert_eq!(m.route_hints, AuthRouteHints::None);
160 assert!(m.provider_metadata.is_none());
161 }
162
163 #[test]
164 fn route_hints_serde_roundtrip() {
165 for hints in [
166 AuthRouteHints::None,
167 AuthRouteHints::OpenAi(Box::default()),
168 AuthRouteHints::Anthropic(Box::default()),
169 AuthRouteHints::Google(Box::default()),
170 ] {
171 let s = serde_json::to_string(&hints).unwrap();
172 let back: AuthRouteHints = serde_json::from_str(&s).unwrap();
173 assert_eq!(back, hints);
174 }
175 }
176
177 #[test]
178 fn provider_auth_metadata_roundtrip() {
179 let m = ProviderAuthMetadata::OpenAi(OpenAiAuthMetadata::default());
180 let s = serde_json::to_string(&m).unwrap();
181 let back: ProviderAuthMetadata = serde_json::from_str(&s).unwrap();
182 assert_eq!(back, m);
183 }
184}