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 {
32 pub const CLEF: &str = "clef";
34 pub const CLEF_FLASH: &str = "clef-flash";
36 pub const JEV_LATEST: &str = "jev-latest";
38}
39
40pub mod hosts {
42 pub const CLOUDFLARE: &str = "api.cloudflare.com";
43 pub const TYPESAFE: &str = "api.typesafe.ai";
44}
45
46pub const TYPESAFE_ENDPOINT: &str = "https://api.typesafe.ai/v1/systemone";
48
49pub mod clef_limits {
51 pub const MIN_QUESTIONS: usize = 1;
53 pub const MAX_QUESTIONS: usize = 64;
55 pub const MAX_QUESTION_ID_LEN: usize = 100;
57 pub const MAX_IMAGES: usize = 4;
59 pub const MAX_BODY_BYTES: usize = 13 * 1024 * 1024;
61}
62
63#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
66#[non_exhaustive]
67pub struct ProviderRequest {
68 pub model: String,
70 pub state: Value,
73 pub questions: IndexMap<String, Question>,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 pub images: Option<Vec<Image>>,
76}
77
78impl ProviderRequest {
79 pub fn new(
80 model: impl Into<String>,
81 state: impl Into<Value>,
82 questions: IndexMap<String, Question>,
83 ) -> Self {
84 Self {
85 model: model.into(),
86 state: state.into(),
87 questions,
88 images: None,
89 }
90 }
91
92 pub fn with_images(mut self, images: Vec<Image>) -> Self {
93 self.images = Some(images);
94 self
95 }
96}
97
98#[derive(Clone, Debug, PartialEq, Deserialize, Serialize)]
100#[non_exhaustive]
101pub struct ProviderResponse {
102 pub model: String,
103 pub answers: IndexMap<String, Answer>,
104 #[serde(default, skip_serializing_if = "Option::is_none")]
107 pub usage: Option<Usage>,
108}
109
110impl ProviderResponse {
111 pub fn new(model: impl Into<String>, answers: IndexMap<String, Answer>) -> Self {
112 Self {
113 model: model.into(),
114 answers,
115 usage: None,
116 }
117 }
118
119 pub fn with_usage(mut self, usage: Usage) -> Self {
120 self.usage = Some(usage);
121 self
122 }
123}
124
125pub use cortexkit_model_batch::status::{
132 item_code_for_status, workers_ai_codes, workers_ai_item_code,
133};
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138 use crate::errors::{
139 ACCOUNT_LIMIT_EXHAUSTED, ACCOUNT_NOT_ENTITLED, AUTH_FAILED, INVALID_ITEM,
140 MODEL_UNAVAILABLE, PROVIDER_ERROR, RATE_LIMITED,
141 };
142
143 #[test]
144 fn documented_statuses_map_to_item_codes() {
145 for status in [429, 529] {
146 assert_eq!(item_code_for_status(status), Some(RATE_LIMITED));
147 }
148 for status in [408, 500, 502, 503] {
149 assert_eq!(item_code_for_status(status), Some(PROVIDER_ERROR));
150 }
151 for status in [400, 413, 422, 409] {
152 assert_eq!(item_code_for_status(status), Some(INVALID_ITEM));
153 }
154 for status in [401, 403] {
155 assert_eq!(item_code_for_status(status), Some(AUTH_FAILED));
156 }
157 assert_eq!(item_code_for_status(404), Some(MODEL_UNAVAILABLE));
158 assert_eq!(item_code_for_status(200), None);
159 }
160
161 #[test]
162 fn clef_errors_map_by_workers_ai_code_first() {
163 assert_eq!(
164 workers_ai_item_code(429, Some(3036)),
165 Some(ACCOUNT_LIMIT_EXHAUSTED)
166 );
167 for code in [5035, 5016, 3023] {
168 assert_eq!(
169 workers_ai_item_code(403, Some(code)),
170 Some(ACCOUNT_NOT_ENTITLED)
171 );
172 }
173 assert_eq!(
174 workers_ai_item_code(400, Some(5007)),
175 Some(MODEL_UNAVAILABLE)
176 );
177 assert_eq!(workers_ai_item_code(429, Some(3040)), Some(RATE_LIMITED));
178 assert_eq!(workers_ai_item_code(403, None), Some(AUTH_FAILED));
179 }
180}