Skip to content

feat: Add iOS 26 Foundation Models framework support for Apple Intelligence LLM#42

Merged
pablof7z merged 1 commit into
masterfrom
feature/apple-intelligence-ios26
Dec 28, 2025
Merged

feat: Add iOS 26 Foundation Models framework support for Apple Intelligence LLM#42
pablof7z merged 1 commit into
masterfrom
feature/apple-intelligence-ios26

Conversation

@pablof7z

Copy link
Copy Markdown
Collaborator

Summary

  • Updates Apple Intelligence capability detection to use the new Foundation Models framework introduced in iOS 26
  • Fixes the issue where Apple Intelligence was not appearing as an LLM provider option on compatible devices (including iPhone 17)
  • Adds complete device identifier support for iPhone 15 Pro through iPhone 17 series

Changes

  • AICapabilityDetector.swift: Updated device identifiers, added Foundation Models availability check, added getAppleIntelligenceAvailability() method with detailed status
  • AppleIntelligenceLLMService.swift: New service for interacting with Apple's on-device LLM via Foundation Models framework
  • Tests: Added comprehensive tests for new functionality

Device Compatibility Updated

Device Identifier
iPhone 15 Pro iPhone16,1
iPhone 15 Pro Max iPhone16,2
iPhone 16 Pro iPhone17,1
iPhone 16 Pro Max iPhone17,2
iPhone 16 iPhone17,3
iPhone 16 Plus iPhone17,4
iPhone 16e iPhone17,5
iPhone 17 Pro iPhone18,1
iPhone 17 Pro Max iPhone18,2
iPhone 17 iPhone18,3
iPads with M1+ iPad13,4+, iPad14,x, iPad16,x

Test Plan

  • Verify Apple Intelligence appears in LLM provider list on compatible devices running iOS 26
  • Test availability detection returns correct reason when unavailable
  • Verify fallback behavior on iOS < 26
  • Run unit tests

References

🤖 Generated with Claude Code

…igence LLM

Updates Apple Intelligence capability detection to use the new Foundation Models
framework introduced in iOS 26. This fixes the issue where Apple Intelligence was
not appearing as an LLM provider option on compatible devices.

Changes:
- Update device identifiers to include iPhone 17 series (iPhone18,x)
- Add Foundation Models framework integration for iOS 26+
- Create AppleIntelligenceLLMService with streaming support
- Add detailed availability status with specific unavailability reasons
- Update tests for new functionality

Device compatibility updated:
- iPhone 15 Pro/Pro Max (iPhone16,1/16,2)
- iPhone 16 series (iPhone17,1-5)
- iPhone 17 series (iPhone18,1-3)
- iPads with M1+ chips (iPad13,4+, iPad14,x, iPad16,x)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@claude

claude Bot commented Dec 28, 2025

Copy link
Copy Markdown

Pull Request Review

Overall Assessment

This is a well-structured PR that adds iOS 26 Foundation Models framework support for Apple Intelligence. The code quality is high, with good error handling, comprehensive testing, and thoughtful API design. I've identified a few areas for improvement below.


Code Quality & Best Practices ✅

Strengths:

  • Excellent separation of concerns: The protocol-based design allows for easy testing and future modifications
  • Proper use of Swift concurrency: Actor isolation for AppleIntelligenceLLMServiceImpl is appropriate for thread-safe state management
  • Good use of conditional compilation: #if canImport(FoundationModels) ensures backward compatibility
  • Comprehensive error handling: Custom error types with descriptive messages
  • Backward compatibility: Convenience initializer in MockAICapabilityDetector maintains existing API

Suggested Improvements:

1. Session Management Could Cause Issues ⚠️
In AppleIntelligenceLLMService.swift:245-262, the session caching logic only checks if instructions match:

private func getOrCreateSession(instructions: String?) async throws -> LanguageModelSession {
    if let session = currentSession, instructions == cachedInstructions {
        return session
    }
    // Creates new session...
}

Issue: If the same instructions are used but the previous session encountered an error or was invalidated, you'd be reusing a potentially broken session.

Recommendation: Consider adding session health checks or error recovery logic:

private func getOrCreateSession(instructions: String?) async throws -> LanguageModelSession {
    // Check if session is still valid
    if let session = currentSession, 
       instructions == cachedInstructions,
       await isSessionHealthy(session) {
        return session
    }
    // Create new session...
}

2. Memory Management for Long-Running Sessions 💭
The currentSession is never explicitly invalidated. For a long-running app, this could potentially hold resources.

Recommendation: Consider adding a method to explicitly clear the session:

public func clearSession() async {
    currentSession = nil
    cachedInstructions = nil
}

Potential Bugs 🐛

1. Missing Error Propagation in Stream ⚠️
In AppleIntelligenceLLMService.swift:191-200, the streaming implementation catches errors but doesn't distinguish between expected completion and actual errors:

return AsyncThrowingStream { continuation in
    Task {
        do {
            let stream = session.streamResponse(to: prompt, options: genOptions)
            for try await partialResponse in stream {
                continuation.yield(partialResponse.content)
            }
            continuation.finish()
        } catch {
            continuation.finish(throwing: AppleIntelligenceError.generationFailed(error.localizedDescription))
        }
    }
}

Issue: The Task is not stored or tracked, so if the caller is deallocated, this could continue running.

Recommendation: Consider using a weak reference or task cancellation:

