Skip to content

Fix concurrency issues due to preconcurrency imports and in MLTensor extension#430

Open
naykutguven wants to merge 4 commits intoargmaxinc:swift-6from
naykutguven:mltensor-fix
Open

Fix concurrency issues due to preconcurrency imports and in MLTensor extension#430
naykutguven wants to merge 4 commits intoargmaxinc:swift-6from
naykutguven:mltensor-fix

Conversation

@naykutguven
Copy link
Contributor

Swift 6 concurrency fixes for MLTensor extensions + async sampler integration

Summary

This PR resolves Swift 6 concurrency issues around MLTensor helper APIs by removing semaphore-based bridging and making tensor conversion helpers natively async. It propagates the async API to token sampling call sites and adds targeted unit tests for coverage.

What changed

  1. Updated MLTensor public helpers to async in Sources/WhisperKit/Utilities/Extensions+Public.swift:
    • asIntArray() -> [Int] -> asIntArray() async -> [Int]
    • asFloatArray() -> [Float] -> asFloatArray() async -> [Float]
    • asMLMultiArray() -> MLMultiArray -> asMLMultiArray() async -> MLMultiArray
  2. Removed DispatchSemaphore + Task blocking patterns in those helpers and replaced them with direct async shapedArray(of:) usage.
  3. Updated token sampling APIs in Sources/WhisperKit/Core/Text/TokenSampler.swift:
    • TokenSampling.update(...) is now async
    • GreedyTokenSampler.sampleWithMLTensor(...) is now async
    • Call sites now await tensor conversions.
  4. Updated decoder call sites in Sources/WhisperKit/Core/TextDecoder.swift to await tokenSampler.update(...).
  5. Added @preconcurrency import for framework interoperability:
    • Sources/WhisperKit/Utilities/Extensions+Public.swift: CoreML
    • Sources/WhisperKit/Core/Audio/AudioProcessor.swift: AVFoundation
  6. Added new test suite Tests/WhisperKitTests/MLTensorExtensionsTests.swift covering:
    • asIntArray
    • asFloatArray for Float32, FloatType, and Int32
    • asMLMultiArray round-trips for FloatType and Int32

Breaking changes (Before / After)

1) TokenSampling.update(...) is now async

Before

public protocol TokenSampling {
    func update(tokens: [Int], logits: MLMultiArray, logProbs: [Float]) -> SamplingResult
}

let sampleResult = tokenSampler.update(tokens: currentTokens, logits: logits, logProbs: logProbs)

After

public protocol TokenSampling {
    func update(tokens: [Int], logits: MLMultiArray, logProbs: [Float]) async -> SamplingResult
}

let sampleResult = await tokenSampler.update(tokens: currentTokens, logits: logits, logProbs: logProbs)

2) MLTensor helper methods are now async

Before

let ids = tensor.asIntArray()
let probs = tensor.asFloatArray()
let multiArray = tensor.asMLMultiArray()

After

let ids = await tensor.asIntArray()
let probs = await tensor.asFloatArray()
let multiArray = await tensor.asMLMultiArray()

3) Conforming sampler implementations must be async

Before

public func update(tokens: [Int], logits: MLMultiArray, logProbs: [Float]) -> SamplingResult

After

public func update(tokens: [Int], logits: MLMultiArray, logProbs: [Float]) async -> SamplingResult

Risk

  1. API migration risk for external callers due async signature changes.
  2. Runtime behavior is intended to remain equivalent for supported scalar types.
  3. @preconcurrency is intentionally used as an interoperability bridge with current SDK annotations.

Copilot AI review requested due to automatic review settings February 24, 2026 20:19
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

This PR updates WhisperKit’s CoreML MLTensor helper APIs and token sampling flow to be Swift 6 concurrency-safe by making tensor conversion helpers and sampling updates natively async, removing semaphore-based blocking, and adding tests for the new async helpers.

Changes:

  • Converted MLTensor helpers (asIntArray, asFloatArray, asMLMultiArray) to async and removed semaphore/Task blocking bridging.
  • Propagated async sampling through TokenSampling.update(...), GreedyTokenSampler.sampleWithMLTensor(...), and TextDecoder call sites.
  • Added @preconcurrency import for CoreML/AVFoundation interoperability and introduced a new async test suite for the tensor helpers.

Reviewed changes

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

Show a summary per file
File Description
Tests/WhisperKitTests/MLTensorExtensionsTests.swift Adds async unit tests covering the new async MLTensor conversion helpers.
Sources/WhisperKit/Utilities/Extensions+Public.swift Makes MLTensor helper conversions async; adds @preconcurrency import CoreML.
Sources/WhisperKit/Core/TextDecoder.swift Updates decoding flow to await the now-async sampler update.
Sources/WhisperKit/Core/Text/TokenSampler.swift Makes sampling update async and integrates async tensor conversion calls.
Sources/WhisperKit/Core/Audio/AudioProcessor.swift Switches to @preconcurrency import AVFoundation for concurrency annotation compatibility.

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

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
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.

2 participants