diff --git a/CHANGELOG.md b/CHANGELOG.md index e6fc037..f528774 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes to IntelligenceBridge are documented here. ## Unreleased +### Added + +- Add a Foundation Models availability value that maps Apple's on-device model state to stable reasons and reports + unsupported platforms explicitly. +- Re-export Apple's Foundation Models APIs on supported platforms so consumers can use `SystemLanguageModel`, + `LanguageModelSession`, `@Generable`, and `@Guide` directly. + ### Changed - Rename the package, product, module, documentation, repository-facing links, logging subsystem, and canonical emoji to IntelligenceBridge 🧠 while preserving the Image Playground-specific public API. diff --git a/README.md b/README.md index 0934710..c36f819 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,9 @@ # IntelligenceBridge -IntelligenceBridge is a focused Apple-platform integration layer for Apple intelligence capabilities such as Image Playground. It makes platform availability, framework integration, and presentation seams consistent without hiding Apple's frameworks or taking ownership of product prompts and persistence. 🧠 +IntelligenceBridge is a focused Apple-platform integration layer for Apple intelligence capabilities such as Image Playground +and Foundation Models. It makes platform availability, framework integration, and presentation seams consistent without +hiding Apple's frameworks or taking ownership of product prompts and persistence. 🧠 Image Playground is the package's first capability. Its existing API centralizes availability checks, concept setup, SwiftUI presentation wiring, cancellation, and temporary result handling while leaving generated-media persistence to the host application. @@ -32,6 +34,26 @@ content The presentation API is available on Apple platforms that support Image Playground. The package also compiles on tvOS so shared multiplatform application targets can resolve it, while ``ImagePlaygroundBridgeAvailability/current`` reports unavailable there. +Foundation Models support preserves Apple's native API surface. Importing IntelligenceBridge on a supported platform also +makes `SystemLanguageModel`, `LanguageModelSession`, `@Generable`, and `@Guide` available. Use the bridge availability value +to decide whether to offer model-backed behavior while keeping prompts, sessions, generated values, and product policy in +the host application. + +```swift +import IntelligenceBridge + +guard FoundationModelBridgeAvailability.current == .available else { + return +} + +let session = LanguageModelSession() +``` + +The availability mapping follows Apple's +[`SystemLanguageModel.Availability`](https://developer.apple.com/documentation/foundationmodels/systemlanguagemodel/availability-swift.enum). +It distinguishes disabled Apple Intelligence, an ineligible device, a model that is not ready, and an unsupported platform. +The package does not wrap `LanguageModelSession` or introduce a generic language-model abstraction. + ## Documentation API documentation is published with DocC after a GitHub release. See the [IntelligenceBridge documentation](https://thatfactory.github.io/intelligence-bridge/documentation/intelligencebridge/). diff --git a/Sources/IntelligenceBridge/FoundationModelBridgeAvailability.swift b/Sources/IntelligenceBridge/FoundationModelBridgeAvailability.swift new file mode 100644 index 0000000..35ab731 --- /dev/null +++ b/Sources/IntelligenceBridge/FoundationModelBridgeAvailability.swift @@ -0,0 +1,74 @@ +#if canImport(FoundationModels) && !os(tvOS) + @_exported import FoundationModels +#endif + +/// Describes whether Apple's on-device foundation model is available. +public enum FoundationModelBridgeAvailability: Equatable, Sendable { + /// The on-device foundation model is available. + case available + + /// The on-device foundation model is unavailable for the associated reason. + case unavailable(Reason) + + /// A reason the on-device foundation model is unavailable. + public enum Reason: Equatable, Sendable { + /// Apple Intelligence is disabled in system settings. + case appleIntelligenceNotEnabled + + /// The current device does not support Apple Intelligence. + case deviceNotEligible + + /// The on-device model is not ready yet. + case modelNotReady + + /// The framework is unavailable on the current platform. + case unsupportedPlatform + + /// The framework reported an unavailable reason unknown to this version of the package. + case other + } + + /// The current device's on-device foundation-model capability. + public static var current: Self { + #if canImport(FoundationModels) && !os(tvOS) + Self(SystemLanguageModel.default.availability) + #else + unsupportedPlatform + #endif + } + + #if canImport(FoundationModels) && !os(tvOS) + /// Creates a bridge availability value from Apple's model availability. + /// + /// - Parameter availability: The availability reported by a system language model. + public init(_ availability: SystemLanguageModel.Availability) { + switch availability { + case .available: + self = .available + case .unavailable(let reason): + self = .unavailable(Self.bridgeReason(for: reason)) + } + } + #endif + + static var unsupportedPlatform: Self { + .unavailable(.unsupportedPlatform) + } + + #if canImport(FoundationModels) && !os(tvOS) + static func bridgeReason( + for reason: SystemLanguageModel.Availability.UnavailableReason + ) -> Reason { + switch reason { + case .appleIntelligenceNotEnabled: + .appleIntelligenceNotEnabled + case .deviceNotEligible: + .deviceNotEligible + case .modelNotReady: + .modelNotReady + @unknown default: + .other + } + } + #endif +} diff --git a/Sources/IntelligenceBridge/IntelligenceBridge.docc/IntelligenceBridge.md b/Sources/IntelligenceBridge/IntelligenceBridge.docc/IntelligenceBridge.md index 2db5471..bcceb0d 100644 --- a/Sources/IntelligenceBridge/IntelligenceBridge.docc/IntelligenceBridge.md +++ b/Sources/IntelligenceBridge/IntelligenceBridge.docc/IntelligenceBridge.md @@ -8,6 +8,12 @@ Image Playground is the package's first capability. Use ``ImagePlaygroundBridgeA Image Playground supplies ``ImagePlaygroundBridgeResult/temporaryURL`` only as temporary output. The completion callback is the host application's ownership boundary: copy the file into durable, application-owned storage before returning. IntelligenceBridge never persists images, reads a photo library, synchronizes media, or owns product-specific prompts. +For Foundation Models, use ``FoundationModelBridgeAvailability/current`` to decide whether to offer model-backed behavior. +On supported platforms, importing IntelligenceBridge also exposes Apple's +[`FoundationModels`](https://developer.apple.com/documentation/foundationmodels) APIs, including `SystemLanguageModel`, +`LanguageModelSession`, `@Generable`, and `@Guide`. The host application owns prompts, sessions, generated values, and +product policy; IntelligenceBridge does not wrap Apple's session API or define a generic language-model abstraction. + ## Topics ### Availability and requests @@ -19,3 +25,8 @@ Image Playground supplies ``ImagePlaygroundBridgeResult/temporaryURL`` only as t ### Presentation results - ``ImagePlaygroundBridgeResult`` + +### Foundation Models + +- ``FoundationModelBridgeAvailability`` +- ``FoundationModelBridgeAvailability/Reason`` diff --git a/Tests/IntelligenceBridgeTests/FoundationModelBridgeAvailabilityTests.swift b/Tests/IntelligenceBridgeTests/FoundationModelBridgeAvailabilityTests.swift new file mode 100644 index 0000000..fb422cf --- /dev/null +++ b/Tests/IntelligenceBridgeTests/FoundationModelBridgeAvailabilityTests.swift @@ -0,0 +1,49 @@ +import Testing + +@testable import IntelligenceBridge + +#if canImport(FoundationModels) && !os(tvOS) + import FoundationModels + + @Test("Foundation Models availability maps to available") + func foundationModelsAvailabilityMapsToAvailable() { + #expect( + FoundationModelBridgeAvailability(.available) == .available + ) + } + + @Test( + "Foundation Models unavailable reasons map deterministically", + arguments: [ + ( + SystemLanguageModel.Availability.UnavailableReason.appleIntelligenceNotEnabled, + FoundationModelBridgeAvailability.Reason.appleIntelligenceNotEnabled + ), + ( + SystemLanguageModel.Availability.UnavailableReason.deviceNotEligible, + FoundationModelBridgeAvailability.Reason.deviceNotEligible + ), + ( + SystemLanguageModel.Availability.UnavailableReason.modelNotReady, + FoundationModelBridgeAvailability.Reason.modelNotReady + ), + ] + ) + func foundationModelsUnavailableReasonsMapDeterministically( + reason: SystemLanguageModel.Availability.UnavailableReason, + expectedReason: FoundationModelBridgeAvailability.Reason + ) { + #expect( + FoundationModelBridgeAvailability(.unavailable(reason)) + == .unavailable(expectedReason) + ) + } +#endif + +@Test("Unsupported platforms use a deterministic fallback") +func unsupportedPlatformsUseDeterministicFallback() { + #expect( + FoundationModelBridgeAvailability.unsupportedPlatform + == .unavailable(.unsupportedPlatform) + ) +} diff --git a/Tests/IntelligenceBridgeTests/FoundationModelsConsumerTests.swift b/Tests/IntelligenceBridgeTests/FoundationModelsConsumerTests.swift new file mode 100644 index 0000000..6613289 --- /dev/null +++ b/Tests/IntelligenceBridgeTests/FoundationModelsConsumerTests.swift @@ -0,0 +1,17 @@ +import IntelligenceBridge +import Testing + +#if canImport(FoundationModels) && !os(tvOS) + @Generable + private struct GeneratedValue { + @Guide(description: "A short value") + var value: String + } + + @Test("Foundation Models APIs are re-exported to consumers") + func foundationModelsAPIsAreReexportedToConsumers() { + _ = SystemLanguageModel.self + _ = LanguageModelSession.self + _ = GeneratedValue.self + } +#endif