Skip to content

Commit a13f66b

Browse files
authored
Merge pull request #64 from rryam/feature/mlx-package-traits
Add MLX Package Trait to reduce dependency footprint
2 parents d6b4a83 + 8502f26 commit a13f66b

File tree

10 files changed

+104
-44
lines changed

10 files changed

+104
-44
lines changed

Package.resolved

Lines changed: 1 addition & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version: 6.0
1+
// swift-tools-version: 6.1
22
// The swift-tools-version declares the minimum version of Swift required to build this package.
33

44
import PackageDescription
@@ -34,9 +34,18 @@ let package = Package(
3434
targets: ["VecturaMLXCLI"]
3535
),
3636
],
37+
traits: [
38+
.trait(
39+
name: "MLX",
40+
description: "Enable MLX-based embeddings for GPU-accelerated inference"
41+
),
42+
],
3743
dependencies: [
44+
// Always included - lightweight dependencies
3845
.package(url: "https://github.com/jkrukowski/swift-embeddings.git", from: "0.0.21"),
3946
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.4.0"),
47+
48+
// MLX dependency - only loaded when MLX trait is enabled via target conditions
4049
.package(url: "https://github.com/ml-explore/mlx-swift-lm/", from: "2.30.3"),
4150
],
4251
targets: [
@@ -54,7 +63,11 @@ let package = Package(
5463
name: "VecturaMLXKit",
5564
dependencies: [
5665
"VecturaKit",
57-
.product(name: "MLXEmbedders", package: "mlx-swift-lm"),
66+
.product(
67+
name: "MLXEmbedders",
68+
package: "mlx-swift-lm",
69+
condition: .when(traits: ["MLX"])
70+
),
5871
]
5972
),
6073
.target(
@@ -77,7 +90,7 @@ let package = Package(
7790
name: "VecturaMLXCLI",
7891
dependencies: [
7992
"VecturaKit",
80-
"VecturaMLXKit",
93+
.target(name: "VecturaMLXKit", condition: .when(traits: ["MLX"])),
8194
.product(name: "ArgumentParser", package: "swift-argument-parser"),
8295
]
8396
),
@@ -87,7 +100,9 @@ let package = Package(
87100
),
88101
.executableTarget(
89102
name: "TestMLXExamples",
90-
dependencies: ["VecturaMLXKit"]
103+
dependencies: [
104+
.target(name: "VecturaMLXKit", condition: .when(traits: ["MLX"]))
105+
]
91106
),
92107
.executableTarget(
93108
name: "TestNLExamples",
@@ -99,7 +114,9 @@ let package = Package(
99114
),
100115
.testTarget(
101116
name: "VecturaMLXKitTests",
102-
dependencies: ["VecturaMLXKit"]
117+
dependencies: [
118+
.target(name: "VecturaMLXKit", condition: .when(traits: ["MLX"]))
119+
]
103120
),
104121
.testTarget(
105122
name: "VecturaNLKitTests",

README.md

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ The framework offers `VecturaKit` as the core vector database with pluggable emb
1010
It also includes CLI tools (`vectura-cli` and `vectura-mlx-cli`) for easily trying out the package.
1111

1212
<p align="center">
13-
<img src="https://img.shields.io/badge/Swift-6.0+-fa7343?style=flat&logo=swift&logoColor=white" alt="Swift 6.0+">
13+
<img src="https://img.shields.io/badge/Swift-6.1+-fa7343?style=flat&logo=swift&logoColor=white" alt="Swift 6.1+">
1414
<br>
1515
<img src="https://img.shields.io/badge/iOS-17.0+-000000?style=flat&logo=apple&logoColor=white" alt="iOS 17.0+">
1616
<img src="https://img.shields.io/badge/macOS-14.0+-000000?style=flat&logo=apple&logoColor=white" alt="macOS 14.0+">
@@ -40,6 +40,7 @@ Explore the following books to understand more about AI and iOS development:
4040
- [Supported Platforms](#supported-platforms)
4141
- [Installation](#installation)
4242
- [Swift Package Manager](#swift-package-manager)
43+
- [Package Traits (MLX Support)](#package-traits-mlx-support)
4344
- [Dependencies](#dependencies)
4445
- [Usage](#usage)
4546
- [Import VecturaKit](#import-vecturakit)
@@ -102,10 +103,32 @@ To integrate VecturaKit into your project using Swift Package Manager, add the f
102103

103104
```swift
104105
dependencies: [
105-
.package(url: "https://github.com/rryam/VecturaKit.git", from: "2.5.2"),
106+
.package(url: "https://github.com/rryam/VecturaKit.git", from: "3.0.0"),
106107
],
107108
```
108109

110+
### Package Traits (MLX Support)
111+
112+
Starting with version 3.0.0, VecturaKit uses [Package Traits](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0450-swiftpm-package-traits.md) (SE-0450) to reduce dependency footprint. The heavy MLX dependencies are only downloaded when explicitly enabled.
113+
114+
**For VecturaKit or VecturaNLKit only (lightweight):**
115+
116+
```swift
117+
dependencies: [
118+
.package(url: "https://github.com/rryam/VecturaKit.git", from: "3.0.0"),
119+
],
120+
```
121+
122+
**For VecturaMLXKit (enables MLX dependencies):**
123+
124+
```swift
125+
dependencies: [
126+
.package(url: "https://github.com/rryam/VecturaKit.git", from: "3.0.0", traits: ["MLX"]),
127+
],
128+
```
129+
130+
> **Note:** Package Traits require Swift 6.1+ (Xcode 16.3+). If using Xcode's "Add Package Dependencies" UI for MLX support, you'll need to manually edit your `Package.swift` to add the `traits: ["MLX"]` parameter.
131+
109132
### Dependencies
110133

111134
VecturaKit uses the following Swift packages:
@@ -418,6 +441,8 @@ let results = try await vectorDB.search(query: "search query")
418441

419442
VecturaKit supports Apple's MLX framework through the `MLXEmbedder` for accelerated on-device machine learning performance.
420443

444+
> **Important:** To use `VecturaMLXKit`, you must enable the `MLX` trait in your package dependency. See [Package Traits](#package-traits-mlx-support) for details.
445+
421446
### Import MLX Support
422447

423448
```swift
@@ -647,7 +672,7 @@ Common options for `vectura-cli`:
647672
- `--dimension, -v`: Vector dimension (auto-detected by default)
648673
- `--threshold, -t`: Minimum similarity threshold (default: 0.7)
649674
- `--num-results, -n`: Number of results to return (default: 10)
650-
- `--model-id, -m`: Model ID for embeddings (default: "minishlab/potion-retrieval-32M")
675+
- `--model-id, -m`: Model ID for embeddings (default: "minishlab/potion-base-4M")
651676

652677
### MLX CLI Tool (`vectura-mlx-cli`)
653678

@@ -696,7 +721,7 @@ Contributions are welcome! Please fork the repository and submit a pull request
696721
### Code Style
697722

698723
- Follow SwiftLint rules (run `swiftlint lint`)
699-
- Use Swift 6.0+ features where appropriate
724+
- Use Swift 6.1+ features where appropriate
700725
- Maintain backward compatibility when possible
701726
- Document public APIs with DocC comments
702727

Sources/TestMLXExamples/TestMLXExamples.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// Test script for VecturaMLXKit README examples
22
import Foundation
3+
4+
#if canImport(MLXEmbedders)
35
import VecturaKit
46
import VecturaMLXKit
57
import MLXEmbedders
@@ -87,3 +89,12 @@ struct TestMLXExamples {
8789
debugPrint("Document count after reset: \(try await vectorDB.documentCount)")
8890
}
8991
}
92+
#else
93+
@main
94+
struct TestMLXExamples {
95+
static func main() {
96+
print("VecturaMLXKit is not available. Enable the MLX trait to run this example.")
97+
print("Usage: swift run --traits MLX TestMLXExamples")
98+
}
99+
}
100+
#endif

Sources/VecturaCLI/VecturaCLI.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ extension VecturaCLI {
100100
var numResults: Int = 5
101101

102102
@Option(name: [.long, .customShort("m")], help: "Model ID for embeddings")
103-
var modelId: String = "minishlab/potion-retrieval-32M"
103+
var modelId: String = "minishlab/potion-base-4M"
104104

105105
mutating func run() async throws {
106106
print("VecturaKit Mock Demonstration")

Sources/VecturaKit/Embedder/VecturaModelSource.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public enum VecturaModelSource: Sendable {
2929
public extension VecturaModelSource {
3030

3131
/// The default model identifier when not otherwise specified.
32-
static let defaultModelId = "minishlab/potion-retrieval-32M"
32+
static let defaultModelId = "minishlab/potion-base-4M"
3333

3434
/// The default model when not otherwise specified.
3535
static let `default` = Self.id(Self.defaultModelId)

Sources/VecturaMLXCLI/VecturaMLXCLI.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import ArgumentParser
22
import Foundation
3+
4+
#if canImport(MLXEmbedders)
35
import MLXEmbedders
46
import VecturaKit
57
import VecturaMLXKit
@@ -280,3 +282,17 @@ extension VecturaMLXCLI {
280282
}
281283
}
282284
}
285+
#else
286+
@main
287+
struct VecturaMLXCLI: ParsableCommand {
288+
static let configuration = CommandConfiguration(
289+
commandName: "vectura-mlx",
290+
abstract: "A CLI tool for VecturaKit vector database using MLX embeddings"
291+
)
292+
293+
mutating func run() throws {
294+
print("VecturaMLXKit is not available. Enable the MLX trait to use this CLI.")
295+
print("Usage: swift run --traits MLX vectura-mlx-cli <command>")
296+
}
297+
}
298+
#endif

Sources/VecturaMLXKit/MLXEmbedder.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#if canImport(MLXEmbedders)
12
import Foundation
23
import MLX
34
import MLXEmbedders
@@ -126,3 +127,4 @@ enum EmbeddingError: Error {
126127
case unsupportedPoolingShape([Int])
127128
case vectorCountMismatch(expected: Int, received: Int)
128129
}
130+
#endif

Tests/VecturaMLXKitTests/VecturaMLXKitTests.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#if canImport(MLXEmbedders)
12
import Foundation
23
import Metal
34
import MLX
@@ -11,6 +12,7 @@ import Testing
1112
/// 1. Metal device (GPU) availability
1213
/// 2. Metal Toolchain (install via: xcodebuild -downloadComponent MetalToolchain)
1314
/// 3. MLX device libraries to be available
15+
/// 4. MLX trait enabled (swift test --traits MLX)
1416
///
1517
/// Run tests with: xcodebuild test -scheme VecturaMLXKitTests -destination 'platform=macOS'
1618
/// (swift test may not work due to Metal library compilation requirements)
@@ -238,3 +240,4 @@ struct VecturaMLXKitTests {
238240
#expect(results.isEmpty, "Search should return no results when the query does not match any document.")
239241
}
240242
}
243+
#endif

codemagic.yaml

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,27 @@ definitions:
2828
# Set environment variables for model downloads
2929
export HF_HUB_OFFLINE=0
3030
31-
# Run core tests (excluding 30-min PerformanceTests suite)
31+
# Run core tests (excluding PerformanceTests and MLX-related tests)
32+
# MLX tests require the MLX trait to be enabled
3233
# Using --no-parallel to avoid concurrent model download issues
33-
swift test --no-parallel --skip PerformanceTests
34+
swift test --no-parallel \
35+
--skip PerformanceTests \
36+
--skip VecturaMLXKitTests
37+
- &run_tests_with_mlx
38+
name: Run Tests (with MLX)
39+
script: |
40+
#!/bin/zsh
41+
42+
# Set environment variables for model downloads
43+
export HF_HUB_OFFLINE=0
44+
45+
# Run all tests with MLX trait enabled
46+
swift test --no-parallel --traits MLX --skip PerformanceTests
3447
workflows:
3548
vecturakit:
3649
name: VecturaKit Workflow
3750
environment:
38-
xcode: 26.0
51+
xcode: 26.2
3952
vars:
4053
XCODE_SCHEME: "VecturaKit"
4154
APP_ID: "VecturaKit"
@@ -53,7 +66,7 @@ workflows:
5366
vecturamlxkit:
5467
name: VecturaMLXKit Workflow
5568
environment:
56-
xcode: 26.0
69+
xcode: 26.2
5770
vars:
5871
XCODE_SCHEME: "VecturaMLXKit"
5972
APP_ID: "VecturaMLXKit"
@@ -72,4 +85,4 @@ workflows:
7285
7386
xcodebuild -downloadComponent MetalToolchain
7487
- *build_framework
75-
- *run_tests
88+
- *run_tests_with_mlx

0 commit comments

Comments
 (0)