Skip to content

Add additionalContext support to MLXLanguageModel#145

Open
noorbhatia wants to merge 2 commits intomattt:mainfrom
noorbhatia:mlx-custom-generation-options
Open

Add additionalContext support to MLXLanguageModel#145
noorbhatia wants to merge 2 commits intomattt:mainfrom
noorbhatia:mlx-custom-generation-options

Conversation

@noorbhatia
Copy link
Contributor

@noorbhatia noorbhatia commented Mar 13, 2026

Add CustomGenerationOptions struct to MLXLanguageModel with an additionalContext: [String: JSONValue]? property for injecting variables into Jinja2 chat templates

Usage

var options = GenerationOptions()
options[custom: MLXLanguageModel.self] = .init(
    additionalContext: ["enable_thinking": .bool(true)]
)
let response = try await session.respond(to: "Hello", options: options)

@noorbhatia
Copy link
Contributor Author

Hi @mattt , can you take a look at this. Thanks!

Copy link
Owner

@mattt mattt left a comment

Choose a reason for hiding this comment

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

Sorry for not reviewing sooner. #147 also introduces MLXLanguageModel.CustomGenerationOptions, so we'll have to do some traffic control here. Should have both of these merged today.

Comment on lines +306 to +308
let additionalContext: [String: any Sendable]? = options[custom: MLXLanguageModel.self]
.flatMap { $0.additionalContext }
.map { $0.mapValues { $0.toSendable() } }
Copy link
Owner

Choose a reason for hiding this comment

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

This logic for converting from MLXLMCommon.JSONValue to Any values for UserInput is repeated a few times, so it'd probably make sense to move it into CustomGenerationOptions itself.

public struct CustomGenerationOptions: AnyLanguageModel.CustomGenerationOptions {
/// Additional key-value pairs injected into the chat template rendering context.
public var additionalContext: [String: MLXLMCommon.JSONValue]?

Copy link
Owner

Choose a reason for hiding this comment

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

Reminder to myself that we should add a parameter for UserInput.Processing in a follow-up.

@mattt mattt force-pushed the mlx-custom-generation-options branch from df19229 to d27310d Compare March 23, 2026 13:06
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for passing an additionalContext dictionary through GenerationOptions into MLXLMCommon’s chat-template rendering context, enabling callers to inject custom variables for Jinja2-based templates.

Changes:

  • Extends MLXLanguageModel.CustomGenerationOptions with additionalContext and threads it into MLXLMCommon.UserInput construction paths.
  • Adds a basic MLX test that exercises setting additionalContext via GenerationOptions.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
Sources/AnyLanguageModel/Models/MLXLanguageModel.swift Introduces additionalContext custom option and forwards it into MLX user input creation for standard, streaming, and structured generation flows.
Tests/AnyLanguageModelTests/MLXLanguageModelTests.swift Adds a regression test ensuring additionalContext can be set and a response is produced.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +211 to +216
/// Additional key-value pairs injected into the chat template rendering context.
public var additionalContext: [String: MLXLMCommon.JSONValue]?

var additionalContextForUserInput: [String: any Sendable]? {
additionalContext?.mapValues { $0.toSendable() }
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

additionalContext is exposed as [String: MLXLMCommon.JSONValue]?, which leaks the MLXLMCommon dependency into AnyLanguageModel’s public API. Other models’ custom options use the package-wide JSONValue (e.g., Anthropic’s extraBody: [String: JSONValue]?), so consider changing this to [String: JSONValue]? (or a typealias) and converting internally before building MLXLMCommon.UserInput.

Copilot uses AI. Check for mistakes.
case .int(let i): return i
case .double(let d): return d
case .bool(let b): return b
case .null: return NSNull()
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

MLXLMCommon.JSONValue.toSendable() maps .null to NSNull(), while elsewhere in this file nulls are represented as MLXLMCommon.JSONValue.null when converting JSON for Sendable contexts. Mixing null representations can lead to inconsistent template rendering and may also interact poorly with strict Sendable checking; prefer a single null representation (ideally MLXLMCommon.JSONValue.null if additionalContext ultimately expects Sendable values).

Suggested change
case .null: return NSNull()
case .null: return MLXLMCommon.JSONValue.null

Copilot uses AI. Check for mistakes.
Comment on lines 841 to 846
let userInput = MLXLMCommon.UserInput(
chat: chat,
processing: .init(resize: .init(width: 512, height: 512)),
tools: toolSpecs
tools: toolSpecs,
additionalContext: additionalContext,
)
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

makeUserInput(...) now appears unused, and MLXLMCommon.UserInput construction (including processing defaults) is duplicated in respond, streamResponse, and structured generation. To avoid drift and keep future changes (like additionalContext) consistent, consider updating makeUserInput to accept additionalContext and reusing it in these call sites, or removing the helper if you prefer inline construction.

Copilot uses AI. Check for mistakes.
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