import Foundation public struct KimiUsageSnapshot: Sendable { public let weekly: KimiUsageDetail public let rateLimit: KimiUsageDetail? public let updatedAt: Date public init(weekly: KimiUsageDetail, rateLimit: KimiUsageDetail?, updatedAt: Date) { self.weekly = weekly self.rateLimit = rateLimit self.updatedAt = updatedAt } private static func parseDate(_ dateString: String?) -> Date? { guard let dateString else { return nil } let formatter = ISO8601DateFormatter() formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds] if let date = formatter.date(from: dateString) { return date } let fallback = ISO8601DateFormatter() fallback.formatOptions = [.withInternetDateTime] return fallback.date(from: dateString) } private static func minutesFromNow(_ date: Date?) -> Int? { guard let date else { return nil } let minutes = Int(date.timeIntervalSince(Date()) / 60) return minutes > 0 ? minutes : nil }} extension KimiUsageSnapshot { public func toUsageSnapshot() -> UsageSnapshot { // Parse weekly quota let weeklyLimit = Int(weekly.limit) ?? 0 let weeklyRemaining = Int(weekly.remaining ?? "") let weeklyUsed = Int(weekly.used ?? "") ?? { guard let remaining = weeklyRemaining else { return 0 } return max(0, weeklyLimit - remaining) }() let weeklyPercent = weeklyLimit > 0 ? Double(weeklyUsed) / Double(weeklyLimit) * 100 : 0 let weeklyWindow = RateWindow( usedPercent: weeklyPercent, windowMinutes: nil, // Weekly doesn't have a fixed window like rate limit resetsAt: Self.parseDate(self.weekly.resetTime), resetDescription: "\(weeklyUsed)/\(weeklyLimit) requests") // Parse rate limit if available var rateLimitWindow: RateWindow? if let rateLimit = self.rateLimit { let rateLimitValue = Int(rateLimit.limit) ?? 0 let rateRemaining = Int(rateLimit.remaining ?? "") let rateUsed = Int(rateLimit.used ?? "") ?? { guard let remaining = rateRemaining else { return 0 } return max(0, rateLimitValue - remaining) }() let ratePercent = rateLimitValue > 0 ? Double(rateUsed) / Double(rateLimitValue) * 100 : 0 rateLimitWindow = RateWindow( usedPercent: ratePercent, windowMinutes: 300, // 300 minutes = 5 hours resetsAt: Self.parseDate(rateLimit.resetTime), resetDescription: "Rate: \(rateUsed)/\(rateLimitValue) per 5 hours") } let identity = ProviderIdentitySnapshot( providerID: .kimi, accountEmail: nil, accountOrganization: nil, loginMethod: nil) return UsageSnapshot( primary: weeklyWindow, secondary: rateLimitWindow, tertiary: nil, providerCost: nil, updatedAt: self.updatedAt, identity: identity) }}
import Foundation
public struct KimiUsageSnapshot: Sendable {
public let weekly: KimiUsageDetail
public let rateLimit: KimiUsageDetail?
public let updatedAt: Date
public init(weekly: KimiUsageDetail, rateLimit: KimiUsageDetail?, updatedAt: Date) {
self.weekly = weekly
self.rateLimit = rateLimit
self.updatedAt = updatedAt
}
private static func parseDate(_ dateString: String?) -> Date? {
guard let dateString else { return nil }
let formatter = ISO8601DateFormatter()
formatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
if let date = formatter.date(from: dateString) {
return date
}
let fallback = ISO8601DateFormatter()
fallback.formatOptions = [.withInternetDateTime]
return fallback.date(from: dateString)
}
private static func minutesFromNow(_ date: Date?) -> Int? {
guard let date else { return nil }
let minutes = Int(date.timeIntervalSince(Date()) / 60)
return minutes > 0 ? minutes : nil
}
}
extension KimiUsageSnapshot {
public func toUsageSnapshot() -> UsageSnapshot {
// Parse weekly quota
let weeklyLimit = Int(weekly.limit) ?? 0
let weeklyRemaining = Int(weekly.remaining ?? "")
let weeklyUsed = Int(weekly.used ?? "") ?? {
guard let remaining = weeklyRemaining else { return 0 }
return max(0, weeklyLimit - remaining)
}()
let weeklyPercent = weeklyLimit > 0 ? Double(weeklyUsed) / Double(weeklyLimit) * 100 : 0
let weeklyWindow = RateWindow(
usedPercent: weeklyPercent,
windowMinutes: nil, // Weekly doesn't have a fixed window like rate limit
resetsAt: Self.parseDate(self.weekly.resetTime),
resetDescription: "\(weeklyUsed)/\(weeklyLimit) requests")
// Parse rate limit if available
var rateLimitWindow: RateWindow?
if let rateLimit = self.rateLimit {
let rateLimitValue = Int(rateLimit.limit) ?? 0
let rateRemaining = Int(rateLimit.remaining ?? "")
let rateUsed = Int(rateLimit.used ?? "") ?? {
guard let remaining = rateRemaining else { return 0 }
return max(0, rateLimitValue - remaining)
}()
let ratePercent = rateLimitValue > 0 ? Double(rateUsed) / Double(rateLimitValue) * 100 : 0
rateLimitWindow = RateWindow(
usedPercent: ratePercent,
windowMinutes: 300, // 300 minutes = 5 hours
resetsAt: Self.parseDate(rateLimit.resetTime),
resetDescription: "Rate: \(rateUsed)/\(rateLimitValue) per 5 hours")
}
let identity = ProviderIdentitySnapshot(
providerID: .kimi,
accountEmail: nil,
accountOrganization: nil,
loginMethod: nil)
return UsageSnapshot(
primary: weeklyWindow,
secondary: rateLimitWindow,
tertiary: nil,
providerCost: nil,
updatedAt: self.updatedAt,
identity: identity)
}
}