import Foundation // ───────────────────────────────────────────────────────────── // Generation Configuration // ───────────────────────────────────────────────────────────── public struct GenerationConfig: Sendable { public let maxTokens: Int public let temperature: Float public let topK: Int? public let topP: Float? public let stopTokens: [Int]? public init( maxTokens: Int = 100, temperature: Float = 1.0, topK: Int? = nil, topP: Float? = nil, stopTokens: [Int]? = nil ) { self.maxTokens = maxTokens self.temperature = temperature self.topK = topK self.topP = topP self.stopTokens = stopTokens } // Default configuration public static let defaultConfig = GenerationConfig(maxTokens: 100, temperature: 1.0) } // ───────────────────────────────────────────────────────────── // Streaming Generator - Token-by-token generation // ───────────────────────────────────────────────────────────── public final class StreamingGenerator: @unchecked Sendable { private let model: E4BModel private let tokenizer: Tokenizer private let engine: MarkBaseEngine private let sampler: Sampler public init(model: E4BModel, tokenizer: Tokenizer, engine: MarkBaseEngine) { self.model = model self.tokenizer = tokenizer self.engine = engine self.sampler = Sampler() } // ───────────────────────────────────────────────────────────── // Stream Generate - AsyncStream for token-by-token output // ───────────────────────────────────────────────────────────── public func generate( prompt: String, config: GenerationConfig = .defaultConfig ) -> AsyncStream { return AsyncStream { continuation in Task { do { // Encode prompt let promptTokens = tokenizer.encode(text: prompt) // Pre-fill KV cache with prompt tokens var lastLogits: [Float] = [] for (position, tokenId) in promptTokens.enumerated() { lastLogits = try model.forward(tokenId: tokenId, position: position) } // Generate tokens var generatedTokens: [Int] = [] var position = promptTokens.count var streamDecoder = StreamingDecoder(tokenizer: tokenizer) for _ in 0.. String { print("[GEN COMPLETE] Starting generation for prompt: '\(prompt)'") fflush(stdout) // Encode prompt print("[GEN COMPLETE] Encoding prompt...") fflush(stdout) let promptTokens = tokenizer.encode(text: prompt) print("[GEN COMPLETE] Encoded to \(promptTokens.count) tokens: \(promptTokens)") fflush(stdout) // Pre-fill KV cache with prompt tokens print("[GEN COMPLETE] Starting forward pass for prompt tokens...") fflush(stdout) var lastLogits: [Float] = [] for (position, tokenId) in promptTokens.enumerated() { print("[GEN COMPLETE] Forward pass for token \(tokenId) at position \(position)") fflush(stdout) lastLogits = try model.forward(tokenId: tokenId, position: position) print("[GEN COMPLETE] Forward pass completed, logits count: \(lastLogits.count)") fflush(stdout) } print("[GEN COMPLETE] All prompt tokens processed") fflush(stdout) // Generate tokens var generatedTokens: [Int] = [] var position = promptTokens.count for _ in 0.. [Int] { // Pre-fill KV cache with prompt tokens var lastLogits: [Float] = [] for (position, tokenId) in promptTokens.enumerated() { lastLogits = try model.forward(tokenId: tokenId, position: position) } var generatedTokens: [Int] = [] var position = promptTokens.count for _ in 0..