diff --git a/README.md b/README.md index d153b838..5a12ebda 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ All you need to do is change your import statement: + import AnyLanguageModel ``` +Anything AnyLanguageModel adds beyond Apple's API +is marked as an extension in its documentation. +[Differences from Foundation Models](#differences-from-foundation-models) +summarizes these extensions +and lists the few Foundation Models APIs it doesn't implement yet. + ```swift struct WeatherTool: Tool { let name = "getWeather" @@ -373,6 +379,10 @@ use a vision-capable model For llama.cpp, pass the model's multimodal projector with `mmprojPath:`. +> [!NOTE] +> Image inputs are an AnyLanguageModel extension. +> See [Differences from Foundation Models](#differences-from-foundation-models). + ### Tool Calling Tool calling is supported by all providers. @@ -432,6 +442,10 @@ actor ToolExecutionObserver: ToolExecutionDelegate { session.toolExecutionDelegate = ToolExecutionObserver() ``` +> [!NOTE] +> Tool execution delegates are an AnyLanguageModel extension. +> See [Differences from Foundation Models](#differences-from-foundation-models). + ### Token Usage Inspect token counts with `response.usage` @@ -492,6 +506,69 @@ the latest value is kept for each metadata key. > [Foundation Models 27 usage API](https://developer.apple.com/documentation/foundationmodels/languagemodelsession/usage-swift.struct). > `Codable` and `Equatable` support are AnyLanguageModel extensions. +## Differences from Foundation Models + +Code that uses an extension doesn't compile with Foundation Models on OS 26. +Each extension's documentation comment says so, +and extensions that follow a Foundation Models 27 API, +such as token usage, +say which API they follow. + +### Extensions + +- `LanguageModel` and `Availability`: + the protocol that lets a session use any model provider. + Foundation Models 27 adds its own `LanguageModel` protocol + with different requirements. + Session initializers require a `model:` argument + instead of defaulting to `SystemLanguageModel.default`. +- `GenerationOptions[custom:]` and `CustomGenerationOptions`: + options for one provider, + described in that provider's section under [Providers](#providers). +- `respond(to:images:)`, `Transcript.ImageSegment`, and `Transcript.Segment.image`: + [image inputs](#image-inputs). + Foundation Models 27 adds prompt attachments, + and AnyLanguageModel 2.0 will change to match them. +- `ToolExecutionDelegate`, `ToolExecutionDecision`, and `toolExecutionDelegate`: + [observing and controlling tool calls](#tool-calling). +- `transcriptErrorHandlingPolicy` and `waitForResponseCompletion()`: + what a transcript keeps when a request fails or is cancelled. +- `LanguageModelSession.tools` and `instructions`: + the session's tools and instructions, + for language models defined outside AnyLanguageModel. +- `Usage` and the `usage` properties: + [token usage](#token-usage), + which follows the Foundation Models 27 API. +- Public initializers for `Response`, `ResponseStream`, `ResponseStream.Snapshot`, + `GenerationGuide`, and `LanguageModelFeedback`, + for language models defined outside AnyLanguageModel. +- `Codable` conformance for `GeneratedContent`, `GenerationID`, `Usage`, + and the types nested in `Transcript`. +- `GeneratedContentError` and each provider's error type. +- `JSONValue`: + JSON values for provider options such as `extraBody`. +- Smaller additions to existing types, + such as `LanguageModel.isAvailable`, `SystemLanguageModel.supportsImageInput`, + `Transcript.ToolCall.providerMetadata`, and `GenerationError.Refusal.transcriptEntries`. + +### Behavior differences + +- A session adds the prompt to its transcript before the model responds, + as a single text segment. +- A structured response is recorded in the transcript as JSON text, + not as a structured segment. +- A session created from a transcript restores `instructions` + only when the first entry is instructions with a single text segment. + +### Not yet implemented + +- `@Generable(description:representNilExplicitlyInGeneratedContent:)` + and the matching `GenerationSchema` and `DynamicGenerationSchema` initializers +- `DynamicGenerationSchema.null` +- `logFeedbackAttachment(sentiment:issues:desiredResponseText:)` + and `logFeedbackAttachment(sentiment:issues:desiredResponseContent:)` +- `SystemLanguageModel.supportedLanguages`, `supportsLocale(_:)`, and `tokenCount(for:)` + ## Providers ### Apple Foundation Models diff --git a/Sources/AnyLanguageModel/Availability.swift b/Sources/AnyLanguageModel/Availability.swift index eacaf786..f3e4516a 100644 --- a/Sources/AnyLanguageModel/Availability.swift +++ b/Sources/AnyLanguageModel/Availability.swift @@ -1,4 +1,13 @@ /// The availability status for a specific language model. +/// +/// This generic type replaces Foundation Models' `SystemLanguageModel.Availability` +/// so that each model can report its own reasons for being unavailable. +/// The cases have the same names, +/// so a `switch` over a model's `availability` works with both frameworks. +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public enum Availability { /// The model is ready for making requests. case available diff --git a/Sources/AnyLanguageModel/GeneratedContent.swift b/Sources/AnyLanguageModel/GeneratedContent.swift index 7b8cc15b..0f386c7d 100644 --- a/Sources/AnyLanguageModel/GeneratedContent.swift +++ b/Sources/AnyLanguageModel/GeneratedContent.swift @@ -4,6 +4,10 @@ import CoreFoundation /// A type that represents structured, generated content. /// /// Generated content may contain a single value, an array, or key-value pairs with unique keys. +/// +/// - Note: The `Codable` conformance is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public struct GeneratedContent: Sendable, Equatable, Generable, CustomDebugStringConvertible, Codable { /// An instance of the generation schema. public static var generationSchema: GenerationSchema { @@ -338,6 +342,10 @@ extension GeneratedContent { /// /// `Kind` represents the various types of JSON-compatible data that can be held within /// a `GeneratedContent` instance, including primitive types, arrays, and structured objects. + /// + /// - Note: The `Codable` conformance is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. public enum Kind: Equatable, Sendable { /// Represents a null value. @@ -393,6 +401,11 @@ extension GeneratedContent { // MARK: - GeneratedContentError +/// Errors that can occur when converting generated content to a value. +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public enum GeneratedContentError: Error, Hashable { case propertyNotFound(String) case typeMismatch diff --git a/Sources/AnyLanguageModel/GenerationGuide.swift b/Sources/AnyLanguageModel/GenerationGuide.swift index d2a67402..84a4b782 100644 --- a/Sources/AnyLanguageModel/GenerationGuide.swift +++ b/Sources/AnyLanguageModel/GenerationGuide.swift @@ -8,6 +8,11 @@ public struct GenerationGuide: Sendable { var minimum: Double? var maximum: Double? + /// Creates a guide with no constraints. + /// + /// - Note: This initializer is exclusive to AnyLanguageModel. + /// It's public for language models outside this module; + /// Foundation Models doesn't make it public. public init() {} init(minimumCount: Int?, maximumCount: Int?) { diff --git a/Sources/AnyLanguageModel/GenerationID.swift b/Sources/AnyLanguageModel/GenerationID.swift index 08816b26..80d95c8e 100644 --- a/Sources/AnyLanguageModel/GenerationID.swift +++ b/Sources/AnyLanguageModel/GenerationID.swift @@ -13,7 +13,7 @@ import struct Foundation.UUID /// } /// /// struct PeopleView: View { -/// @State private var session = LanguageModelSession() +/// @State private var session = LanguageModelSession(model: SystemLanguageModel.default) /// @State private var people = [Person.PartiallyGenerated]() /// /// var body: some View { @@ -41,6 +41,10 @@ import struct Foundation.UUID /// } /// } /// ``` +/// +/// - Note: The `Codable` conformance is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public struct GenerationID: Sendable, Hashable, Codable { private let uuid: UUID diff --git a/Sources/AnyLanguageModel/GenerationOptions.swift b/Sources/AnyLanguageModel/GenerationOptions.swift index f28ab57f..cd2352a9 100644 --- a/Sources/AnyLanguageModel/GenerationOptions.swift +++ b/Sources/AnyLanguageModel/GenerationOptions.swift @@ -138,6 +138,10 @@ public struct GenerationOptions: Sendable, Equatable { /// /// - Parameter modelType: The language model type to get or set custom options for. /// - Returns: The custom options for the specified model type, or `nil` if none are set. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. public subscript( custom modelType: Model.Type ) -> Model.CustomGenerationOptions? { @@ -219,6 +223,10 @@ extension GenerationOptions { /// } /// } /// ``` +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public protocol CustomGenerationOptions: Equatable, Sendable {} extension Never: CustomGenerationOptions {} diff --git a/Sources/AnyLanguageModel/LanguageModel.swift b/Sources/AnyLanguageModel/LanguageModel.swift index 082aa5f3..9a9039da 100644 --- a/Sources/AnyLanguageModel/LanguageModel.swift +++ b/Sources/AnyLanguageModel/LanguageModel.swift @@ -1,5 +1,20 @@ import Foundation +/// A type that generates responses for a language model session. +/// +/// Model providers conform to this protocol +/// so that a ``LanguageModelSession`` can use them. +/// A conforming type reports its availability, +/// generates complete and streamed responses, +/// and can define its own custom generation options. +/// +/// - Note: This API is exclusive to AnyLanguageModel. +/// On OS 26, a Foundation Models session always uses `SystemLanguageModel`; +/// this protocol is what lets a session use any provider. +/// Foundation Models 27 adds its own `LanguageModel` protocol +/// with different requirements, +/// so using this protocol means your code is no longer drop-in compatible +/// with the Foundation Models framework. public protocol LanguageModel: Sendable { associatedtype UnavailableReason @@ -100,6 +115,12 @@ extension LanguageModel { ) } + /// A Boolean value that indicates whether the model is ready for requests. + /// + /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// Foundation Models provides `isAvailable` only on `SystemLanguageModel`. public var isAvailable: Bool { if case .available = availability { return true diff --git a/Sources/AnyLanguageModel/LanguageModelFeedback.swift b/Sources/AnyLanguageModel/LanguageModelFeedback.swift index f1b9fd10..f3c8c956 100644 --- a/Sources/AnyLanguageModel/LanguageModelFeedback.swift +++ b/Sources/AnyLanguageModel/LanguageModelFeedback.swift @@ -1,3 +1,8 @@ +/// Feedback about a model's response. +/// +/// - Note: The ``sentiment`` and ``issues`` properties are exclusive to AnyLanguageModel. +/// They're public for language models outside this module; +/// Foundation Models doesn't make them public. public struct LanguageModelFeedback { /// A sentiment regarding the model's response. public enum Sentiment: Sendable, CaseIterable, Equatable, Hashable { @@ -92,6 +97,11 @@ public struct LanguageModelFeedback { /// - Parameters: /// - sentiment: A sentiment for the model's response. /// - issues: Issues with the model's response. + /// + /// - Note: This initializer is exclusive to AnyLanguageModel. + /// It's public so that language models outside this module + /// can create feedback; + /// Foundation Models doesn't make it public. public init(sentiment: Sentiment, issues: [Issue]) { self.sentiment = sentiment self.issues = issues diff --git a/Sources/AnyLanguageModel/LanguageModelSession.swift b/Sources/AnyLanguageModel/LanguageModelSession.swift index f027b894..5fa32c09 100644 --- a/Sources/AnyLanguageModel/LanguageModelSession.swift +++ b/Sources/AnyLanguageModel/LanguageModelSession.swift @@ -2,6 +2,10 @@ import Foundation import Observation /// Controls transcript retention when generation fails or is cancelled. +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public struct TranscriptErrorHandlingPolicy: Sendable, Equatable { private let shouldRevert: Bool @@ -23,6 +27,10 @@ public final class LanguageModelSession: @unchecked Sendable { /// On failure, `nil` retains the prompt without committing streaming checkpoints. /// Streaming cancellation never commits the partial answer as a completed response, regardless /// of this policy. These defaults do not claim Foundation Models behavioral parity. + /// + /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. public var transcriptErrorHandlingPolicy: TranscriptErrorHandlingPolicy? { get { access(keyPath: \.transcriptErrorHandlingPolicy) @@ -44,6 +52,10 @@ public final class LanguageModelSession: @unchecked Sendable { /// /// Counts increase as responses and streaming snapshots report usage. /// Restoring a transcript does not restore usage from previous sessions. + /// + /// - Note: This property is exclusive to AnyLanguageModel on OS 26. + /// It follows the Foundation Models 27 `LanguageModelSession.usage` API, + /// so code that uses it ports to Foundation Models on OS 27. public var usage: Usage { access(keyPath: \.usage) return state.withLock { $0.usage } @@ -54,17 +66,39 @@ public final class LanguageModelSession: @unchecked Sendable { @ObservationIgnored private let responseRelays = Locked<[UUID: Task]>([:]) /// Waits for transcript cleanup of all streaming relays registered when this call begins. - /// Relays started later are excluded. Cancelling this wait does not cancel generation. - /// Call after cancelling consumers and before persisting the transcript. This is an - /// AnyLanguageModel extension; nonstreaming operations must be awaited separately. + /// + /// Relays started later are excluded. + /// Cancelling this wait does not cancel generation. + /// Call after cancelling consumers and before persisting the transcript. + /// Nonstreaming operations must be awaited separately. /// Do not call from a tool executing within one of the included responses. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. nonisolated public func waitForResponseCompletion() async { let tasks = responseRelays.withLock { Array($0.values) } for task in tasks { await task.value } } private let model: any LanguageModel + + /// The tools that the model can call during the session. + /// + /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// It's public so that language models outside this module + /// can read the session's tools. public let tools: [any Tool] + + /// The instructions for the session, if any. + /// + /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// It's public so that language models outside this module + /// can read the session's instructions. public let instructions: Instructions? /// A delegate that observes and controls tool execution. @@ -77,6 +111,17 @@ public final class LanguageModelSession: @unchecked Sendable { /// with the Foundation Models framework. @ObservationIgnored public var toolExecutionDelegate: (any ToolExecutionDelegate)? + /// Creates a session with a model, tools, + /// and instructions that you build with a result builder. + /// + /// - Note: Unlike Foundation Models, + /// which defaults `model` to `SystemLanguageModel.default`, + /// AnyLanguageModel requires the `model` argument + /// and accepts any type that conforms to ``LanguageModel``. + /// Code that omits `model` doesn't compile with AnyLanguageModel; + /// pass `SystemLanguageModel.default` to use the system model. + /// Code that passes another model + /// is no longer drop-in compatible with the Foundation Models framework. public convenience init( model: any LanguageModel, tools: [any Tool] = [], @@ -85,6 +130,11 @@ public final class LanguageModelSession: @unchecked Sendable { try self.init(model: model, tools: tools, instructions: instructions()) } + /// Creates a session with a model, tools, and instructions as a string. + /// + /// - Note: Unlike Foundation Models, + /// AnyLanguageModel requires the `model` argument + /// and accepts any ``LanguageModel``. public convenience init( model: any LanguageModel, tools: [any Tool] = [], @@ -93,6 +143,11 @@ public final class LanguageModelSession: @unchecked Sendable { self.init(model: model, tools: tools, instructions: Instructions(instructions), transcript: Transcript()) } + /// Creates a session with a model, tools, and optional instructions. + /// + /// - Note: Unlike Foundation Models, + /// AnyLanguageModel requires the `model` argument + /// and accepts any ``LanguageModel``. public convenience init( model: any LanguageModel, tools: [any Tool] = [], @@ -101,6 +156,12 @@ public final class LanguageModelSession: @unchecked Sendable { self.init(model: model, tools: tools, instructions: instructions, transcript: Transcript()) } + /// Creates a session with a model and tools + /// that continues from an existing transcript. + /// + /// - Note: Unlike Foundation Models, + /// AnyLanguageModel requires the `model` argument + /// and accepts any ``LanguageModel``. public convenience init( model: any LanguageModel, tools: [any Tool] = [], @@ -295,6 +356,12 @@ public final class LanguageModelSession: @unchecked Sendable { /// Matches the token-usage API in Foundation Models 27. /// Counts default to zero when the provider does not report them. /// Usage is cumulative across the response's tool rounds. + /// + /// - Note: This API is exclusive to AnyLanguageModel on OS 26. + /// It follows the Foundation Models 27 `Usage` API, + /// so code that uses it ports to Foundation Models on OS 27. + /// The `Codable` and `Equatable` conformances are exclusive to AnyLanguageModel; + /// Foundation Models 27 doesn't provide them. public struct Usage: Sendable, Equatable, Codable { /// Token counts for the input submitted to the model. public struct Input: Sendable, Equatable, Codable { @@ -418,6 +485,10 @@ public final class LanguageModelSession: @unchecked Sendable { /// Provider-reported token usage, /// with zero counts for values the provider does not report. + /// + /// - Note: This property is exclusive to AnyLanguageModel on OS 26. + /// It follows the Foundation Models 27 `Response.usage` API, + /// so code that uses it ports to Foundation Models on OS 27. public let usage: Usage internal let providerMetadata: [String: String]? @@ -428,6 +499,11 @@ public final class LanguageModelSession: @unchecked Sendable { /// - rawContent: The raw content produced by the model. /// - transcriptEntries: Transcript entries associated with the response. /// - usage: Provider-reported token usage. + /// + /// - Note: This initializer is exclusive to AnyLanguageModel. + /// It's public so that language models outside this module + /// can create responses; + /// Foundation Models doesn't make it public. public init( content: Content, rawContent: GeneratedContent, @@ -809,6 +885,11 @@ extension LanguageModelSession { // MARK: - Image Convenience Methods extension LanguageModelSession { + /// Produces a text response to a prompt and an image. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. @discardableResult nonisolated public func respond( to prompt: String, @@ -822,6 +903,11 @@ extension LanguageModelSession { ) } + /// Produces a text response to a prompt and images. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. @discardableResult nonisolated public func respond( to prompt: String, @@ -837,6 +923,11 @@ extension LanguageModelSession { ) } + /// Produces a response of the specified type to a prompt and an image. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. @discardableResult nonisolated public func respond( to prompt: String, @@ -854,6 +945,11 @@ extension LanguageModelSession { ) } + /// Produces a response of the specified type to a prompt and images. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. @discardableResult nonisolated public func respond( to prompt: String, @@ -924,6 +1020,11 @@ extension LanguageModelSession { } } + /// Streams a text response to a prompt and an image. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public func streamResponse( to prompt: String, image: Transcript.ImageSegment, @@ -936,6 +1037,11 @@ extension LanguageModelSession { ) } + /// Streams a text response to a prompt and images. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public func streamResponse( to prompt: String, images: [Transcript.ImageSegment], @@ -950,6 +1056,11 @@ extension LanguageModelSession { ) } + /// Streams a response of the specified type to a prompt and an image. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. nonisolated public func streamResponse( to prompt: String, image: Transcript.ImageSegment, @@ -966,6 +1077,11 @@ extension LanguageModelSession { ) } + /// Streams a response of the specified type to a prompt and images. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. nonisolated public func streamResponse( to prompt: String, images: [Transcript.ImageSegment], @@ -1039,6 +1155,13 @@ extension LanguageModelSession { } public struct Refusal: Sendable { + /// The transcript entries associated with the refusal. + /// + /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// Foundation Models takes transcript entries in the initializer + /// but doesn't make this property public. public let transcriptEntries: [Transcript.Entry] public init(transcriptEntries: [Transcript.Entry]) { @@ -1128,6 +1251,11 @@ extension LanguageModelSession { /// - content: The complete response content. /// - rawContent: The raw content produced by the model. /// - usage: Provider-reported token usage. + /// + /// - Note: This initializer is exclusive to AnyLanguageModel. + /// It's public so that language models outside this module + /// can create response streams; + /// Foundation Models doesn't make it public. public init( content: Content, rawContent: GeneratedContent, @@ -1146,6 +1274,11 @@ extension LanguageModelSession { /// Creates a response stream that yields snapshots from an async stream. /// - Parameter stream: The snapshot stream to relay. + /// + /// - Note: This initializer is exclusive to AnyLanguageModel. + /// It's public so that language models outside this module + /// can create response streams; + /// Foundation Models doesn't make it public. public init(stream: AsyncThrowingStream) { // When streaming, snapshots arrive from the upstream sequence, so no fallback is required. self.fallbackSnapshot = nil @@ -1163,10 +1296,18 @@ extension LanguageModelSession { /// Transcript entries (tool calls and outputs) produced so far while streaming. /// Cumulative across tool rounds; /// empty for providers that don't stream tool activity. + /// + /// - Note: This property is exclusive to AnyLanguageModel on OS 26. + /// It follows the Foundation Models 27 `ResponseStream.Snapshot.transcriptEntries` API, + /// so code that uses it ports to Foundation Models on OS 27. public var transcriptEntries: ArraySlice /// Provider-reported counts so far, /// with zero counts for values the provider does not report. + /// + /// - Note: This property is exclusive to AnyLanguageModel on OS 26. + /// It follows the Foundation Models 27 `ResponseStream.Snapshot.usage` API, + /// so code that uses it ports to Foundation Models on OS 27. public var usage: Usage internal var providerMetadata: [String: String]? @@ -1177,6 +1318,11 @@ extension LanguageModelSession { /// - rawContent: The raw content produced by the model. /// - transcriptEntries: Transcript entries accumulated so far (tool calls/outputs). /// - usage: Provider-reported token usage so far. + /// + /// - Note: This initializer is exclusive to AnyLanguageModel. + /// It's public so that language models outside this module + /// can create snapshots; + /// Foundation Models doesn't make it public. public init( content: Content.PartiallyGenerated, rawContent: GeneratedContent, diff --git a/Sources/AnyLanguageModel/Models/AnthropicLanguageModel.swift b/Sources/AnyLanguageModel/Models/AnthropicLanguageModel.swift index 2f7dd7cc..a9ef9768 100644 --- a/Sources/AnyLanguageModel/Models/AnthropicLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/AnthropicLanguageModel.swift @@ -30,6 +30,9 @@ import OrderedCollections public struct AnthropicLanguageModel: LanguageModel { /// Custom generation options specific to Anthropic's Claude API. /// + /// Reached through `GenerationOptions[custom: AnthropicLanguageModel.self]`, + /// an AnyLanguageModel extension. + /// /// Use this type to pass additional parameters that are not part of the /// standard ``GenerationOptions``, such as Anthropic-specific sampling /// parameters and metadata. diff --git a/Sources/AnyLanguageModel/Models/CoreMLLanguageModel.swift b/Sources/AnyLanguageModel/Models/CoreMLLanguageModel.swift index 05c3aebd..3aa74e2d 100644 --- a/Sources/AnyLanguageModel/Models/CoreMLLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/CoreMLLanguageModel.swift @@ -315,6 +315,10 @@ } /// Errors that can occur when working with Core ML language models. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. @available(macOS 15.0, iOS 18.0, tvOS 18.0, visionOS 2.0, watchOS 11.0, *) public enum CoreMLLanguageModelError: LocalizedError { /// The provided model isn't a compiled Core ML model. diff --git a/Sources/AnyLanguageModel/Models/GeminiLanguageModel.swift b/Sources/AnyLanguageModel/Models/GeminiLanguageModel.swift index ba06a0c8..4b777db3 100644 --- a/Sources/AnyLanguageModel/Models/GeminiLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/GeminiLanguageModel.swift @@ -16,6 +16,9 @@ public struct GeminiLanguageModel: LanguageModel { /// Custom generation options specific to Gemini models. /// + /// Reached through `GenerationOptions[custom: GeminiLanguageModel.self]`, + /// an AnyLanguageModel extension. + /// /// Use this type to configure Gemini-specific features like thinking mode /// and server-side tools through ``GenerationOptions``. /// diff --git a/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift b/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift index 68c5ea1d..08269e40 100644 --- a/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/LlamaLanguageModel.swift @@ -66,6 +66,9 @@ import Foundation /// Custom generation options specific to llama.cpp. /// + /// Reached through `GenerationOptions[custom: LlamaLanguageModel.self]`, + /// an AnyLanguageModel extension. + /// /// Use this type to pass llama.cpp-specific sampling parameters that are /// not part of the standard ``GenerationOptions``. /// @@ -2602,6 +2605,10 @@ import Foundation } /// Errors that can occur when using LlamaLanguageModel + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. public enum LlamaLanguageModelError: Error, LocalizedError { case modelLoadFailed case contextInitializationFailed diff --git a/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift b/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift index d911cb3f..dbc58c99 100644 --- a/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/MLXLanguageModel.swift @@ -201,8 +201,9 @@ import Foundation /// Configures MLX-specific generation behavior. /// - /// Set these values through ``GenerationOptions`` using - /// `GenerationOptions[custom: MLXLanguageModel.self]`. + /// Set these values through + /// `GenerationOptions[custom: MLXLanguageModel.self]`, + /// an AnyLanguageModel extension. public struct CustomGenerationOptions: AnyLanguageModel.CustomGenerationOptions, Codable { /// Configures KV-cache behavior for MLX generation. public struct KVCache: Codable, Equatable, Sendable { @@ -2040,6 +2041,10 @@ import Foundation // MARK: - Structured JSON Generation /// Errors that can occur when using MLXLanguageModel. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. public enum MLXLanguageModelError: Error, LocalizedError { case invalidVocabSize case unsupportedJSONValueType diff --git a/Sources/AnyLanguageModel/Models/OllamaLanguageModel.swift b/Sources/AnyLanguageModel/Models/OllamaLanguageModel.swift index 9a5fd206..27da52f8 100644 --- a/Sources/AnyLanguageModel/Models/OllamaLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/OllamaLanguageModel.swift @@ -20,6 +20,9 @@ public struct OllamaLanguageModel: LanguageModel { /// Custom generation options specific to Ollama. /// + /// Reached through `GenerationOptions[custom: OllamaLanguageModel.self]`, + /// an AnyLanguageModel extension. + /// /// Use this type to pass additional model parameters that are not part /// of the standard ``GenerationOptions``. /// diff --git a/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift b/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift index ac297f9f..38cde097 100644 --- a/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/OpenAILanguageModel.swift @@ -38,6 +38,9 @@ public struct OpenAILanguageModel: LanguageModel { /// Custom generation options specific to OpenAI-compatible APIs. /// + /// Reached through `GenerationOptions[custom: OpenAILanguageModel.self]`, + /// an AnyLanguageModel extension. + /// /// Use this type to pass additional parameters that are not part of the /// standard ``GenerationOptions``, such as sampling parameters, penalties, /// and vendor-specific extensions. @@ -2009,6 +2012,10 @@ private func extractToolCallsFromOutput(_ output: [JSONValue]?) -> [OpenAIToolCa // MARK: - Errors /// Errors that can occur when using ``OpenAILanguageModel``. +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public enum OpenAILanguageModelError: LocalizedError { /// The response contained no output to use. /// diff --git a/Sources/AnyLanguageModel/Models/OpenResponsesLanguageModel.swift b/Sources/AnyLanguageModel/Models/OpenResponsesLanguageModel.swift index 82dfb46a..7742e866 100644 --- a/Sources/AnyLanguageModel/Models/OpenResponsesLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/OpenResponsesLanguageModel.swift @@ -27,6 +27,9 @@ public struct OpenResponsesLanguageModel: LanguageModel { /// Custom generation options for Open Responses–compatible APIs. /// + /// Reached through `GenerationOptions[custom: OpenResponsesLanguageModel.self]`, + /// an AnyLanguageModel extension. + /// /// Includes Open Responses–specific fields such as ``toolChoice`` (including /// ``ToolChoice/allowedTools(tools:mode:)``), ``allowedTools``, and /// reasoning/text options. Use ``extraBody`` for parameters not yet modeled. @@ -1240,6 +1243,10 @@ private enum OpenResponsesStreamEvent: Decodable, Sendable { // MARK: - Errors /// Errors that can occur when using ``OpenResponsesLanguageModel``. +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public enum OpenResponsesLanguageModelError: LocalizedError, Sendable { /// The response contained no output to use. /// diff --git a/Sources/AnyLanguageModel/Models/SystemLanguageModel.swift b/Sources/AnyLanguageModel/Models/SystemLanguageModel.swift index d4f10119..1b60f349 100644 --- a/Sources/AnyLanguageModel/Models/SystemLanguageModel.swift +++ b/Sources/AnyLanguageModel/Models/SystemLanguageModel.swift @@ -64,6 +64,11 @@ #endif /// Whether the model accepts image input. + /// + /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// In Foundation Models 27, check whether `capabilities` contains `.vision` instead. public var supportsImageInput: Bool { #if compiler(>=6.4) && !os(tvOS) && !os(watchOS) if #available(macOS 27.0, iOS 27.0, visionOS 27.0, *) { diff --git a/Sources/AnyLanguageModel/Shared/JSONValue.swift b/Sources/AnyLanguageModel/Shared/JSONValue.swift index 5d3c3156..7a1cf8e9 100644 --- a/Sources/AnyLanguageModel/Shared/JSONValue.swift +++ b/Sources/AnyLanguageModel/Shared/JSONValue.swift @@ -1,4 +1,8 @@ import enum JSONSchema.JSONValue /// A type-safe representation of JSON values used by AnyLanguageModel APIs. +/// +/// - Note: This API is exclusive to AnyLanguageModel +/// and using it means your code is no longer drop-in compatible +/// with the Foundation Models framework. public typealias JSONValue = JSONSchema.JSONValue diff --git a/Sources/AnyLanguageModel/Transcript.swift b/Sources/AnyLanguageModel/Transcript.swift index edd6c939..33b7ad79 100644 --- a/Sources/AnyLanguageModel/Transcript.swift +++ b/Sources/AnyLanguageModel/Transcript.swift @@ -1,6 +1,13 @@ import Foundation /// A type that represents a conversation history between a user and a language model. +/// +/// - Note: Foundation Models makes only `Transcript` and `GenerationSchema` `Codable`. +/// The `Codable` conformances of the nested transcript types, +/// such as ``Transcript/Entry`` and ``Transcript/Segment``, +/// are exclusive to AnyLanguageModel, +/// and using them means your code is no longer drop-in compatible +/// with the Foundation Models framework. public struct Transcript: Sendable, Equatable, Codable { private var entries: [Entry] @@ -65,6 +72,12 @@ public struct Transcript: Sendable, Equatable, Codable { case structure(StructuredSegment) /// A segment containing an image. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// Foundation Models 27 adds prompt attachments, + /// so this API will change to match them in AnyLanguageModel 2.0. case image(ImageSegment) /// The stable identity of the entity associated with this instance. @@ -116,6 +129,12 @@ public struct Transcript: Sendable, Equatable, Codable { /// Use this type to include images alongside text and structured content when /// constructing `Transcript` entries. Images can be provided as raw data with a /// MIME type or by URL. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// Foundation Models 27 adds prompt attachments, + /// so this API will change to match them in AnyLanguageModel 2.0. public struct ImageSegment: Sendable, Identifiable, Equatable, Codable { /// The stable identity of the entity associated with this instance. public var id: String @@ -124,6 +143,10 @@ public struct Transcript: Sendable, Equatable, Codable { public let source: Source /// The origin of an image's content. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public enum Source: Sendable, Equatable, Codable { /// Image bytes and their MIME type (for example, `image/jpeg`). case data(Data, mimeType: String) @@ -197,6 +220,12 @@ public struct Transcript: Sendable, Equatable, Codable { } /// Errors that can occur when converting platform images to encoded data. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. + /// Foundation Models 27 adds prompt attachments, + /// so this API will change to match them in AnyLanguageModel 2.0. public enum ImageEncodingError: Error { /// The image couldn't be converted to the requested format. case imageConversionFailed @@ -376,6 +405,8 @@ public struct Transcript: Sendable, Equatable, Codable { /// should interpret or modify them. /// /// - Note: This property is exclusive to AnyLanguageModel + /// and using it means your code is no longer drop-in compatible + /// with the Foundation Models framework. public var providerMetadata: [String: String]? public init( @@ -512,6 +543,10 @@ extension Transcript.StructuredSegment: CustomStringConvertible { extension Transcript.ImageSegment { /// Preferred image encodings for image conversion. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public enum Format: Sendable { /// JPEG encoding with the specified compression quality. case jpeg(compressionQuality: Double = 0.9) @@ -545,6 +580,10 @@ extension Transcript.ImageSegment { /// - image: The source image to encode. /// - format: The target encoding. Defaults to JPEG with 0.9 quality. /// - Throws: ``Transcript/ImageEncodingError-swift.enum/imageConversionFailed`` if encoding fails. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public init(image: UIImage, format: Format = .jpeg()) throws { let (data, mimeType) = try Self.encode(image, format: format) self.init(data: data, mimeType: mimeType) @@ -591,6 +630,10 @@ extension Transcript.ImageSegment { /// - image: The source image to encode. /// - format: The target encoding. Defaults to JPEG with 0.9 quality. /// - Throws: ``Transcript/ImageEncodingError-swift.enum/imageConversionFailed`` if encoding fails. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public init(image: NSImage, format: Format = .jpeg()) throws { let (data, mimeType) = try Self.encode(image, format: format) self.init(data: data, mimeType: mimeType) @@ -647,6 +690,10 @@ extension Transcript.ImageSegment { /// - image: The source image to encode. /// - format: The target encoding. Defaults to JPEG with 0.9 quality. /// - Throws: ``Transcript/ImageEncodingError-swift.enum/imageConversionFailed`` if encoding fails. + /// + /// - Note: This API is exclusive to AnyLanguageModel + /// and will change to match Foundation Models 27 prompt attachments + /// in AnyLanguageModel 2.0. public init(image: CGImage, format: Format = .jpeg()) throws { let (data, mimeType) = try Self.encode(image, format: format) self.init(data: data, mimeType: mimeType)