From 4c1718bb9ae70d20c55674766294a4ff29503747 Mon Sep 17 00:00:00 2001 From: noorbhatia Date: Wed, 3 Jun 2026 22:52:24 +0530 Subject: [PATCH] Bump mlx-swift-lm to 3.x (3.31.3) --- Package.resolved | 197 +----------------- Package.swift | 22 +- .../Models/MLXLanguageModel.swift | 50 +++-- 3 files changed, 60 insertions(+), 209 deletions(-) diff --git a/Package.resolved b/Package.resolved index 7ed371b..fc106f1 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,15 +1,6 @@ { - "originHash" : "f2f0ba1d1b9625bd5147b2fbd7b82236dac35ee1baa399fcf5c76b22fd428bb8", + "originHash" : "ac4d9985bc0c659d2c3e37b5e85c823ce19b8402e5b743a74d77a9199c3718e0", "pins" : [ - { - "identity" : "async-http-client", - "kind" : "remoteSourceControl", - "location" : "https://github.com/swift-server/async-http-client.git", - "state" : { - "revision" : "2fc4652fb4689eb24af10e55cabaa61d8ba774fd", - "version" : "1.32.0" - } - }, { "identity" : "eventsource", "kind" : "remoteSourceControl", @@ -22,7 +13,7 @@ { "identity" : "jsonschema", "kind" : "remoteSourceControl", - "location" : "https://github.com/mattt/JSONSchema.git", + "location" : "https://github.com/mattt/JSONSchema", "state" : { "revision" : "4c6f2467d5bc72b062c7a9b7e4cd77a09635ea8b", "version" : "1.3.1" @@ -31,57 +22,12 @@ { "identity" : "partialjsondecoder", "kind" : "remoteSourceControl", - "location" : "https://github.com/mattt/PartialJSONDecoder.git", + "location" : "https://github.com/mattt/PartialJSONDecoder", "state" : { "revision" : "e4d389e6bcc6771bb988d1a8a17695d8bfa97172", "version" : "1.0.0" } }, - { - "identity" : "swift-algorithms", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-algorithms.git", - "state" : { - "revision" : "87e50f483c54e6efd60e885f7f5aa946cee68023", - "version" : "1.2.1" - } - }, - { - "identity" : "swift-asn1", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-asn1.git", - "state" : { - "revision" : "810496cf121e525d660cd0ea89a758740476b85f", - "version" : "1.5.1" - } - }, - { - "identity" : "swift-async-algorithms", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-async-algorithms.git", - "state" : { - "revision" : "9d349bcc328ac3c31ce40e746b5882742a0d1272", - "version" : "1.1.3" - } - }, - { - "identity" : "swift-atomics", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-atomics.git", - "state" : { - "revision" : "b601256eab081c0f92f059e12818ac1d4f178ff7", - "version" : "1.3.0" - } - }, - { - "identity" : "swift-certificates", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-certificates.git", - "state" : { - "revision" : "24ccdeeeed4dfaae7955fcac9dbf5489ed4f1a25", - "version" : "1.18.0" - } - }, { "identity" : "swift-collections", "kind" : "remoteSourceControl", @@ -91,149 +37,14 @@ "version" : "1.3.0" } }, - { - "identity" : "swift-configuration", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-configuration.git", - "state" : { - "revision" : "be76c4ad929eb6c4bcaf3351799f2adf9e6848a9", - "version" : "1.2.0" - } - }, - { - "identity" : "swift-crypto", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-crypto.git", - "state" : { - "revision" : "6f70fa9eab24c1fd982af18c281c4525d05e3095", - "version" : "4.2.0" - } - }, - { - "identity" : "swift-distributed-tracing", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-distributed-tracing.git", - "state" : { - "revision" : "e109d8b5308d0e05201d9a1dd1c475446a946a11", - "version" : "1.4.0" - } - }, - { - "identity" : "swift-http-structured-headers", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-http-structured-headers.git", - "state" : { - "revision" : "76d7627bd88b47bf5a0f8497dd244885960dde0b", - "version" : "1.6.0" - } - }, - { - "identity" : "swift-http-types", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-http-types.git", - "state" : { - "revision" : "45eb0224913ea070ec4fba17291b9e7ecf4749ca", - "version" : "1.5.1" - } - }, - { - "identity" : "swift-log", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-log.git", - "state" : { - "revision" : "bbd81b6725ae874c69e9b8c8804d462356b55523", - "version" : "1.10.1" - } - }, - { - "identity" : "swift-nio", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio.git", - "state" : { - "revision" : "e932d3c4d8f77433c8f7093b5ebcbf91463948a0", - "version" : "2.95.0" - } - }, - { - "identity" : "swift-nio-extras", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-extras.git", - "state" : { - "revision" : "3df009d563dc9f21a5c85b33d8c2e34d2e4f8c3b", - "version" : "1.32.1" - } - }, - { - "identity" : "swift-nio-http2", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-http2.git", - "state" : { - "revision" : "b6571f3db40799df5a7fc0e92c399aa71c883edd", - "version" : "1.40.0" - } - }, - { - "identity" : "swift-nio-ssl", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-ssl.git", - "state" : { - "revision" : "173cc69a058623525a58ae6710e2f5727c663793", - "version" : "2.36.0" - } - }, - { - "identity" : "swift-nio-transport-services", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-nio-transport-services.git", - "state" : { - "revision" : "60c3e187154421171721c1a38e800b390680fb5d", - "version" : "1.26.0" - } - }, - { - "identity" : "swift-numerics", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-numerics.git", - "state" : { - "revision" : "0c0290ff6b24942dadb83a929ffaaa1481df04a2", - "version" : "1.1.1" - } - }, - { - "identity" : "swift-service-context", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-service-context.git", - "state" : { - "revision" : "d0997351b0c7779017f88e7a93bc30a1878d7f29", - "version" : "1.3.0" - } - }, - { - "identity" : "swift-service-lifecycle", - "kind" : "remoteSourceControl", - "location" : "https://github.com/swift-server/swift-service-lifecycle", - "state" : { - "revision" : "89888196dd79c61c50bca9a103d8114f32e1e598", - "version" : "2.10.1" - } - }, { "identity" : "swift-syntax", "kind" : "remoteSourceControl", - "location" : "https://github.com/swiftlang/swift-syntax.git", + "location" : "https://github.com/swiftlang/swift-syntax", "state" : { "revision" : "0687f71944021d616d34d922343dcef086855920", "version" : "600.0.1" } - }, - { - "identity" : "swift-system", - "kind" : "remoteSourceControl", - "location" : "https://github.com/apple/swift-system", - "state" : { - "revision" : "7c6ad0fc39d0763e0b699210e4124afd5041c5df", - "version" : "1.6.4" - } } ], "version" : 3 diff --git a/Package.swift b/Package.swift index 933f837..2a06cc3 100644 --- a/Package.swift +++ b/Package.swift @@ -30,6 +30,7 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/huggingface/swift-transformers", from: "1.0.0"), + .package(url: "https://github.com/huggingface/swift-huggingface", from: "0.9.0"), .package( url: "https://github.com/mattt/EventSource", from: "1.3.0", @@ -41,8 +42,10 @@ let package = Package( .package(url: "https://github.com/mattt/JSONSchema", from: "1.3.0"), .package(url: "https://github.com/mattt/llama.swift", .upToNextMajor(from: "2.7484.0")), .package(url: "https://github.com/mattt/PartialJSONDecoder", from: "1.0.0"), - // mlx-swift-lm must be >= 2.25.5 for ToolSpec/tool calls and UserInput(chat:processing:tools:). - .package(url: "https://github.com/ml-explore/mlx-swift-lm", from: "2.25.5"), + // mlx-swift-lm 3.x decouples from the HuggingFace Hub and swift-transformers tokenizer; the + // MLXHuggingFace product + macros (with swift-huggingface and swift-transformers' Tokenizers) + // restore Hub-based loading. See the MLX trait products below and `MLXLanguageModel.swift`. + .package(url: "https://github.com/ml-explore/mlx-swift-lm", from: "3.0.0"), .package(url: "https://github.com/swiftlang/swift-syntax", from: "600.0.0"), .package(url: "https://github.com/swift-server/async-http-client.git", from: "1.24.0"), ], @@ -69,6 +72,21 @@ let package = Package( package: "mlx-swift-lm", condition: .when(traits: ["MLX"]) ), + .product( + name: "MLXHuggingFace", + package: "mlx-swift-lm", + condition: .when(traits: ["MLX"]) + ), + .product( + name: "HuggingFace", + package: "swift-huggingface", + condition: .when(traits: ["MLX"]) + ), + .product( + name: "Tokenizers", + package: "swift-transformers", + condition: .when(traits: ["MLX"]) + ), .product( name: "Transformers", package: "swift-transformers", diff --git a/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift b/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift index 0ef37ef..189ae11 100644 --- a/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift @@ -14,9 +14,16 @@ import Foundation import JSONSchema import MLXLMCommon import MLX + // MLXLLM and MLXVLM are imported for their `TrampolineModelFactory` registration, which + // `ModelFactoryRegistry` resolves by name when loading LLM/VLM architectures. + import MLXLLM import MLXVLM + // MLXHuggingFace provides the `#hubDownloader()` / `#huggingFaceTokenizerLoader()` macros; their + // expansions reference `HuggingFace.HubClient` and `Tokenizers.AutoTokenizer`, so both modules + // must be in scope at the call site. + import MLXHuggingFace + import HuggingFace import Tokenizers - import Hub /// Wrapper to store model availability state in NSCache. private final class CachedModelState: NSObject, @unchecked Sendable { @@ -613,8 +620,8 @@ import Foundation /// The model identifier. public let modelId: String - /// The Hub API instance for downloading models. - public let hub: HubApi? + /// The Hugging Face Hub client used for downloading models. + public let hub: HubClient? /// The local directory containing the model files. public let directory: URL? @@ -626,12 +633,12 @@ import Foundation /// /// - Parameters: /// - modelId: The model identifier (for example, "mlx-community/Llama-3.2-3B-Instruct-4bit"). - /// - hub: An optional Hub API instance for downloading models. If not provided, the default Hub API is used. + /// - hub: An optional Hugging Face Hub client for downloading models. If not provided, the default client is used. /// - directory: An optional local directory URL containing the model files. If provided, the model is loaded from this directory instead of downloading. /// - gpuMemory: The GPU-memory behavior used for this model's active and idle phases. public init( modelId: String, - hub: HubApi? = nil, + hub: HubClient? = nil, directory: URL? = nil, gpuMemory: GPUMemoryConfiguration = .automatic ) { @@ -675,15 +682,30 @@ import Foundation } /// Get or load model context with caching - private func loadContext(modelId: String, hub: HubApi?, directory: URL?) async throws -> ModelContext { + private func loadContext(modelId: String, hub: HubClient?, directory: URL?) async throws -> ModelContext { let key = directory?.absoluteString ?? modelId return try await modelCache.context(for: key) { + // mlx-swift-lm 3.x requires an explicit downloader and tokenizer loader. The + // MLXHuggingFace macros expand to a HubClient-backed downloader and an + // AutoTokenizer-backed loader, matching the prior HuggingFace Hub behavior. if let directory { - return try await loadModel(directory: directory) + return try await loadModel(from: directory, using: #huggingFaceTokenizerLoader()) } - return try await loadModel(hub: hub ?? HubApi(), id: modelId) + if let hub { + return try await loadModel( + from: #hubDownloader(hub), + using: #huggingFaceTokenizerLoader(), + id: modelId + ) + } + + return try await loadModel( + from: #hubDownloader(), + using: #huggingFaceTokenizerLoader(), + id: modelId + ) } } @@ -1714,7 +1736,7 @@ import Foundation private struct MLXTokenBackend: TokenBackend { let model: any MLXLMCommon.LanguageModel - let tokenizer: any Tokenizer + let tokenizer: any MLXLMCommon.Tokenizer var state: MLXLMCommon.LMOutput.State? var cache: [MLXLMCommon.KVCache] var processor: MLXLMCommon.LogitProcessor? @@ -1795,7 +1817,7 @@ import Foundation private static func buildEndTokens( eosTokenId: Int, - tokenizer: any Tokenizer, + tokenizer: any MLXLMCommon.Tokenizer, configuration: ModelConfiguration ) -> Set { var tokens: Set = [eosTokenId] @@ -1816,13 +1838,13 @@ import Foundation func isSpecialToken(_ token: Int) -> Bool { // Use swift-transformers' own special token registry (skipSpecialTokens) instead of guessing. - let raw = tokenizer.decode(tokens: [token], skipSpecialTokens: false) + let raw = tokenizer.decode(tokenIds: [token], skipSpecialTokens: false) guard !raw.isEmpty else { return false } - let filtered = tokenizer.decode(tokens: [token], skipSpecialTokens: true) + let filtered = tokenizer.decode(tokenIds: [token], skipSpecialTokens: true) return filtered.isEmpty } - private static func buildTokensExcludedFromRepetitionPenalty(tokenizer: any Tokenizer) -> Set { + private static func buildTokensExcludedFromRepetitionPenalty(tokenizer: any MLXLMCommon.Tokenizer) -> Set { let excludedTexts = ["{", "}", "[", "]", ",", ":", "\""] var excluded = Set() excluded.reserveCapacity(excludedTexts.count * 2) @@ -1842,7 +1864,7 @@ import Foundation } func tokenText(_ token: Int) -> String? { - let decoded = tokenizer.decode(tokens: [token], skipSpecialTokens: false) + let decoded = tokenizer.decode(tokenIds: [token], skipSpecialTokens: false) return decoded.isEmpty ? nil : decoded }