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