Skip to main content

claude_codes/io/
rate_limit.rs

1use serde::{Deserialize, Serialize};
2
3/// Rate limit event from Claude CLI.
4///
5/// Sent periodically to inform consumers about current rate limit status,
6/// including overage eligibility and reset timing.
7///
8/// # Example JSON
9///
10/// ```json
11/// {
12///   "type": "rate_limit_event",
13///   "rate_limit_info": {
14///     "status": "allowed",
15///     "resetsAt": 1771390800,
16///     "rateLimitType": "five_hour",
17///     "overageStatus": "rejected",
18///     "overageDisabledReason": "org_level_disabled",
19///     "isUsingOverage": false
20///   },
21///   "uuid": "76258cfb-0dc8-4d4b-8682-77082b59c03f",
22///   "session_id": "1ae0af5b-89fa-4075-8156-d5d3702f6505"
23/// }
24/// ```
25///
26/// # Example
27///
28/// ```
29/// use claude_codes::ClaudeOutput;
30///
31/// let json = r#"{"type":"rate_limit_event","rate_limit_info":{"status":"allowed","resetsAt":1771390800,"rateLimitType":"five_hour","overageStatus":"rejected","overageDisabledReason":"org_level_disabled","isUsingOverage":false},"uuid":"abc","session_id":"def"}"#;
32/// let output: ClaudeOutput = serde_json::from_str(json).unwrap();
33///
34/// if let Some(evt) = output.as_rate_limit_event() {
35///     println!("Rate limit status: {}", evt.rate_limit_info.status);
36///     println!("Resets at: {}", evt.rate_limit_info.resets_at);
37/// }
38/// ```
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct RateLimitEvent {
41    /// Rate limit status details
42    pub rate_limit_info: RateLimitInfo,
43    /// Session identifier
44    pub session_id: String,
45    /// Unique identifier for this message
46    #[serde(skip_serializing_if = "Option::is_none")]
47    pub uuid: Option<String>,
48}
49
50/// Rate limit status information.
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct RateLimitInfo {
53    /// Current rate limit status (e.g., "allowed")
54    pub status: String,
55    /// Unix timestamp when the rate limit resets
56    #[serde(rename = "resetsAt")]
57    pub resets_at: u64,
58    /// Type of rate limit (e.g., "five_hour")
59    #[serde(rename = "rateLimitType")]
60    pub rate_limit_type: String,
61    /// Overage status (e.g., "rejected", "allowed")
62    #[serde(rename = "overageStatus")]
63    pub overage_status: String,
64    /// Reason overage is disabled, if applicable
65    #[serde(rename = "overageDisabledReason")]
66    pub overage_disabled_reason: Option<String>,
67    /// Whether overage billing is active
68    #[serde(rename = "isUsingOverage")]
69    pub is_using_overage: bool,
70}
71
72#[cfg(test)]
73mod tests {
74    use crate::io::ClaudeOutput;
75
76    #[test]
77    fn test_deserialize_rate_limit_event() {
78        let json = r#"{"type":"rate_limit_event","rate_limit_info":{"status":"allowed","resetsAt":1771390800,"rateLimitType":"five_hour","overageStatus":"rejected","overageDisabledReason":"org_level_disabled","isUsingOverage":false},"uuid":"76258cfb-0dc8-4d4b-8682-77082b59c03f","session_id":"1ae0af5b-89fa-4075-8156-d5d3702f6505"}"#;
79
80        let output: ClaudeOutput = serde_json::from_str(json).unwrap();
81        assert!(output.is_rate_limit_event());
82        assert_eq!(output.message_type(), "rate_limit_event");
83        assert_eq!(
84            output.session_id(),
85            Some("1ae0af5b-89fa-4075-8156-d5d3702f6505")
86        );
87
88        let evt = output.as_rate_limit_event().unwrap();
89        assert_eq!(evt.rate_limit_info.status, "allowed");
90        assert_eq!(evt.rate_limit_info.resets_at, 1771390800);
91        assert_eq!(evt.rate_limit_info.rate_limit_type, "five_hour");
92        assert_eq!(evt.rate_limit_info.overage_status, "rejected");
93        assert_eq!(
94            evt.rate_limit_info.overage_disabled_reason,
95            Some("org_level_disabled".to_string())
96        );
97        assert!(!evt.rate_limit_info.is_using_overage);
98        assert_eq!(
99            evt.uuid,
100            Some("76258cfb-0dc8-4d4b-8682-77082b59c03f".to_string())
101        );
102    }
103
104    #[test]
105    fn test_deserialize_rate_limit_event_minimal() {
106        let json = r#"{"type":"rate_limit_event","rate_limit_info":{"status":"allowed","resetsAt":0,"rateLimitType":"hourly","overageStatus":"allowed","isUsingOverage":true},"session_id":"abc"}"#;
107
108        let output: ClaudeOutput = serde_json::from_str(json).unwrap();
109        let evt = output.as_rate_limit_event().unwrap();
110        assert_eq!(evt.rate_limit_info.overage_disabled_reason, None);
111        assert!(evt.rate_limit_info.is_using_overage);
112        assert!(evt.uuid.is_none());
113    }
114}