Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 7 additions & 7 deletions Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ let package = Package(
),
.package(
url: "https://github.com/shareup/mlx-swift-lm",
from: "0.0.14"
from: "0.0.16"
),
.package(
url: "https://github.com/DePasqualeOrg/swift-tokenizers",
Expand Down Expand Up @@ -49,6 +49,9 @@ let package = Package(
// .copy("Resources/gemma-3-27b-it-qat-4bit"),
// .copy("Resources/gemma-3-4b-it-qat-3bit"),
// .copy("Resources/gemma-3-4b-it-qat-4bit"),
// .copy("Resources/gemma-4-e2b-it-4bit"),
// .copy("Resources/gemma-4-e4b-it-4bit"),
// .copy("Resources/gemma-4-12B-it-4bit"),
// .copy("Resources/gpt-oss-20b-MLX-8bit"),
// .copy("Resources/gpt-oss-20b-MXFP4-Q4"),
// .copy("Resources/LFM2-8B-A1B-4bit"),
Expand Down
133 changes: 132 additions & 1 deletion Sources/SHLLM/LLM.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public struct LLM<Model: LanguageModel>: AsyncSequence {
}

case let .loaded(context):
let toolSchemas = input.tools
let input = try await context.processor.prepare(input: input)
var params = generateParameters
if let maxOutputTokenCount {
Expand All @@ -153,7 +154,8 @@ public struct LLM<Model: LanguageModel>: AsyncSequence {
let stream = try MLXLMCommon.generate(
input: input,
parameters: params,
context: context
context: context,
tools: toolSchemas
)

var iterator = stream.makeAsyncIterator()
Expand Down Expand Up @@ -625,6 +627,135 @@ extension LLM where Model == Gemma3 {
}
}

// MARK: - Gemma 4 Vision

extension LLM where Model == Gemma4 {
/// **gemma-4-e2b** and **gemma-4-e4b**
///
/// To enable thinking, set
/// `UserInput(additionalContext: ["enable_thinking": true])`
/// and add `<|think|>` to the **beginning** and **end** of
/// the system prompt. (The documentation says to just add it to
/// the beginning of the system prompt, but testing has shown it
/// to be more reliable when added to the beginning and end of the
/// system prompt.
///
/// https://huggingface.co/google/gemma-4-12B-it#2-thinking-mode-configuration
public static func gemma4(
directory: URL,
input: UserInput,
tools: [any ToolProtocol] = [],
maxInputTokenCount: Int? = nil,
maxOutputTokenCount: Int? = nil
) throws -> LLM<Gemma4> {
try SHLLM.assertSupportedDevice
return .init(
directory: directory,
input: input,
tools: tools,
maxInputTokenCount: maxInputTokenCount,
maxOutputTokenCount: maxOutputTokenCount,
customConfiguration: { config in
var config = config
config.extraEOSTokens = ["<turn|>"]
return config
},
generateParameters: generateParameters,
responseParser: gemma4Parser
)
}

// https://huggingface.co/google/gemma-4-E2B-it#best-practices
//
// 1. Sampling Parameters
//
// - temperature=1.0
// - top_p=0.95
// - top_k=64
static var generateParameters: GenerateParameters {
GenerateParameters(
temperature: 1.0,
topP: 0.95,
topK: 64
)
}

static var gemma4_E2B: URL {
get throws {
let dir = "gemma-4-e2b-it-4bit"
return try Bundle.shllm.directory(named: dir)
}
}

static var gemma4_E4B: URL {
get throws {
let dir = "gemma-4-e4b-it-4bit"
return try Bundle.shllm.directory(named: dir)
}
}
}

// MARK: - Gemma 4 Unified Vision

extension LLM where Model == Gemma4Unified {
/// **gemma-4-12b**
///
/// To enable thinking, set
/// `UserInput(additionalContext: ["enable_thinking": true])`
/// and add `<|think|>` to the **beginning** and **end** of
/// the system prompt. (The documentation says to just add it to
/// the beginning of the system prompt, but testing has shown it
/// to be more reliable when added to the beginning and end of the
/// system prompt.
///
/// https://huggingface.co/google/gemma-4-12B-it#2-thinking-mode-configuration
public static func gemma4Unified(
directory: URL,
input: UserInput,
tools: [any ToolProtocol] = [],
maxInputTokenCount: Int? = nil,
maxOutputTokenCount: Int? = nil
) throws -> LLM<Gemma4Unified> {
try SHLLM.assertSupportedDevice
return .init(
directory: directory,
input: input,
tools: tools,
maxInputTokenCount: maxInputTokenCount,
maxOutputTokenCount: maxOutputTokenCount,
customConfiguration: { config in
var config = config
config.extraEOSTokens = ["<turn|>"]
return config
},
generateParameters: generateParameters,
responseParser: gemma4Parser
)
}

// https://huggingface.co/google/gemma-4-12B-it#best-practices
//
// 1. Sampling Parameters
//
// - temperature=1.0
// - top_p=0.95
// - top_k=64
static var generateParameters: GenerateParameters {
GenerateParameters(
temperature: 1.0,
topP: 0.95,
topK: 64
)
}

static var gemma4_12B: URL {
get throws {
let dir = "gemma-4-12B-it-4bit"
return try Bundle.shllm.directory(named: dir)
}
}
}

// MARK: - gpt-oss

extension LLM where Model == GPTOSSModel {
Expand Down
Loading
Loading