cortexkit_role_classifier/
provider.rs1use indexmap::IndexMap;
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14
15use crate::{
16 question::{Image, Question},
17 reply::{Answer, Usage},
18};
19
20pub mod catalog_ids {
25 pub const CLEF: &str = "cloudflare-workers-ai/@cf/cloudflare/clef";
26 pub const CLEF_FLASH: &str = "cloudflare-workers-ai/@cf/cloudflare/clef-flash";
27 pub const JEV_1_13_0: &str = "typesafe/jev-1.13.0";
28}
29
30pub mod models {
36 pub const CLEF: &str = "clef";
38 pub const CLEF_FLASH: &str = "clef-flash";
40 pub const JEV_1_13_0: &str = "jev-1.13.0";
45 pub const JEV_LATEST: &str = "jev-latest";
49}
50
51pub mod hosts {
53 pub const CLOUDFLARE: &str = "api.cloudflare.com";
54 pub const TYPESAFE: &str = "api.typesafe.ai";
55}
56
57pub const TYPESAFE_ENDPOINT: &str = "https://api.typesafe.ai/v1/systemone";
59
60pub mod clef_limits {
62 pub const MIN_QUESTIONS: usize = 1;
64 pub const MAX_QUESTIONS: usize = 64;
66 pub const MAX_QUESTION_ID_LEN: usize = 100;
68 pub const MAX_IMAGES: usize = 4;
70 pub const MAX_BODY_BYTES: usize = 13 * 1024 * 1024;
72}
73
74#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
77#[non_exhaustive]
78pub struct ProviderRequest {
79 pub model: String,
81 pub state: Value,
84 pub questions: IndexMap<String, Question>,
85 #[serde(default, skip_serializing_if = "Option::is_none")]
86 pub images: Option<Vec<Image>>,
87}
88
89impl ProviderRequest {
90 pub fn new(
91 model: impl Into<String>,
92 state: impl Into<Value>,
93 questions: IndexMap<String, Question>,
94 ) -> Self {
95 Self {
96 model: model.into(),
97 state: state.into(),
98 questions,
99 images: None,
100 }
101 }
102
103 pub fn with_images(mut self, images: Vec<Image>) -> Self {
104 self.images = Some(images);
105 self
106 }
107}
108
109#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
111#[non_exhaustive]
112pub struct ProviderResponse {
113 pub model: String,
114 pub answers: IndexMap<String, Answer>,
115 #[serde(default, skip_serializing_if = "Option::is_none")]
118 pub usage: Option<Usage>,
119}
120
121impl ProviderResponse {
122 pub fn new(model: impl Into<String>, answers: IndexMap<String, Answer>) -> Self {
123 Self {
124 model: model.into(),
125 answers,
126 usage: None,
127 }
128 }
129
130 pub fn with_usage(mut self, usage: Usage) -> Self {
131 self.usage = Some(usage);
132 self
133 }
134}
135
136pub use cortexkit_model_batch::status::{
143 item_code_for_status, workers_ai_codes, workers_ai_item_code,
144};
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149 use crate::errors::{
150 ACCOUNT_LIMIT_EXHAUSTED, ACCOUNT_NOT_ENTITLED, AUTH_FAILED, INVALID_ITEM,
151 MODEL_UNAVAILABLE, PROVIDER_ERROR, RATE_LIMITED,
152 };
153
154 #[test]
155 fn documented_statuses_map_to_item_codes() {
156 for status in [429, 529] {
157 assert_eq!(item_code_for_status(status), Some(RATE_LIMITED));
158 }
159 for status in [408, 500, 502, 503] {
160 assert_eq!(item_code_for_status(status), Some(PROVIDER_ERROR));
161 }
162 for status in [400, 413, 422, 409] {
163 assert_eq!(item_code_for_status(status), Some(INVALID_ITEM));
164 }
165 for status in [401, 403] {
166 assert_eq!(item_code_for_status(status), Some(AUTH_FAILED));
167 }
168 assert_eq!(item_code_for_status(404), Some(MODEL_UNAVAILABLE));
169 assert_eq!(item_code_for_status(200), None);
170 }
171
172 #[test]
173 fn clef_errors_map_by_workers_ai_code_first() {
174 assert_eq!(
175 workers_ai_item_code(429, Some(3036)),
176 Some(ACCOUNT_LIMIT_EXHAUSTED)
177 );
178 for code in [5035, 5016, 3023] {
179 assert_eq!(
180 workers_ai_item_code(403, Some(code)),
181 Some(ACCOUNT_NOT_ENTITLED)
182 );
183 }
184 assert_eq!(
185 workers_ai_item_code(400, Some(5007)),
186 Some(MODEL_UNAVAILABLE)
187 );
188 assert_eq!(workers_ai_item_code(429, Some(3040)), Some(RATE_LIMITED));
189 assert_eq!(workers_ai_item_code(403, None), Some(AUTH_FAILED));
190 }
191}