import Foundation // ───────────────────────────────────────────────────────────── // Server-Sent Events (SSE) Support // ───────────────────────────────────────────────────────────── /// SSE Event structure public struct SSEEvent { public let id: String? public let event: String? public let data: String public let retry: Int? public init(id: String? = nil, event: String? = nil, data: String, retry: Int? = nil) { self.id = id self.event = event self.data = data self.retry = retry } /// Format as SSE string public func format() -> String { var output = "" if let id = id { output += "id: \(id)\n" } if let event = event { output += "event: \(event)\n" } if let retry = retry { output += "retry: \(retry)\n" } // Handle multi-line data let lines = data.split(separator: "\n") for line in lines { output += "data: \(line)\n" } output += "\n" return output } } /// SSE Stream Generator public final class SSEStream { private var buffer = "" public init() {} /// Add event to stream public func add(event: SSEEvent) -> String { let formatted = event.format() buffer += formatted return formatted } /// Create chat completion chunk public static func chatChunk( id: String, model: String, content: String? = nil, role: String? = nil, finishReason: String? = nil ) -> SSEEvent { var delta: [String: String] = [:] if let role = role { delta["role"] = role } if let content = content { delta["content"] = content } let chunk: [String: Any] = [ "id": id, "object": "chat.completion.chunk", "created": Int(Date().timeIntervalSince1970), "model": model, "choices": [ [ "index": 0, "delta": delta, "finish_reason": finishReason as Any ] ] ] guard let jsonData = try? JSONSerialization.data(withJSONObject: chunk), let jsonString = String(data: jsonData, encoding: .utf8) else { return SSEEvent(data: "") } return SSEEvent(data: jsonString) } /// Create text completion chunk public static func textChunk( id: String, model: String, text: String, finishReason: String? = nil ) -> SSEEvent { let chunk: [String: Any] = [ "id": id, "object": "text_completion", "created": Int(Date().timeIntervalSince1970), "model": model, "choices": [ [ "index": 0, "text": text, "finish_reason": finishReason as Any ] ] ] guard let jsonData = try? JSONSerialization.data(withJSONObject: chunk), let jsonString = String(data: jsonData, encoding: .utf8) else { return SSEEvent(data: "") } return SSEEvent(data: jsonString) } /// Create [DONE] event public static func done() -> SSEEvent { SSEEvent(data: "[DONE]") } /// Create error event public static func error(message: String) -> SSEEvent { let error: [String: Any] = [ "error": [ "message": message, "type": "invalid_request_error", "code": nil ] ] guard let jsonData = try? JSONSerialization.data(withJSONObject: error), let jsonString = String(data: jsonData, encoding: .utf8) else { return SSEEvent(data: "") } return SSEEvent(event: "error", data: jsonString) } }