Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2a76e56
Track the current SDK's SamplingMode.Kind case names (#431)
CharlieTLe Jul 17, 2026
51b0fce
update tag on swift-format -- I had it wrong (#421)
davidkoski Jul 17, 2026
9cd1a48
Fix FoundationModels API drift and the integration tests that no long…
thechriswebb Jul 17, 2026
e69d0a9
fix(MLXFoundationModels): prepare tool-calling input through the mode…
jyauxi Jul 17, 2026
616cae2
Make BaseKVCache.ropeOffset overridable (#437)
GoodOlClint Jul 17, 2026
1c86cc1
fix(MLXFoundationModels): stop respond() crashing when emitting usage…
thechriswebb Jul 17, 2026
343cae3
Silence Metal compiler warning noise in integration test runs (#440)
CharlieTLe Jul 17, 2026
fd0f13b
add TurboQuant KV cache compression (#232)
TheTom Jul 20, 2026
6608a35
Expose minimal Gemma3 surface for frozen-text-encoder use (#387)
xocialize Jul 21, 2026
bc95ffb
Load EOS token IDs from nested text configs (#449)
aleroot Jul 21, 2026
f1bfca4
Optimize Qwen3.5 interleaved M-RoPE (#442)
aleroot Jul 21, 2026
e6e3de7
MLXLLM Gemma4Text: add MoE block (router + experts) (#364)
neuromechanist Jul 21, 2026
8e3b3f0
Fix MTP integration test skip semantics; auto-download 31B checkpoint…
CharlieTLe Jul 21, 2026
78eaa5b
Enable MTP speculative decoding for Gemma 4 12B (gemma4_unified targe…
fdagostino Jul 21, 2026
1032402
Hoist tool-schema $defs to the tool-calling envelope root (fixes #432…
jyauxi Jul 22, 2026
f7cacbc
Qwen3VL vision: per-image fused SDPA instead of a dense joint mask (#…
kklimuk Jul 22, 2026
eaefe75
Add regression coverage for mixed-precision quantized checkpoint load…
fdagostino Jul 22, 2026
12d2da0
DeepSeek-V3: populate kvHeads and update the KV cache once per attent…
GoodOlClint Jul 22, 2026
9d3a497
Support multi-round tool calling in MLXFoundationModels (#456)
thechriswebb Jul 23, 2026
294c31f
Add DeepSeek-V2 model (#379)
GoodOlClint Jul 23, 2026
5cd767e
Add Hunyuan dense V1 (hunyuan_v1_dense): Hunyuan-MT-7B and Hy-MT2-7B …
beshkenadze Jul 23, 2026
5fbb130
Add GitHub workflow for IntegrationTesting tests (#458)
CharlieTLe Jul 23, 2026
18edd22
Add end-to-end video input to the base Gemma 4 (gemma4) VLM (#391)
fdagostino Jul 23, 2026
3cbf928
Integration tests: build on both macOS 26 and 27 SDKs (#464)
CharlieTLe Jul 24, 2026
e467a72
Merge upstream/main: Gemma4 video input + audio coexistence, MTP 12B,…
Satchitananda Jul 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/integration_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Integration Tests

# Heavy integration tests (Hugging Face model downloads, Metal GPU, long-running).
# Kept out of the PR path so they never block merges
on:
workflow_dispatch:

permissions:
contents: read

jobs:
integration_tests:
if: github.repository == 'ml-explore/mlx-swift-lm'
runs-on: [self-hosted, macos]
timeout-minutes: 120
steps:
- uses: actions/checkout@v6
with:
submodules: recursive

- name: Select Xcode
shell: bash
run: |
# The FoundationModels integration tests only build against the macOS 27
# SDK (canImport(FoundationModels, _version: 2)); on the macOS 26 SDK the
# MLXFoundationModels adapter compiles out and those tests are skipped.
# Prefer Xcode 27 when the runner has it so the full suite runs; otherwise
# fall back to the default toolchain and run the SDK-agnostic tests.
dev=""
for app in /Applications/Xcode_27*.app /Applications/Xcode-27*.app /Applications/Xcode.app; do
[ -d "$app" ] || continue
v=$("$app/Contents/Developer/usr/bin/xcodebuild" -version 2>/dev/null | head -1)
case "$v" in "Xcode 27"*) dev="$app/Contents/Developer" ;; esac
[ -n "$dev" ] && break
done
if [ -n "$dev" ]; then
echo "Using Xcode 27 at $dev (full suite, incl. FoundationModels tests)"
echo "DEVELOPER_DIR=$dev" >> "$GITHUB_ENV"
else
echo "Xcode 27 not found; using default $(xcode-select -p)."
echo "FoundationModels tests will be compiled out (macOS 27 SDK required)."
fi

- name: Verify MetalToolchain installed
shell: bash
run: xcodebuild -showComponent MetalToolchain

- name: Run IntegrationTesting tests (Xcode, macOS)
shell: sh
run: |
xcodebuild -version
swift --version
# Model-dependent tests must run in a single xctest worker: concurrent
# workers race on the shared on-disk Hugging Face cache. Disable parallel
# testing (see IntegrationTestingTests/.../Support/FMTestHelpers.swift).
xcodebuild test \
-project IntegrationTesting/IntegrationTesting.xcodeproj \
-scheme IntegrationTesting \
-destination 'platform=macOS' \
-parallel-testing-enabled NO \
-skipPackagePluginValidation \
-resultBundlePath IntegrationTesting.xcresult

- name: Upload test results
if: failure()
uses: actions/upload-artifact@v4
with:
name: integration-test-results
path: |
IntegrationTesting.xcresult
~/Library/Logs/DiagnosticReports/*
retention-days: 7
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
</BuildableReference>
</TestableReference>
</Testables>
<EnvironmentVariables>
<EnvironmentVariable
key = "OS_ACTIVITY_MODE"
value = "disable"
isEnabled = "YES">
</EnvironmentVariable>
</EnvironmentVariables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright © 2026 Apple Inc.

import Foundation
import HuggingFace
import IntegrationTestHelpers
import MLX
import MLXHuggingFace
import MLXLMCommon
import MLXNN
@_spi(Testing) import MLXVLM
Expand Down Expand Up @@ -35,16 +37,34 @@ private func drafterForwardFixturesOrSkip(name: String) async -> URL? {
// on MLX runtime state and produce non-deterministic numeric divergence in
// the Rung 2/3 forward parity assertion.

/// Model ID of the 31B assistant drafter checkpoint shared by the tests below.
private let drafter31BModelId = "mlx-community/gemma-4-31B-it-assistant-bf16"

/// Pinned checkpoint revision matching the weights that were live when the
/// Rung 4 `drafter_block` fixtures were generated. Kept in sync with
/// `MTPRung4TokenParityTests`.
private let drafter31BRevision = "28e92270316e89288579ec59c17939541d9ca433"

/// Shared downloader for the drafter checkpoint. Fetches to the local HF
/// cache on first use; subsequent tests and runs reuse the cache.
private let downloader: any Downloader = #hubDownloader()

private func drafter31BDirectory() async throws -> URL {
try await downloader.download(
id: drafter31BModelId,
revision: drafter31BRevision,
matching: ["*.safetensors", "*.json"],
useLatest: false,
progressHandler: { _ in }
)
}

@Suite(.serialized)
struct Gemma4AssistantIntegrationTests {

@Test
func testGemma4AssistantConfigurationDecodesRealCheckpoint() throws {
let drafterDir = hfSnapshotDir(modelId: "mlx-community/gemma-4-31B-it-assistant-bf16")
guard let drafterDir else {
Issue.record("31B drafter checkpoint not present in HF cache; skipping")
return
}
func testGemma4AssistantConfigurationDecodesRealCheckpoint() async throws {
let drafterDir = try await drafter31BDirectory()
let configURL = drafterDir.appendingPathComponent("config.json")
let data = try Data(contentsOf: configURL)
let cfg = try JSONDecoder().decode(Gemma4AssistantConfiguration.self, from: data)
Expand All @@ -64,13 +84,8 @@ struct Gemma4AssistantIntegrationTests {
}

@Test
func testRung1WeightsLoadFrom31BCheckpoint() throws {
guard
let drafterDir = hfSnapshotDir(modelId: "mlx-community/gemma-4-31B-it-assistant-bf16")
else {
Issue.record("31B drafter checkpoint not in HF cache; skipping Rung 1")
return
}
func testRung1WeightsLoadFrom31BCheckpoint() async throws {
let drafterDir = try await drafter31BDirectory()
let configURL = drafterDir.appendingPathComponent("config.json")
let cfg = try JSONDecoder().decode(
Gemma4AssistantConfiguration.self, from: Data(contentsOf: configURL))
Expand All @@ -86,12 +101,7 @@ struct Gemma4AssistantIntegrationTests {
guard let fixturesDir = await drafterForwardFixturesOrSkip(name: "case_01") else {
return
}
guard
let drafterDir = hfSnapshotDir(modelId: "mlx-community/gemma-4-31B-it-assistant-bf16")
else {
Issue.record("31B drafter checkpoint not in HF cache; skipping Rung 2/3")
return
}
let drafterDir = try await drafter31BDirectory()

let configURL = drafterDir.appendingPathComponent("config.json")
let cfg = try JSONDecoder().decode(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright © 2026 Apple Inc.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
// Gated on both traits because the tokenizer path routes through the
// same `loadTestModelContainer` as the bridge tests.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
// Gated on both traits because the tokenizer path routes through
// `loadTestModelContainer` the same as the other integration tests.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright © 2025 Apple Inc.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down Expand Up @@ -33,10 +33,8 @@ struct GenerableRoundTripTests {
let stream = try await executeResponse(executor, request: request, model: model)
var text = ""
for try await event in stream {
if let response = event as? LanguageModelExecutorGenerationChannel.Response,
case .appendText(let delta) = response.action
{
text += delta.content
if case .appendText(let chunk, _, .response) = event {
text += chunk
}
}
return text
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// text because the schema -- a single `const` string field -- forces
// the entire body as FF after the opening `{`.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
// `loadTestModelContainer`. The GrammarConstraint type lives in the
// MLXGuidedGeneration library and is always available alongside the adapter.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// Gated on both traits because the tokenizer path routes through
// `loadTestModelContainer`.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
// `loadTestModelContainer`. `GrammarConstraint` lives in the
// MLXGuidedGeneration library and is always available alongside the adapter.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// Gated on both traits because the tokenizer path routes through
// the same `loadTestModelContainer` as the other tests.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright © 2026 Apple Inc.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
// fixture is not yet available. Llama-3 coverage is pending its
// `tokenizer_llama3.json` fixture.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright © 2025 Apple Inc.

#if FoundationModelsIntegration
#if FoundationModelsIntegration && canImport(FoundationModels, _version: 2)

import Testing
import Foundation
Expand Down
Loading