gproxy_protocol/protocol/
operation.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum Provider {
12 OpenAi,
13 Claude,
14 Gemini,
15}
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
19#[serde(rename_all = "snake_case")]
20pub enum OperationGroup {
21 Models,
22 CountTokens,
23 GenerateContent,
24 Images,
25 Embeddings,
26 Compact,
27 Conversation,
28 Realtime,
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
37#[serde(rename_all = "snake_case")]
38pub enum Operation {
39 ListModels,
40 GetModel,
41 CountTokens,
42 GenerateContent,
43 StreamGenerateContent,
44 CreateImage,
45 EditImage,
46 CreateEmbedding,
47 CompactContent,
48 CreateConversation,
49 ConnectRealtime,
50}
51
52impl Operation {
53 pub const fn group(self) -> OperationGroup {
55 match self {
56 Self::ListModels | Self::GetModel => OperationGroup::Models,
57 Self::CountTokens => OperationGroup::CountTokens,
58 Self::GenerateContent | Self::StreamGenerateContent => OperationGroup::GenerateContent,
59 Self::CreateImage | Self::EditImage => OperationGroup::Images,
60 Self::CreateEmbedding => OperationGroup::Embeddings,
61 Self::CompactContent => OperationGroup::Compact,
62 Self::CreateConversation => OperationGroup::Conversation,
63 Self::ConnectRealtime => OperationGroup::Realtime,
64 }
65 }
66
67 pub const fn has_request_body(self) -> bool {
69 !matches!(
70 self,
71 Self::ListModels | Self::GetModel | Self::ConnectRealtime
72 )
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
82#[serde(untagged)]
83pub enum OperationKind {
84 ContentGeneration(ContentGenerationKind),
85 Provider(Provider),
86}
87
88impl OperationKind {
89 pub const fn provider(self) -> Provider {
90 match self {
91 Self::ContentGeneration(kind) => kind.provider(),
92 Self::Provider(provider) => provider,
93 }
94 }
95
96 pub const fn is_content_generation(self) -> bool {
97 matches!(self, Self::ContentGeneration(_))
98 }
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
103#[serde(rename_all = "snake_case")]
104pub enum ContentGenerationKind {
105 OpenAiResponses,
106 #[serde(rename = "open_ai_responses_websocket")]
107 OpenAiResponsesWebSocket,
108 OpenAiChatCompletions,
109 ClaudeMessages,
110 GeminiGenerateContent,
111}
112
113impl ContentGenerationKind {
114 pub const fn provider(self) -> Provider {
115 match self {
116 Self::OpenAiResponses
117 | Self::OpenAiResponsesWebSocket
118 | Self::OpenAiChatCompletions => Provider::OpenAi,
119 Self::ClaudeMessages => Provider::Claude,
120 Self::GeminiGenerateContent => Provider::Gemini,
121 }
122 }
123}
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
127pub struct OperationKey {
128 pub operation: Operation,
129 pub kind: OperationKind,
130}
131
132impl OperationKey {
133 pub fn content_generation(operation: Operation, kind: ContentGenerationKind) -> Self {
134 debug_assert!(
135 operation.is_content_generation(),
136 "content-generation kind used with non-content operation"
137 );
138 Self {
139 operation,
140 kind: OperationKind::ContentGeneration(kind),
141 }
142 }
143
144 pub fn provider(operation: Operation, provider: Provider) -> Self {
145 debug_assert!(
146 !operation.is_content_generation(),
147 "provider kind used with content-generation operation"
148 );
149 Self {
150 operation,
151 kind: OperationKind::Provider(provider),
152 }
153 }
154
155 pub const fn group(self) -> OperationGroup {
156 self.operation.group()
157 }
158
159 pub const fn provider_family(self) -> Provider {
160 self.kind.provider()
161 }
162
163 pub const fn is_consistent(self) -> bool {
164 self.operation.is_content_generation() == self.kind.is_content_generation()
165 }
166}
167
168impl Operation {
169 pub const fn is_content_generation(self) -> bool {
170 matches!(self, Self::GenerateContent | Self::StreamGenerateContent)
171 }
172}
173
174#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
176#[serde(rename_all = "UPPERCASE")]
177pub enum HttpMethod {
178 Get,
179 Post,
180 Put,
181 Patch,
182 Delete,
183}
184
185impl From<HttpMethod> for http::Method {
186 fn from(m: HttpMethod) -> Self {
187 match m {
188 HttpMethod::Get => http::Method::GET,
189 HttpMethod::Post => http::Method::POST,
190 HttpMethod::Put => http::Method::PUT,
191 HttpMethod::Patch => http::Method::PATCH,
192 HttpMethod::Delete => http::Method::DELETE,
193 }
194 }
195}
196
197#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
199pub struct Endpoint {
200 pub operation_key: OperationKey,
201 pub method: HttpMethod,
202 pub path: String,
204}
205
206impl Endpoint {
207 pub fn new(operation_key: OperationKey, method: HttpMethod, path: impl Into<String>) -> Self {
208 Self {
209 operation_key,
210 method,
211 path: path.into(),
212 }
213 }
214
215 pub fn content_generation(
216 operation: Operation,
217 kind: ContentGenerationKind,
218 method: HttpMethod,
219 path: impl Into<String>,
220 ) -> Self {
221 Self::new(
222 OperationKey::content_generation(operation, kind),
223 method,
224 path,
225 )
226 }
227
228 pub fn provider(
229 operation: Operation,
230 provider: Provider,
231 method: HttpMethod,
232 path: impl Into<String>,
233 ) -> Self {
234 Self::new(OperationKey::provider(operation, provider), method, path)
235 }
236
237 pub const fn provider_family(&self) -> Provider {
238 self.operation_key.provider_family()
239 }
240
241 pub const fn group(&self) -> OperationGroup {
242 self.operation_key.group()
243 }
244}