oxicode_ai/utils/
overflow.rs1use crate::messages::AssistantMessage;
7
8const OVERFLOW_PATTERNS: &[&str] = &[
11 "prompt is too long", "request_too_large", "input is too long for requested model", "exceeds the context window", "exceeds the maximum number of tokens", "maximum prompt length", "reduce the length of the messages", "maximum context length", "exceeds the limit of", "exceeds the available context size", "greater than the context length", "context window exceeds limit", "exceeded model token limit", "too large for model with", "model_context_window_exceeded", "prompt too long", "context_length_exceeded", "context length exceeded", "too many tokens", "token limit exceeded", ];
32
33const NON_OVERFLOW_PATTERNS: &[&str] = &[
37 "Throttling error:", "Service unavailable:", "rate limit", "too many requests", ];
42
43pub fn is_context_overflow(message: &AssistantMessage, context_window: Option<usize>) -> bool {
61 if message.stop_reason == crate::types::StopReason::Error
63 && let Some(ref error_msg) = message.error_message
64 {
65 let is_non_overflow = NON_OVERFLOW_PATTERNS
67 .iter()
68 .any(|p: &&str| error_msg.contains(p));
69
70 if !is_non_overflow {
71 let is_overflow = OVERFLOW_PATTERNS
72 .iter()
73 .any(|p: &&str| error_msg.contains(p));
74
75 if is_overflow {
76 return true;
77 }
78 }
79
80 if (error_msg.contains("400") || error_msg.contains("413"))
82 && (error_msg.contains("no body") || error_msg.trim().len() < 50)
83 {
84 return true;
85 }
86 }
87
88 let Some(window) = context_window else {
89 return false;
90 };
91
92 if message.stop_reason == crate::types::StopReason::Stop {
94 let input_tokens = message.usage.input + message.usage.cache_read;
95 if input_tokens > window {
96 return true;
97 }
98 }
99
100 if message.stop_reason == crate::types::StopReason::Length && message.usage.output == 0 {
104 let input_tokens = message.usage.input + message.usage.cache_read;
105 if input_tokens >= (window as f64 * 0.99) as usize {
107 return true;
108 }
109 }
110
111 false
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use crate::types::{Cost, StopReason, Usage};
118
119 fn make_error_message(error: &str) -> AssistantMessage {
120 let mut msg =
121 AssistantMessage::new(crate::types::Api::OpenAiCompletions, "test", "test-model");
122 msg.stop_reason = StopReason::Error;
123 msg.error_message = Some(error.to_string());
124 msg
125 }
126
127 fn make_success_message(input: usize, output: usize) -> AssistantMessage {
128 let mut msg =
129 AssistantMessage::new(crate::types::Api::OpenAiCompletions, "test", "test-model");
130 msg.stop_reason = StopReason::Stop;
131 msg.usage = Usage {
132 input,
133 output,
134 total_tokens: input + output,
135 cache_read: 0,
136 cache_write: 0,
137 cost: Cost::default(),
138 };
139 msg
140 }
141
142 fn make_length_message(input: usize, output: usize) -> AssistantMessage {
143 let mut msg =
144 AssistantMessage::new(crate::types::Api::OpenAiCompletions, "test", "test-model");
145 msg.stop_reason = StopReason::Length;
146 msg.usage = Usage {
147 input,
148 output,
149 total_tokens: input + output,
150 cache_read: 0,
151 cache_write: 0,
152 cost: Cost::default(),
153 };
154 msg
155 }
156
157 #[test]
158 fn test_anthropic_overflow() {
159 let msg = make_error_message("prompt is too long: 213462 tokens > 200000 maximum");
160 assert!(is_context_overflow(&msg, None));
161 }
162
163 #[test]
164 fn test_anthropic_request_too_large() {
165 let msg = make_error_message("request_too_large: Request exceeds maximum size");
166 assert!(is_context_overflow(&msg, None));
167 }
168
169 #[test]
170 fn test_openai_overflow() {
171 let msg = make_error_message("Your input exceeds the context window of this model");
172 assert!(is_context_overflow(&msg, None));
173 }
174
175 #[test]
176 fn test_google_overflow() {
177 let msg = make_error_message(
178 "The input token count (1196265) exceeds the maximum number of tokens allowed (1048575)",
179 );
180 assert!(is_context_overflow(&msg, None));
181 }
182
183 #[test]
184 fn test_xai_overflow() {
185 let msg = make_error_message(
186 "This model's maximum prompt length is 131072 but the request contains 537812 tokens",
187 );
188 assert!(is_context_overflow(&msg, None));
189 }
190
191 #[test]
192 fn test_groq_overflow() {
193 let msg = make_error_message("Please reduce the length of the messages or completion");
194 assert!(is_context_overflow(&msg, None));
195 }
196
197 #[test]
198 fn test_mistral_overflow() {
199 let msg = make_error_message(
200 "Prompt contains X tokens ... too large for model with Y maximum context length",
201 );
202 assert!(is_context_overflow(&msg, None));
203 }
204
205 #[test]
206 fn test_non_overflow_rate_limit() {
207 let msg = make_error_message("rate limit exceeded");
208 assert!(!is_context_overflow(&msg, None));
209 }
210
211 #[test]
212 fn test_non_overflow_throttling() {
213 let msg = make_error_message("Throttling error: Too many tokens, please wait");
214 assert!(!is_context_overflow(&msg, None));
216 }
217
218 #[test]
219 fn test_silent_overflow() {
220 let msg = make_success_message(150_000, 500);
221 assert!(is_context_overflow(&msg, Some(128_000)));
222 }
223
224 #[test]
225 fn test_no_silent_overflow() {
226 let msg = make_success_message(100_000, 500);
227 assert!(!is_context_overflow(&msg, Some(128_000)));
228 }
229
230 #[test]
231 fn test_length_stop_overflow() {
232 let msg = make_length_message(127_500, 0);
233 assert!(is_context_overflow(&msg, Some(128_000)));
234 }
235
236 #[test]
237 fn test_length_stop_no_overflow() {
238 let msg = make_length_message(100_000, 0);
239 assert!(!is_context_overflow(&msg, Some(128_000)));
240 }
241
242 #[test]
243 fn test_length_stop_with_output() {
244 let msg = make_length_message(100_000, 500);
246 assert!(!is_context_overflow(&msg, Some(128_000)));
247 }
248
249 #[test]
250 fn test_no_error_no_overflow() {
251 let msg = make_success_message(100, 50);
252 assert!(!is_context_overflow(&msg, None));
253 }
254
255 #[test]
256 fn test_cerebras_overflow() {
257 let msg = make_error_message("400 status code (no body)");
258 assert!(is_context_overflow(&msg, None));
259 }
260
261 #[test]
262 fn test_bedrock_overflow() {
263 let msg = make_error_message("input is too long for requested model");
264 assert!(is_context_overflow(&msg, None));
265 }
266
267 #[test]
268 fn test_llamacpp_overflow() {
269 let msg =
270 make_error_message("the request exceeds the available context size, try increasing it");
271 assert!(is_context_overflow(&msg, None));
272 }
273
274 #[test]
275 fn test_minimax_overflow() {
276 let msg = make_error_message("invalid params, context window exceeds limit");
277 assert!(is_context_overflow(&msg, None));
278 }
279
280 #[test]
281 fn test_kimi_overflow() {
282 let msg = make_error_message(
283 "Your request exceeded model token limit: 128000 (requested: 200000)",
284 );
285 assert!(is_context_overflow(&msg, None));
286 }
287
288 #[test]
289 fn test_generic_context_length_exceeded() {
290 let msg = make_error_message("context_length_exceeded");
291 assert!(is_context_overflow(&msg, None));
292 }
293
294 #[test]
295 fn test_service_unavailable_not_overflow() {
296 let msg = make_error_message("Service unavailable: too many tokens, try again later");
297 assert!(!is_context_overflow(&msg, None));
298 }
299}