pub mod model_fetcher;
pub mod openai_compat;
pub mod openai_responses;
pub mod request_overrides;
pub mod responses_debug;
pub mod sse;
pub mod stream_tool_accumulator;
pub mod tool_schema;
pub(crate) fn looks_like_reasoning_unsupported_error(
status: reqwest::StatusCode,
body: &str,
) -> bool {
if !(status == 400 || status == 404 || status == 405 || status == 409 || status == 422) {
return false;
}
let b = body.to_ascii_lowercase();
let mentions_reasoning =
b.contains("reasoning") || b.contains("thinking") || b.contains("budget_tokens");
let indicates_unsupported = b.contains("unsupported")
|| b.contains("not supported")
|| b.contains("does not support")
|| b.contains("unknown parameter")
|| b.contains("unexpected parameter")
|| b.contains("unrecognized")
|| b.contains("invalid parameter");
mentions_reasoning && indicates_unsupported
}
pub(crate) fn looks_like_previous_response_not_found_error(
status: reqwest::StatusCode,
body: &str,
) -> bool {
if !(status == 400 || status == 404) {
return false;
}
let b = body.to_ascii_lowercase();
if b.contains("previous_response_not_found") {
return true;
}
let mentions_previous_response =
b.contains("previous_response_id") || b.contains("previous response");
let indicates_missing =
b.contains("not found") || b.contains("not_found") || b.contains("does not exist");
mentions_previous_response && indicates_missing
}
#[cfg(test)]
mod previous_response_not_found_tests {
use super::looks_like_previous_response_not_found_error as f;
use reqwest::StatusCode;
#[test]
fn fires_on_openai_previous_response_not_found_error() {
let bad = StatusCode::BAD_REQUEST;
assert!(f(
bad,
r#"{"error":{"message":"Previous response with id 'resp_123' not found.","type":"invalid_request_error","param":"previous_response_id","code":"previous_response_not_found"}}"#
));
assert!(f(bad, "Previous response with id 'resp_x' not found."));
assert!(f(bad, "previous_response_id 'resp_x' does not exist"));
assert!(f(StatusCode::NOT_FOUND, "previous_response_not_found"));
}
#[test]
fn does_not_fire_on_unrelated_errors() {
let bad = StatusCode::BAD_REQUEST;
assert!(!f(bad, "The model `gpt-x` does not exist or is not found"));
assert!(!f(bad, "Invalid value for 'previous_response_id'")); assert!(!f(
bad,
"previous_response_id is not supported for this model"
)); assert!(!f(
StatusCode::INTERNAL_SERVER_ERROR,
"previous_response_not_found"
));
assert!(!f(StatusCode::UNAUTHORIZED, "previous response not found"));
}
}
#[cfg(test)]
mod reasoning_heuristic_tests {
use super::looks_like_reasoning_unsupported_error as f;
use reqwest::StatusCode;
#[test]
fn fires_only_on_reasoning_parameter_rejection() {
let bad = StatusCode::BAD_REQUEST;
assert!(f(bad, "reasoning_effort is not supported for this model"));
assert!(f(bad, "Unknown parameter: reasoning_effort"));
assert!(f(bad, "This model does not support reasoning"));
assert!(f(bad, "Unrecognized request argument: thinking"));
assert!(!f(bad, "Unknown parameter: temperature")); assert!(!f(
bad,
"Invalid value for 'reasoning_effort': must be one of low, medium, high"
)); assert!(!f(
bad,
"Invalid request: missing required field 'messages'"
));
assert!(!f(bad, "The model gpt-x is unknown or unsupported"));
assert!(!f(
StatusCode::INTERNAL_SERVER_ERROR,
"reasoning not supported"
));
}
}