Skip to content

Expose MLX sampler parameters and honor GenerationOptions.sampling - #231

Merged
mattt merged 5 commits into
mainfrom
mattt/mlx-sampler-cleanup
Sep 11, 2026
Merged

mattt merged 5 commits into
mainfrom
mattt/mlx-sampler-cleanup

Conversation

@mattt

@mattt mattt commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

@SpiraMira’s first two commits from #168, cherry-picked onto main with their authorship intact, plus test-formatting fixes and review follow-ups for greedy sampling, sampling seeds, structured-generation coverage, and option documentation.

MLX now reads GenerationOptions.sampling for top-k, top-p, and greedy sampling and exposes MLX-specific sampler controls through CustomGenerationOptions. Precedence is custom options, then sampling, then the existing defaults; structured generation retains its own defaults. Greedy sampling forces temperature zero in both paths, even when an explicit temperature is supplied. Top-k and nucleus seeds are forwarded in both paths; this requires mlx-swift-lm 3.31.4 or later, where per-generation seed support was added.

The speculative OS 27 toolCallingMode commit is excluded; #206 owns that SystemLanguageModel work. This replaces #168 because pushes to the contributor’s fork are blocked. Original description and review discussion: #168.

SpiraMira and others added 3 commits September 11, 2026 05:05
…onOptions

The MLX backend hardcoded sampling parameters in toGenerateParameters /
toStructuredGenerateParameters (topP: 1.0, repetitionPenalty: nil, topK/minP at
defaults) and never read GenerationOptions.sampling, so callers could only tune
temperature and maximumResponseTokens. MLXLMCommon.GenerateParameters already
supports the full set.

Add topP / topK / minP / repetitionPenalty / repetitionContextSize to
MLXLanguageModel.CustomGenerationOptions (all optional, default nil → existing
behavior unchanged) and forward them in both parameter mappers, preserving each
path's prior defaults via `custom?.field ?? <previous default>`.

Implements #165.
Reads the core GenerationOptions.sampling (SamplingMode) in toGenerateParameters /
toStructuredGenerateParameters so top-p/top-k/greedy set via the standard sampling
surface reach MLX, not only the custom block. Precedence: custom block wins, then
sampling-derived, then existing default. Seed is not forwarded (no per-call seed in
MLXLMCommon.GenerateParameters). Adds derivation + precedence tests.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Explicit temperature currently overrides greedy sampling, causing stochastic generation contrary to the sampling contract.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Exposes MLX sampler controls and maps core sampling options into MLX generation parameters.

Changes:

  • Adds MLX-specific sampler and repetition options.
  • Maps greedy, top-k, and nucleus sampling with precedence handling.
  • Adds parameter-mapping tests.
File summaries
File Description
Sources/AnyLanguageModel/Models/MLXLanguageModel.swift Adds and maps MLX sampling controls.
Tests/AnyLanguageModelTests/CustomGenerationOptionsTests.swift Tests sampling derivation and precedence.
Review details

Suppressed comments (3)

Sources/AnyLanguageModel/Models/MLXLanguageModel.swift:299

  • nil does not disable top-k when GenerationOptions.sampling supplies a top-k value; only an explicit 0 does. Document nil as deferring to core sampling and update the repeated initializer documentation.
            /// Set this to `nil` or `0` to disable top-k sampling.

Sources/AnyLanguageModel/Models/MLXLanguageModel.swift:309

  • For structured generation, nil resolves to the existing 1.1 penalty rather than disabling repetition. Document the path-dependent default and explain that 1.0 explicitly neutralizes the penalty; update the repeated initializer documentation too.
            /// Set this to `nil` to disable the repetition penalty.

Sources/AnyLanguageModel/Models/MLXLanguageModel.swift:1396

  • The structured path has the same precedence inversion: an explicit nonzero temperature defeats .greedy, so this no longer implements the sampling mode's argmax contract. Resolve greedyTemperature first here as well.
            temperature: Float(options.temperature ?? derived.greedyTemperature.map(Double.init) ?? 0.2),
  • Files reviewed: 2/2 changed files
  • Comments generated: 4
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Sources/AnyLanguageModel/Models/MLXLanguageModel.swift Outdated
Comment thread Sources/AnyLanguageModel/Models/MLXLanguageModel.swift Outdated
Comment thread Tests/AnyLanguageModelTests/CustomGenerationOptionsTests.swift Outdated
Comment thread Sources/AnyLanguageModel/Models/MLXLanguageModel.swift Outdated

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

MLX discards supported sampling seeds, leaving seeded generation nondeterministic.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

Previously missed (1) — in code that hasn't changed since the last review.

Sources/AnyLanguageModel/Models/MLXLanguageModel.swift:1360

  • This now drops the caller's sampling seed even though the compatible mlx-swift-lm 3.31.4 release exposes GenerateParameters.seed; the package requirement at Package.swift:45 can resolve that release, and the Ollama/Llama mappings already honor this field. As a result, .random(..., seed:) remains nondeterministic on MLX. Preserve the seed while destructuring .topK/.nucleus and pass it to both parameter constructors (with coverage for each path).

Sources/AnyLanguageModel/Models/MLXLanguageModel.swift:302

  • This says every non-nil value disables top-k, but positive values enable it. Document the fallback and positive-value behavior so callers are not instructed to do the opposite of the API's purpose.
            /// Set this to `nil` to inherit top-k sampling from `GenerationOptions.sampling`,
            /// otherwise disable top-k sampling. Set this to `0` to disable it explicitly.
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread Sources/AnyLanguageModel/Models/MLXLanguageModel.swift Outdated
@mattt
mattt merged commit 7ebfcf3 into main Sep 11, 2026
11 checks passed
@mattt
mattt deleted the mattt/mlx-sampler-cleanup branch September 11, 2026 13:07
mattt added a commit that referenced this pull request Sep 14, 2026
The MLX example predates the sampler fields added in #231,
and the llama.cpp example omits `assistantPrefill` from #198.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants