1use schemars::JsonSchema;
22use serde::{Deserialize, Serialize};
23
24#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
31#[schemars(rename = "viewer.ApiCallSubType")]
32pub enum ApiCallSubType {
33 #[serde(rename = "POST_/agent/completions")]
34 PostAgentCompletions,
35 #[serde(rename = "POST_/vector/completions")]
36 PostVectorCompletions,
37 #[serde(rename = "POST_/vector/completions/votes")]
38 PostVectorCompletionsVotes,
39 #[serde(rename = "POST_/vector/completions/cache")]
40 PostVectorCompletionsCache,
41 #[serde(rename = "POST_/functions/list")]
42 PostFunctionsList,
43 #[serde(rename = "POST_/functions")]
44 PostFunctions,
45 #[serde(rename = "POST_/functions/usage")]
46 PostFunctionsUsage,
47 #[serde(rename = "POST_/functions/executions")]
48 PostFunctionsExecutions,
49 #[serde(rename = "POST_/functions/profiles/list")]
50 PostFunctionsProfilesList,
51 #[serde(rename = "POST_/functions/profiles")]
52 PostFunctionsProfiles,
53 #[serde(rename = "POST_/functions/profiles/usage")]
54 PostFunctionsProfilesUsage,
55 #[serde(rename = "POST_/functions/profiles/pairs/list")]
56 PostFunctionsProfilesPairsList,
57 #[serde(rename = "POST_/functions/profiles/pairs/usage")]
58 PostFunctionsProfilesPairsUsage,
59 #[serde(rename = "POST_/functions/inventions")]
60 PostFunctionsInventions,
61 #[serde(rename = "POST_/functions/inventions/recursive")]
62 PostFunctionsInventionsRecursive,
63 #[serde(rename = "POST_/functions/inventions/prompts/list")]
64 PostFunctionsInventionsPromptsList,
65 #[serde(rename = "POST_/functions/inventions/prompts")]
66 PostFunctionsInventionsPrompts,
67 #[serde(rename = "POST_/functions/inventions/prompts/usage")]
68 PostFunctionsInventionsPromptsUsage,
69 #[serde(rename = "POST_/functions/inventions/state")]
70 PostFunctionsInventionsState,
71 #[serde(rename = "POST_/functions/profiles/compute")]
72 PostFunctionsProfilesCompute,
73 #[serde(rename = "POST_/auth/keys")]
74 PostAuthKeys,
75 #[serde(rename = "POST_/auth/keys/openrouter")]
76 PostAuthKeysOpenrouter,
77 #[serde(rename = "DELETE_/auth/keys")]
78 DeleteAuthKeys,
79 #[serde(rename = "DELETE_/auth/keys/openrouter")]
80 DeleteAuthKeysOpenrouter,
81 #[serde(rename = "GET_/auth/keys")]
82 GetAuthKeys,
83 #[serde(rename = "GET_/auth/keys/openrouter")]
84 GetAuthKeysOpenrouter,
85 #[serde(rename = "GET_/auth/credits")]
86 GetAuthCredits,
87 #[serde(rename = "POST_/swarms/list")]
88 PostSwarmsList,
89 #[serde(rename = "POST_/swarms")]
90 PostSwarms,
91 #[serde(rename = "POST_/swarms/usage")]
92 PostSwarmsUsage,
93 #[serde(rename = "POST_/agents/list")]
94 PostAgentsList,
95 #[serde(rename = "POST_/agents")]
96 PostAgents,
97 #[serde(rename = "POST_/agents/usage")]
98 PostAgentsUsage,
99 #[serde(rename = "POST_/error")]
100 PostError,
101 #[serde(rename = "POST_/laboratories/executions")]
102 PostLaboratoriesExecutions,
103}
104
105#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Hash)]
108#[serde(rename_all = "UPPERCASE")]
109#[schemars(rename = "viewer.HttpMethod")]
110pub enum HttpMethod {
111 Get,
112 Post,
113 Delete,
114}
115
116impl HttpMethod {
117 pub fn as_str(&self) -> &'static str {
120 match self {
121 HttpMethod::Get => "GET",
122 HttpMethod::Post => "POST",
123 HttpMethod::Delete => "DELETE",
124 }
125 }
126}
127
128impl ApiCallSubType {
129 pub fn method(&self) -> HttpMethod {
131 match self {
132 ApiCallSubType::GetAuthKeys
133 | ApiCallSubType::GetAuthKeysOpenrouter
134 | ApiCallSubType::GetAuthCredits => HttpMethod::Get,
135 ApiCallSubType::DeleteAuthKeys
136 | ApiCallSubType::DeleteAuthKeysOpenrouter => HttpMethod::Delete,
137 _ => HttpMethod::Post,
138 }
139 }
140
141 pub fn path(&self) -> &'static str {
144 match self {
145 ApiCallSubType::PostAgentCompletions => "/agent/completions",
146 ApiCallSubType::PostVectorCompletions => "/vector/completions",
147 ApiCallSubType::PostVectorCompletionsVotes => "/vector/completions/votes",
148 ApiCallSubType::PostVectorCompletionsCache => "/vector/completions/cache",
149 ApiCallSubType::PostFunctionsList => "/functions/list",
150 ApiCallSubType::PostFunctions => "/functions",
151 ApiCallSubType::PostFunctionsUsage => "/functions/usage",
152 ApiCallSubType::PostFunctionsExecutions => "/functions/executions",
153 ApiCallSubType::PostFunctionsProfilesList => "/functions/profiles/list",
154 ApiCallSubType::PostFunctionsProfiles => "/functions/profiles",
155 ApiCallSubType::PostFunctionsProfilesUsage => "/functions/profiles/usage",
156 ApiCallSubType::PostFunctionsProfilesPairsList => "/functions/profiles/pairs/list",
157 ApiCallSubType::PostFunctionsProfilesPairsUsage => "/functions/profiles/pairs/usage",
158 ApiCallSubType::PostFunctionsInventions => "/functions/inventions",
159 ApiCallSubType::PostFunctionsInventionsRecursive => "/functions/inventions/recursive",
160 ApiCallSubType::PostFunctionsInventionsPromptsList => "/functions/inventions/prompts/list",
161 ApiCallSubType::PostFunctionsInventionsPrompts => "/functions/inventions/prompts",
162 ApiCallSubType::PostFunctionsInventionsPromptsUsage => "/functions/inventions/prompts/usage",
163 ApiCallSubType::PostFunctionsInventionsState => "/functions/inventions/state",
164 ApiCallSubType::PostFunctionsProfilesCompute => "/functions/profiles/compute",
165 ApiCallSubType::PostAuthKeys => "/auth/keys",
166 ApiCallSubType::PostAuthKeysOpenrouter => "/auth/keys/openrouter",
167 ApiCallSubType::DeleteAuthKeys => "/auth/keys",
168 ApiCallSubType::DeleteAuthKeysOpenrouter => "/auth/keys/openrouter",
169 ApiCallSubType::GetAuthKeys => "/auth/keys",
170 ApiCallSubType::GetAuthKeysOpenrouter => "/auth/keys/openrouter",
171 ApiCallSubType::GetAuthCredits => "/auth/credits",
172 ApiCallSubType::PostSwarmsList => "/swarms/list",
173 ApiCallSubType::PostSwarms => "/swarms",
174 ApiCallSubType::PostSwarmsUsage => "/swarms/usage",
175 ApiCallSubType::PostAgentsList => "/agents/list",
176 ApiCallSubType::PostAgents => "/agents",
177 ApiCallSubType::PostAgentsUsage => "/agents/usage",
178 ApiCallSubType::PostError => "/error",
179 ApiCallSubType::PostLaboratoriesExecutions => "/laboratories/executions",
180 }
181 }
182}
183
184#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq)]
201#[serde(tag = "type", rename_all = "snake_case")]
202#[schemars(rename = "viewer.ApiCallEnvelope")]
203pub enum ApiCallEnvelope {
204 #[schemars(title = "Begin")]
205 Begin,
206 #[schemars(title = "Chunk")]
207 Chunk { chunk: serde_json::Value },
208 #[schemars(title = "Error")]
209 Error { error: serde_json::Value },
210 #[schemars(title = "End")]
211 End,
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use serde_json::json;
218
219 #[test]
220 fn sub_type_roundtrip_with_underscore_separator() {
221 let s = ApiCallSubType::PostAgentCompletions;
222 let json = serde_json::to_value(&s).unwrap();
223 assert_eq!(json, json!("POST_/agent/completions"));
224 let back: ApiCallSubType = serde_json::from_value(json).unwrap();
225 assert_eq!(back, ApiCallSubType::PostAgentCompletions);
226 }
227
228 #[test]
229 fn auth_keys_disambiguated_by_method() {
230 let post = ApiCallSubType::PostAuthKeys;
231 let del = ApiCallSubType::DeleteAuthKeys;
232 let get = ApiCallSubType::GetAuthKeys;
233 assert_eq!(post.path(), "/auth/keys");
234 assert_eq!(del.path(), "/auth/keys");
235 assert_eq!(get.path(), "/auth/keys");
236 assert_eq!(post.method(), HttpMethod::Post);
237 assert_eq!(del.method(), HttpMethod::Delete);
238 assert_eq!(get.method(), HttpMethod::Get);
239 assert_eq!(
240 serde_json::to_value(&post).unwrap(),
241 json!("POST_/auth/keys")
242 );
243 assert_eq!(
244 serde_json::to_value(&del).unwrap(),
245 json!("DELETE_/auth/keys")
246 );
247 assert_eq!(serde_json::to_value(&get).unwrap(), json!("GET_/auth/keys"));
248 }
249
250 #[test]
251 fn envelope_serializes_as_tagged_enum() {
252 let begin = serde_json::to_value(ApiCallEnvelope::Begin).unwrap();
253 assert_eq!(begin, json!({"type": "begin"}));
254
255 let chunk = serde_json::to_value(ApiCallEnvelope::Chunk {
256 chunk: json!({"x": 1}),
257 })
258 .unwrap();
259 assert_eq!(chunk, json!({"type": "chunk", "chunk": {"x": 1}}));
260
261 let end = serde_json::to_value(ApiCallEnvelope::End).unwrap();
262 assert_eq!(end, json!({"type": "end"}));
263
264 let err = serde_json::to_value(ApiCallEnvelope::Error {
265 error: json!({"message": "boom"}),
266 })
267 .unwrap();
268 assert_eq!(
269 err,
270 json!({"type": "error", "error": {"message": "boom"}})
271 );
272 }
273
274 #[test]
275 fn method_str_matches_serde_rename_prefix() {
276 assert_eq!(HttpMethod::Get.as_str(), "GET");
277 assert_eq!(HttpMethod::Post.as_str(), "POST");
278 assert_eq!(HttpMethod::Delete.as_str(), "DELETE");
279 for variant in [
280 ApiCallSubType::PostAgentCompletions,
281 ApiCallSubType::GetAuthKeys,
282 ApiCallSubType::DeleteAuthKeysOpenrouter,
283 ] {
284 let rename = serde_json::to_string(&variant).unwrap();
285 let prefix = rename.trim_matches('"').split('_').next().unwrap();
288 assert_eq!(prefix, variant.method().as_str());
289 }
290 }
291}