import Foundation enum NetworkClient { static let session: URLSession = { let configuration = URLSessionConfiguration.default configuration.waitsForConnectivity = true configuration.timeoutIntervalForRequest = 60 configuration.timeoutIntervalForResource = 120 configuration.requestCachePolicy = .reloadIgnoringLocalCacheData return URLSession(configuration: configuration) }() /// Low-latency session for AI API calls — does not block waiting for connectivity. static let aiSession: URLSession = { let configuration = URLSessionConfiguration.default configuration.waitsForConnectivity = false configuration.timeoutIntervalForRequest = 45 configuration.timeoutIntervalForResource = 60 configuration.requestCachePolicy = .reloadIgnoringLocalCacheData configuration.httpMaximumConnectionsPerHost = 4 return URLSession(configuration: configuration) }() static func data( for request: URLRequest, session: URLSession = session, retries: Int = 2 ) async throws -> (Data, URLResponse) { var lastError: Error? for attempt in 0...retries { if attempt > 0 { try await Task.sleep(nanoseconds: UInt64(attempt) * 400_000_000) } do { return try await session.data(for: request) } catch let error as URLError where error.isTransientNetworkFailure { lastError = error } catch { throw error } } throw lastError ?? URLError(.unknown) } static func aiData(for request: URLRequest) async throws -> (Data, URLResponse) { try await data(for: request, session: aiSession, retries: 0) } static func prepare() async { guard let url = URL(string: "https://api.openai.com") else { return } var request = URLRequest(url: url) request.httpMethod = "HEAD" request.timeoutInterval = 10 _ = try? await aiSession.data(for: request) } } private extension URLError { var isTransientNetworkFailure: Bool { switch code { case .networkConnectionLost, .notConnectedToInternet, .timedOut, .cannotConnectToHost, .dnsLookupFailed, .cannotFindHost, .internationalRoamingOff, .callIsActive: return true default: return false } } }