@@ -14,10 +14,61 @@ import CoreImage
1414import Foundation
1515import HTTPTypes
1616import Hummingbird
17+ import Hub
1718import MLX
1819import MLXLLM
1920import MLXLMCommon
2021import MLXVLM
22+ import Tokenizers
23+
24+ // ── Hub/Tokenizer bridges (Downloader + TokenizerLoader conformances) ─────────
25+
26+ private struct HubDownloader : Downloader , Sendable {
27+ let hub : HubApi
28+ func download(
29+ id: String , revision: String ? ,
30+ matching patterns: [ String ] ,
31+ useLatest: Bool ,
32+ progressHandler: @Sendable @escaping ( Progress ) -> Void
33+ ) async throws -> URL {
34+ try await hub. snapshot ( from: id, matching: patterns, progressHandler: progressHandler)
35+ }
36+ }
37+
38+ private struct TransformersTokenizerLoader : TokenizerLoader , Sendable {
39+ func load( from directory: URL ) async throws -> any MLXLMCommon . Tokenizer {
40+ let t = try await AutoTokenizer . from ( modelFolder: directory)
41+ return TransformersTokenizerBridge ( t)
42+ }
43+ }
44+
45+ private struct TransformersTokenizerBridge : MLXLMCommon . Tokenizer , Sendable {
46+ let upstream : any Tokenizers . Tokenizer
47+ init ( _ upstream: any Tokenizers . Tokenizer ) { self . upstream = upstream }
48+ func encode( text: String , addSpecialTokens: Bool ) -> [ Int ] {
49+ upstream. encode ( text: text, addSpecialTokens: addSpecialTokens)
50+ }
51+ func decode( tokenIds: [ Int ] , skipSpecialTokens: Bool ) -> String {
52+ upstream. decode ( tokens: tokenIds, skipSpecialTokens: skipSpecialTokens)
53+ }
54+ func convertTokenToId( _ token: String ) -> Int ? { upstream. convertTokenToId ( token) }
55+ func convertIdToToken( _ id: Int ) -> String ? { upstream. convertIdToToken ( id) }
56+ var bosToken : String ? { upstream. bosToken }
57+ var eosToken : String ? { upstream. eosToken }
58+ var unknownToken : String ? { upstream. unknownToken }
59+ func applyChatTemplate(
60+ messages: [ [ String : any Sendable ] ] ,
61+ tools: [ [ String : any Sendable ] ] ? ,
62+ additionalContext: [ String : any Sendable ] ?
63+ ) throws -> [ Int ] {
64+ do {
65+ return try upstream. applyChatTemplate (
66+ messages: messages, tools: tools, additionalContext: additionalContext)
67+ } catch Tokenizers . TokenizerError . missingChatTemplate {
68+ throw MLXLMCommon . TokenizerError. missingChatTemplate
69+ }
70+ }
71+ }
2172
2273// ── CLI ──────────────────────────────────────────────────────────────────────
2374
@@ -332,21 +383,32 @@ struct MLXServer: AsyncParsableCommand {
332383 } ( )
333384 let tracker = ProgressTracker ( modelId: resolvedModelId)
334385
386+ let cacheRoot = URL . applicationSupportDirectory
387+ . appendingPathComponent ( " MLX " , isDirectory: true )
388+ . appendingPathComponent ( " HuggingFace " , isDirectory: true )
335389 if isVision {
336390 print ( " [SwiftLM] Loading VLM (vision-language model)... " )
391+ let downloader = HubDownloader ( hub: HubApi ( downloadBase: cacheRoot) )
337392 container = try await VLMModelFactory . shared. loadContainer (
393+ from: downloader,
394+ using: TransformersTokenizerLoader ( ) ,
338395 configuration: modelConfig
339396 ) { progress in
340397 tracker. printProgress ( progress)
341398 }
342399 } else {
400+ let downloader = HubDownloader ( hub: HubApi ( downloadBase: cacheRoot) )
343401 container = try await LLMModelFactory . shared. loadContainer (
402+ from: downloader,
403+ using: TransformersTokenizerLoader ( ) ,
344404 configuration: modelConfig
345405 ) { progress in
346406 tracker. printProgress ( progress)
347407 }
348408 }
349409
410+ print ( " [SwiftLM] Loaded model configuration. Inferred tool call format: \( String ( describing: await container. configuration. toolCallFormat) ) " )
411+
350412 // ── Apply GPU/CPU layer partitioning ──
351413 if let gpuCount = requestedGPULayers {
352414 let actual = await container. setGPULayers ( gpuCount)
@@ -914,7 +976,22 @@ func handleChatCompletion(
914976 chatMessages. append ( . system( textContent, images: images) )
915977 systemPromptText += textContent
916978 case " assistant " :
917- chatMessages. append ( . assistant( textContent, images: images) )
979+ var formattedToolCalls : [ [ String : any Sendable ] ] ? = nil
980+ if let tc = msg. tool_calls, !tc. isEmpty {
981+ formattedToolCalls = tc. map { call in
982+ [
983+ " id " : call. id,
984+ " type " : call. type,
985+ " function " : [
986+ " name " : call. function. name,
987+ " arguments " : call. function. arguments
988+ ] as [ String : any Sendable ]
989+ ] as [ String : any Sendable ]
990+ }
991+ }
992+ chatMessages. append ( . assistant( textContent, images: images, toolCalls: formattedToolCalls) )
993+ case " tool " :
994+ chatMessages. append ( . tool( textContent, toolCallId: msg. tool_call_id) )
918995 default :
919996 chatMessages. append ( . user( textContent, images: images) )
920997 }
@@ -1885,6 +1962,8 @@ struct ChatCompletionRequest: Decodable {
18851962 struct Message : Decodable {
18861963 let role : String
18871964 let content : MessageContent ?
1965+ let tool_calls : [ ToolCallResponse ] ?
1966+ let tool_call_id : String ?
18881967
18891968 /// Extract plain text from content (handles both string and multipart)
18901969 var textContent : String {
@@ -1932,11 +2011,11 @@ struct ChatCompletionRequest: Decodable {
19322011 case string( String )
19332012 case parts( [ ContentPart ] )
19342013
1935- init ( from decoder: Decoder ) throws {
1936- let container = try decoder. singleValueContainer ( )
1937- if let str = try ? container . decode ( String . self) {
2014+ init ( from decoder: Swift . Decoder ) throws {
2015+ let svc = try decoder. singleValueContainer ( )
2016+ if let str = try ? svc . decode ( String . self) {
19382017 self = . string( str)
1939- } else if let parts = try ? container . decode ( [ ContentPart ] . self) {
2018+ } else if let parts = try ? svc . decode ( [ ContentPart ] . self) {
19402019 self = . parts( parts)
19412020 } else {
19422021 self = . string( " " )
@@ -2065,13 +2144,13 @@ struct AssistantMessage: Encodable {
20652144 }
20662145}
20672146
2068- struct ToolCallResponse : Encodable {
2147+ struct ToolCallResponse : Codable {
20692148 let id : String
20702149 let type : String
20712150 let function : ToolCallFunction
20722151}
20732152
2074- struct ToolCallFunction : Encodable {
2153+ struct ToolCallFunction : Codable {
20752154 let name : String
20762155 let arguments : String
20772156}
@@ -2096,25 +2175,37 @@ struct TextChoice: Encodable {
20962175 }
20972176}
20982177
2099- struct AnyCodable : Decodable , Sendable {
2178+ // AnyCodable: a Sendable-compatible type-erased JSON value.
2179+ // `value` stores only Sendable-compatible Foundation types: Bool, Int, Double,
2180+ // String, NSNull, [AnyCodable.SendableValue], [String: AnyCodable.SendableValue]
2181+ // AnyCodable: a type-erased JSON value that bridges to Foundation types.
2182+ // Marked @unchecked Sendable: all stored types (Bool/Int/Double/String/NSNull/
2183+ // recursive AnyCodable) are in fact Sendable; `Any` is used for ergonomic storage.
2184+ // AnyCodable: type-erased Decodable wrapper over JSON scalars/arrays/objects.
2185+ // `value` holds Sendable-safe Foundation types (Bool/Int/Double/String/NSNull + collections).
2186+ struct AnyCodable : @unchecked Sendable {
21002187 let value : Any
2101- init ( from decoder: Decoder ) throws {
2102- let c = try decoder. singleValueContainer ( )
2103- if c. decodeNil ( ) { value = NSNull ( ) }
2104- else if let b = try ? c. decode ( Bool . self) { value = b }
2105- else if let i = try ? c. decode ( Int . self) { value = i }
2106- else if let d = try ? c. decode ( Double . self) { value = d }
2107- else if let s = try ? c. decode ( String . self) { value = s }
2108- else if let a = try ? c. decode ( [ AnyCodable ] . self) { value = a. map { $0. value } }
2109- else if let d = try ? c. decode ( [ String : AnyCodable ] . self) { value = d. mapValues { $0. value } }
2110- else { value = NSNull ( ) }
2111- }
2188+
21122189 static func toSendable( _ dict: [ String : AnyCodable ] ? ) -> [ String : any Sendable ] ? {
21132190 guard let dict else { return nil }
21142191 return dict. mapValues { $0. value as! any Sendable }
21152192 }
21162193}
21172194
2195+ extension AnyCodable : Decodable {
2196+ init ( from decoder: Swift . Decoder ) throws {
2197+ let c = try decoder. singleValueContainer ( )
2198+ if ( try ? c. decodeNil ( ) ) == true { value = NSNull ( ) ; return }
2199+ if let b = try ? c. decode ( Bool . self) { value = b; return }
2200+ if let i = try ? c. decode ( Int . self) { value = i; return }
2201+ if let d = try ? c. decode ( Double . self) { value = d; return }
2202+ if let s = try ? c. decode ( String . self) { value = s; return }
2203+ if let a = try ? c. decode ( [ AnyCodable ] . self) { value = a. map { $0. value } ; return }
2204+ if let o = try ? c. decode ( [ String : AnyCodable ] . self) { value = o. mapValues { $0. value } ; return }
2205+ value = NSNull ( )
2206+ }
2207+ }
2208+
21182209struct TokenUsage : Encodable {
21192210 let promptTokens : Int
21202211 let completionTokens : Int
0 commit comments