Skip to main content

atman_runtime/providers/
mod.rs

1pub mod anthropic;
2pub mod codex;
3pub mod mock;
4pub mod openai;
5
6pub(crate) fn classify_attachment_error(status: u16, body: &str) -> Option<String> {
7    if status == 413 {
8        return Some("payload_too_large".into());
9    }
10    let lower = body.to_ascii_lowercase();
11    let attachment_markers = [
12        "image",
13        "attachment",
14        "media_type",
15        "unsupported",
16        "invalid image",
17        "image_parse_error",
18        "invalid_image_url",
19        "request_too_large",
20    ];
21    let has_marker = attachment_markers.iter().any(|m| lower.contains(m));
22    let is_size_signal = lower.contains("too large") || lower.contains("payload_too_large");
23    if status == 400 && has_marker {
24        return Some(pick_reason(&lower));
25    }
26    if is_size_signal {
27        return Some("payload_too_large".into());
28    }
29    None
30}
31
32fn pick_reason(lower: &str) -> String {
33    if lower.contains("invalid_image_url") {
34        "invalid_image_url".into()
35    } else if lower.contains("image_parse_error") {
36        "image_parse_error".into()
37    } else if lower.contains("unsupported") {
38        "unsupported_media_type".into()
39    } else if lower.contains("too large") {
40        "payload_too_large".into()
41    } else {
42        "invalid_image".into()
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49
50    #[test]
51    fn http_413_maps_to_payload_too_large() {
52        let r = classify_attachment_error(413, "").unwrap();
53        assert_eq!(r, "payload_too_large");
54    }
55
56    #[test]
57    fn openai_invalid_image_url_recognized() {
58        let body = r#"{"error":{"code":"invalid_image_url","message":"..."}}"#;
59        let r = classify_attachment_error(400, body).unwrap();
60        assert_eq!(r, "invalid_image_url");
61    }
62
63    #[test]
64    fn anthropic_image_error_recognized() {
65        let body = "unsupported media_type for image";
66        let r = classify_attachment_error(400, body).unwrap();
67        assert_eq!(r, "unsupported_media_type");
68    }
69
70    #[test]
71    fn non_attachment_error_returns_none() {
72        assert!(classify_attachment_error(500, "internal").is_none());
73        assert!(classify_attachment_error(401, "unauthorized").is_none());
74    }
75}