return AsyncThrowingStream { continuation in
    let task = Task {
        do {
            // ... stream logic
        } catch is CancellationError {
            continuation.finish(throwing: CancellationError())
        } catch {
            continuation.finish(throwing: AppleIntelligenceError.generationFailed(error.localizedDescription))
        }
    }
    continuation.onTermination = { @Sendable _ in
        task.cancel()
    }
}

2. Device Identifier Detection Edge Case 🔍
In AICapabilityDetector.swift:168-171, the iPad detection includes specific models but uses prefixes for newer ones:

"iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7",
"iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11",
"iPad14,",  // Prefix match

Question: Why are iPad13 models explicitly listed but iPad14+ use prefix matching? This inconsistency could cause confusion.

Recommendation: Either be consistent (all prefixes or all explicit), or add a comment explaining why iPad13 needs specific model numbers.


Performance Considerations ⚡

1. Excellent Performance Characteristics

  • Session reuse reduces initialization overhead ✅
  • Streaming API prevents memory buildup for long responses ✅
  • Prewarm capability allows optimization of first-request latency ✅

2. Minor Optimization Opportunity
In AICapabilityDetector.swift:141-175, device detection iterates through strings on every call. Consider caching the device identifier:

private static let cachedDeviceIdentifier: String = {
    var systemInfo = utsname()
    uname(&systemInfo)
    let machine = systemInfo.machine
    var identifier = ""
    let mirror = Mirror(reflecting: machine)
    for child in mirror.children {
        guard let value = child.value as? Int8, value != 0 else { break }
        identifier += String(UnicodeScalar(UInt8(value)))
    }
    return identifier
}()

private func isCompatibleDevice() -> Bool {
    let identifier = Self.cachedDeviceIdentifier
    // ... rest of logic
}

Security Concerns 🔒

1. No Security Issues Identified

  • Proper use of framework APIs
  • No hardcoded credentials or sensitive data
  • Error messages don't leak sensitive information
  • Good use of @unchecked Sendable only where necessary

2. Privacy Consideration 💭
The Foundation Models framework processes data on-device, which is excellent for privacy. However, consider documenting:

  • What data is sent to the model
  • Whether conversation history is retained
  • User consent requirements (if any)

Recommendation: Add documentation about privacy implications:

/// Apple Intelligence LLM service using Foundation Models framework
/// 
/// Privacy: All processing happens on-device. No data is sent to Apple's servers.
/// The session maintains conversation context until cleared via clearSession().
public protocol AppleIntelligenceLLMService: Sendable {
    // ...
}

Test Coverage 🧪

Strengths:

  • Comprehensive test coverage for error cases ✅
  • Tests for temperature clamping edge cases ✅
  • Equality tests for enums ✅
  • Fallback service behavior tested ✅

Gaps:

1. Missing Integration Tests
No tests verify actual Foundation Models integration (understandable given iOS 26 requirement, but could use mocks)

2. Missing Tests for Session Reuse
The session caching logic in getOrCreateSession isn't tested. Consider adding:

@Test("Session reuse with same instructions")
@available(iOS 26.0, *)
func sessionReuseWithSameInstructions() async throws {
    // Test that session is reused when instructions match
}

@Test("New session created when instructions change")
@available(iOS 26.0, *)
func newSessionWhenInstructionsChange() async throws {
    // Test that new session is created when instructions differ
}

3. Missing Stream Cancellation Test
Should verify that cancelling a stream properly cleans up:

@Test("Stream cancellation cleans up properly")
func streamCancellation() async throws {
    // Test cancellation behavior
}

Additional Recommendations 📝

1. Documentation
Consider adding more inline documentation for the availability states:

/// Reasons why Apple Intelligence might be unavailable
public enum AppleIntelligenceUnavailableReason: Sendable, Equatable {
    /// Device doesn't have required hardware (A17+ or M1+ chip)
    case deviceNotEligible
    /// User has not enabled Apple Intelligence in Settings
    case appleIntelligenceNotEnabled
    /// Model is still downloading or not fully initialized
    case modelNotReady
    /// iOS version is below 26.0
    case unsupportedOS
    /// Unknown reason (future-proofing for new cases)
    case unknownReason
}

2. Usage Example
Consider adding a usage example in the file header:

/// Example:
/// ```swift
/// let service = AppleIntelligenceLLMServiceFactory.create()
/// 
/// // Check availability
/// switch service.checkAvailability() {
/// case .available:
///     let response = try await service.generate(
///         prompt: "Summarize this text",
///         instructions: "Be concise",
///         options: AppleIntelligenceGenerationOptions(temperature: 0.7)
///     )
///     print(response.content)
/// case .unavailable(let reason):
///     print("Unavailable: \(reason)")
/// }
/// ```

Summary

Approve with minor suggestions

This is high-quality code that follows Swift best practices and provides a clean API for Apple Intelligence integration. The identified issues are minor and mostly relate to edge cases and documentation. The core implementation is solid.

Priority fixes before merge:

  • None blocking

Recommended for follow-up:

  • Add session health checks (Low priority)
  • Add stream cancellation handling (Low priority)
  • Expand test coverage for session management (Medium priority)
  • Add usage documentation (Low priority)

Great work on this implementation!

@pablof7z pablof7z merged commit acf3bf5 into master Dec 28, 2025
3 of 4 checks passed
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.

1 participant