claude_codes/io/
rate_limit.rs1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct RateLimitEvent {
41 pub rate_limit_info: RateLimitInfo,
43 pub session_id: String,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub uuid: Option<String>,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct RateLimitInfo {
53 pub status: String,
55 #[serde(rename = "resetsAt")]
57 pub resets_at: u64,
58 #[serde(rename = "rateLimitType")]
60 pub rate_limit_type: String,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub utilization: Option<f64>,
64 #[serde(skip_serializing_if = "Option::is_none", rename = "overageStatus")]
66 pub overage_status: Option<String>,
67 #[serde(rename = "overageDisabledReason")]
69 pub overage_disabled_reason: Option<String>,
70 #[serde(rename = "isUsingOverage")]
72 pub is_using_overage: bool,
73}
74
75#[cfg(test)]
76mod tests {
77 use crate::io::ClaudeOutput;
78
79 #[test]
80 fn test_deserialize_rate_limit_event() {
81 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"}"#;
82
83 let output: ClaudeOutput = serde_json::from_str(json).unwrap();
84 assert!(output.is_rate_limit_event());
85 assert_eq!(output.message_type(), "rate_limit_event");
86 assert_eq!(
87 output.session_id(),
88 Some("1ae0af5b-89fa-4075-8156-d5d3702f6505")
89 );
90
91 let evt = output.as_rate_limit_event().unwrap();
92 assert_eq!(evt.rate_limit_info.status, "allowed");
93 assert_eq!(evt.rate_limit_info.resets_at, 1771390800);
94 assert_eq!(evt.rate_limit_info.rate_limit_type, "five_hour");
95 assert_eq!(evt.rate_limit_info.utilization, None);
96 assert_eq!(
97 evt.rate_limit_info.overage_status,
98 Some("rejected".to_string())
99 );
100 assert_eq!(
101 evt.rate_limit_info.overage_disabled_reason,
102 Some("org_level_disabled".to_string())
103 );
104 assert!(!evt.rate_limit_info.is_using_overage);
105 assert_eq!(
106 evt.uuid,
107 Some("76258cfb-0dc8-4d4b-8682-77082b59c03f".to_string())
108 );
109 }
110
111 #[test]
112 fn test_deserialize_rate_limit_event_minimal() {
113 let json = r#"{"type":"rate_limit_event","rate_limit_info":{"status":"allowed","resetsAt":0,"rateLimitType":"hourly","overageStatus":"allowed","isUsingOverage":true},"session_id":"abc"}"#;
114
115 let output: ClaudeOutput = serde_json::from_str(json).unwrap();
116 let evt = output.as_rate_limit_event().unwrap();
117 assert_eq!(evt.rate_limit_info.overage_disabled_reason, None);
118 assert!(evt.rate_limit_info.is_using_overage);
119 assert!(evt.uuid.is_none());
120 }
121
122 #[test]
123 fn test_deserialize_rate_limit_event_allowed_warning() {
124 let json = r#"{"type":"rate_limit_event","rate_limit_info":{"status":"allowed_warning","resetsAt":1700000000,"rateLimitType":"five_hour","utilization":0.85,"isUsingOverage":false},"uuid":"550e8400-e29b-41d4-a716-446655440000","session_id":"test-session-id"}"#;
125
126 let output: ClaudeOutput = serde_json::from_str(json).unwrap();
127 let evt = output.as_rate_limit_event().unwrap();
128 assert_eq!(evt.rate_limit_info.status, "allowed_warning");
129 assert_eq!(evt.rate_limit_info.utilization, Some(0.85));
130 assert_eq!(evt.rate_limit_info.overage_status, None);
131 assert_eq!(evt.rate_limit_info.overage_disabled_reason, None);
132 assert!(!evt.rate_limit_info.is_using_overage);
133 }
134
135 #[test]
136 fn test_deserialize_rate_limit_event_rejected() {
137 let json = r#"{"type":"rate_limit_event","rate_limit_info":{"status":"rejected","resetsAt":1700003600,"rateLimitType":"seven_day","isUsingOverage":false,"overageStatus":"rejected","overageDisabledReason":"out_of_credits"},"uuid":"660e8400-e29b-41d4-a716-446655440001","session_id":"test-session-id"}"#;
138
139 let output: ClaudeOutput = serde_json::from_str(json).unwrap();
140 let evt = output.as_rate_limit_event().unwrap();
141 assert_eq!(evt.rate_limit_info.status, "rejected");
142 assert_eq!(evt.rate_limit_info.rate_limit_type, "seven_day");
143 assert_eq!(
144 evt.rate_limit_info.overage_status,
145 Some("rejected".to_string())
146 );
147 assert_eq!(
148 evt.rate_limit_info.overage_disabled_reason,
149 Some("out_of_credits".to_string())
150 );
151 }
152}