From 5ce4800436493442b90af4c8647b6840c582c374 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 16 Oct 2024 10:32:51 -0400 Subject: [PATCH 1/3] [Vertex AI] Increase macOS minimum to 12.0 --- FirebaseVertexAI/Sources/Chat.swift | 2 +- .../Sources/CountTokensRequest.swift | 10 +++---- .../Sources/FunctionCalling.swift | 9 +++++++ .../Sources/GenerateContentError.swift | 2 +- .../Sources/GenerateContentRequest.swift | 6 ++--- .../Sources/GenerateContentResponse.swift | 26 ++++++++++--------- .../Sources/GenerationConfig.swift | 4 +-- .../Sources/GenerativeAIRequest.swift | 4 +-- .../Sources/GenerativeAIService.swift | 2 +- .../Sources/GenerativeModel.swift | 2 +- FirebaseVertexAI/Sources/JSONValue.swift | 5 ++++ FirebaseVertexAI/Sources/ModelContent.swift | 8 +++--- .../Sources/PartsRepresentable+Image.swift | 4 +-- .../Sources/PartsRepresentable.swift | 8 +++--- FirebaseVertexAI/Sources/Safety.swift | 14 ++++++---- .../Sources/Types/Internal/InternalPart.swift | 16 ++++++------ .../Sources/Types/Public/Part.swift | 12 ++++----- .../Sources/Types/Public/Schema.swift | 4 +++ FirebaseVertexAI/Sources/VertexAI.swift | 2 +- .../Tests/Unit/GenerationConfigTests.swift | 2 +- .../Tests/Unit/JSONValueTests.swift | 1 + FirebaseVertexAI/Tests/Unit/PartTests.swift | 2 +- .../Tests/Unit/PartsRepresentableTests.swift | 2 +- .../Tests/Unit/VertexAIAPITests.swift | 2 +- .../Tests/Unit/VertexComponentTests.swift | 2 +- 25 files changed, 88 insertions(+), 63 deletions(-) diff --git a/FirebaseVertexAI/Sources/Chat.swift b/FirebaseVertexAI/Sources/Chat.swift index 2ebab217ca8..717bf29aae2 100644 --- a/FirebaseVertexAI/Sources/Chat.swift +++ b/FirebaseVertexAI/Sources/Chat.swift @@ -16,7 +16,7 @@ import Foundation /// An object that represents a back-and-forth chat with a model, capturing the history and saving /// the context in memory between each message sent. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public class Chat { private let model: GenerativeModel diff --git a/FirebaseVertexAI/Sources/CountTokensRequest.swift b/FirebaseVertexAI/Sources/CountTokensRequest.swift index 128cb3b8ce6..6c36d96b4c0 100644 --- a/FirebaseVertexAI/Sources/CountTokensRequest.swift +++ b/FirebaseVertexAI/Sources/CountTokensRequest.swift @@ -14,7 +14,7 @@ import Foundation -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct CountTokensRequest { let model: String @@ -26,7 +26,7 @@ struct CountTokensRequest { let options: RequestOptions } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension CountTokensRequest: GenerativeAIRequest { typealias Response = CountTokensResponse @@ -36,7 +36,7 @@ extension CountTokensRequest: GenerativeAIRequest { } /// The model's response to a count tokens request. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct CountTokensResponse { /// The total number of tokens in the input given to the model as a prompt. public let totalTokens: Int @@ -50,7 +50,7 @@ public struct CountTokensResponse { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension CountTokensRequest: Encodable { enum CodingKeys: CodingKey { case contents @@ -60,5 +60,5 @@ extension CountTokensRequest: Encodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension CountTokensResponse: Decodable {} diff --git a/FirebaseVertexAI/Sources/FunctionCalling.swift b/FirebaseVertexAI/Sources/FunctionCalling.swift index 69c90b18e10..60514a6f5f4 100644 --- a/FirebaseVertexAI/Sources/FunctionCalling.swift +++ b/FirebaseVertexAI/Sources/FunctionCalling.swift @@ -18,6 +18,7 @@ import Foundation /// /// This `FunctionDeclaration` is a representation of a block of code that can be used as a ``Tool`` /// by the model and executed by the client. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FunctionDeclaration { /// The name of the function. let name: String @@ -53,6 +54,7 @@ public struct FunctionDeclaration { /// /// A `Tool` is a piece of code that enables the system to interact with external systems to perform /// an action, or set of actions, outside of knowledge and scope of the model. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct Tool { /// A list of `FunctionDeclarations` available to the model. let functionDeclarations: [FunctionDeclaration]? @@ -86,6 +88,7 @@ public struct Tool { } /// Configuration for specifying function calling behavior. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FunctionCallingConfig { /// Defines the execution behavior for function calling by defining the execution mode. enum Mode: String { @@ -131,6 +134,7 @@ public struct FunctionCallingConfig { } /// Tool configuration for any `Tool` specified in the request. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct ToolConfig { let functionCallingConfig: FunctionCallingConfig? @@ -141,6 +145,7 @@ public struct ToolConfig { // MARK: - Codable Conformance +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension FunctionDeclaration: Encodable { enum CodingKeys: String, CodingKey { case name @@ -156,10 +161,14 @@ extension FunctionDeclaration: Encodable { } } +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension Tool: Encodable {} +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension FunctionCallingConfig: Encodable {} +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension FunctionCallingConfig.Mode: Encodable {} +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension ToolConfig: Encodable {} diff --git a/FirebaseVertexAI/Sources/GenerateContentError.swift b/FirebaseVertexAI/Sources/GenerateContentError.swift index b5b52d0acd5..76ce516f3cf 100644 --- a/FirebaseVertexAI/Sources/GenerateContentError.swift +++ b/FirebaseVertexAI/Sources/GenerateContentError.swift @@ -15,7 +15,7 @@ import Foundation /// Errors that occur when generating content from a model. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public enum GenerateContentError: Error { /// An internal error occurred. See the underlying error for more context. case internalError(underlying: Error) diff --git a/FirebaseVertexAI/Sources/GenerateContentRequest.swift b/FirebaseVertexAI/Sources/GenerateContentRequest.swift index 87333bbfec1..ffa98fe4159 100644 --- a/FirebaseVertexAI/Sources/GenerateContentRequest.swift +++ b/FirebaseVertexAI/Sources/GenerateContentRequest.swift @@ -14,7 +14,7 @@ import Foundation -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct GenerateContentRequest { /// Model name. let model: String @@ -28,7 +28,7 @@ struct GenerateContentRequest { let options: RequestOptions } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension GenerateContentRequest: Encodable { enum CodingKeys: String, CodingKey { case contents @@ -40,7 +40,7 @@ extension GenerateContentRequest: Encodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension GenerateContentRequest: GenerativeAIRequest { typealias Response = GenerateContentResponse diff --git a/FirebaseVertexAI/Sources/GenerateContentResponse.swift b/FirebaseVertexAI/Sources/GenerateContentResponse.swift index f9d8e1d349c..3472807f1bb 100644 --- a/FirebaseVertexAI/Sources/GenerateContentResponse.swift +++ b/FirebaseVertexAI/Sources/GenerateContentResponse.swift @@ -15,9 +15,10 @@ import Foundation /// The model's response to a generate content request. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct GenerateContentResponse: Sendable { /// Token usage metadata for processing the generate content request. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct UsageMetadata: Sendable { /// The number of tokens in the request prompt. public let promptTokenCount: Int @@ -92,7 +93,7 @@ public struct GenerateContentResponse: Sendable { /// A struct representing a possible reply to a content generation prompt. Each content generation /// prompt may produce multiple candidate responses. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct Candidate: Sendable { /// The response's content. public let content: ModelContent @@ -118,14 +119,14 @@ public struct Candidate: Sendable { } /// A collection of source attributions for a piece of content. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct CitationMetadata: Sendable { /// A list of individual cited sources and the parts of the content to which they apply. public let citations: [Citation] } /// A struct describing a source attribution. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct Citation: Sendable { /// The inclusive beginning of a sequence in a model response that derives from a cited source. public let startIndex: Int @@ -149,7 +150,7 @@ public struct Citation: Sendable { } /// A value enumerating possible reasons for a model to terminate a content generation request. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FinishReason: DecodableProtoEnum, Hashable, Sendable { enum Kind: String { case stop = "STOP" @@ -204,9 +205,10 @@ public struct FinishReason: DecodableProtoEnum, Hashable, Sendable { } /// A metadata struct containing any feedback the model had on the prompt it was provided. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct PromptFeedback: Sendable { /// A type describing possible reasons to block a prompt. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct BlockReason: DecodableProtoEnum, Hashable, Sendable { enum Kind: String { case safety = "SAFETY" @@ -257,7 +259,7 @@ public struct PromptFeedback: Sendable { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension GenerateContentResponse: Decodable { enum CodingKeys: CodingKey { case candidates @@ -291,7 +293,7 @@ extension GenerateContentResponse: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension GenerateContentResponse.UsageMetadata: Decodable { enum CodingKeys: CodingKey { case promptTokenCount @@ -308,7 +310,7 @@ extension GenerateContentResponse.UsageMetadata: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension Candidate: Decodable { enum CodingKeys: CodingKey { case content @@ -357,10 +359,10 @@ extension Candidate: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension CitationMetadata: Decodable {} -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension Citation: Decodable { enum CodingKeys: CodingKey { case startIndex @@ -412,7 +414,7 @@ extension Citation: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension PromptFeedback: Decodable { enum CodingKeys: CodingKey { case blockReason diff --git a/FirebaseVertexAI/Sources/GenerationConfig.swift b/FirebaseVertexAI/Sources/GenerationConfig.swift index 8598624aea0..fa472dd37e1 100644 --- a/FirebaseVertexAI/Sources/GenerationConfig.swift +++ b/FirebaseVertexAI/Sources/GenerationConfig.swift @@ -16,7 +16,7 @@ import Foundation /// A struct defining model parameters to be used when sending generative AI /// requests to the backend model. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct GenerationConfig { /// A parameter controlling the degree of randomness in token selection. A /// temperature of zero is deterministic, always choosing the @@ -143,5 +143,5 @@ public struct GenerationConfig { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension GenerationConfig: Encodable {} diff --git a/FirebaseVertexAI/Sources/GenerativeAIRequest.swift b/FirebaseVertexAI/Sources/GenerativeAIRequest.swift index ac9046e0de4..b792830120e 100644 --- a/FirebaseVertexAI/Sources/GenerativeAIRequest.swift +++ b/FirebaseVertexAI/Sources/GenerativeAIRequest.swift @@ -14,7 +14,7 @@ import Foundation -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) protocol GenerativeAIRequest: Encodable { associatedtype Response: Decodable @@ -24,7 +24,7 @@ protocol GenerativeAIRequest: Encodable { } /// Configuration parameters for sending requests to the backend. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct RequestOptions { /// The request’s timeout interval in seconds; if not specified uses the default value for a /// `URLRequest`. diff --git a/FirebaseVertexAI/Sources/GenerativeAIService.swift b/FirebaseVertexAI/Sources/GenerativeAIService.swift index ff49a17b07f..30a24c13c6b 100644 --- a/FirebaseVertexAI/Sources/GenerativeAIService.swift +++ b/FirebaseVertexAI/Sources/GenerativeAIService.swift @@ -18,7 +18,7 @@ import FirebaseCore import Foundation import os.log -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct GenerativeAIService { /// The language of the SDK in the format `gl-/`. static let languageTag = "gl-swift/5" diff --git a/FirebaseVertexAI/Sources/GenerativeModel.swift b/FirebaseVertexAI/Sources/GenerativeModel.swift index c920a0daa88..0d2ea829f55 100644 --- a/FirebaseVertexAI/Sources/GenerativeModel.swift +++ b/FirebaseVertexAI/Sources/GenerativeModel.swift @@ -18,7 +18,7 @@ import Foundation /// A type that represents a remote multimodal model (like Gemini), with the ability to generate /// content based on various input types. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public final class GenerativeModel { /// The resource name of the model in the backend; has the format "models/model-name". let modelResourceName: String diff --git a/FirebaseVertexAI/Sources/JSONValue.swift b/FirebaseVertexAI/Sources/JSONValue.swift index c12e8aecb0f..f1333888d27 100644 --- a/FirebaseVertexAI/Sources/JSONValue.swift +++ b/FirebaseVertexAI/Sources/JSONValue.swift @@ -18,12 +18,14 @@ import Foundation /// /// This may be decoded from, or encoded to, a /// [`google.protobuf.Struct`](https://protobuf.dev/reference/protobuf/google.protobuf/#struct). +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public typealias JSONObject = [String: JSONValue] /// Represents a value in one of JSON's data types. /// /// This may be decoded from, or encoded to, a /// [`google.protobuf.Value`](https://protobuf.dev/reference/protobuf/google.protobuf/#value). +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public enum JSONValue: Sendable { /// A `null` value. case null @@ -44,6 +46,7 @@ public enum JSONValue: Sendable { case array([JSONValue]) } +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension JSONValue: Decodable { public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() @@ -68,6 +71,7 @@ extension JSONValue: Decodable { } } +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension JSONValue: Encodable { public func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() @@ -93,4 +97,5 @@ extension JSONValue: Encodable { } } +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension JSONValue: Equatable {} diff --git a/FirebaseVertexAI/Sources/ModelContent.swift b/FirebaseVertexAI/Sources/ModelContent.swift index 885d209e0a1..ba87736e648 100644 --- a/FirebaseVertexAI/Sources/ModelContent.swift +++ b/FirebaseVertexAI/Sources/ModelContent.swift @@ -14,7 +14,7 @@ import Foundation -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension [ModelContent] { // TODO: Rename and refactor this. func throwIfError() throws { @@ -34,7 +34,7 @@ extension [ModelContent] { /// A type describing data in media formats interpretable by an AI model. Each generative AI /// request or response contains an `Array` of ``ModelContent``s, and each ``ModelContent`` value /// may comprise multiple heterogeneous ``Part``s. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct ModelContent: Equatable, Sendable { enum InternalPart: Equatable, Sendable { case text(String) @@ -106,7 +106,7 @@ public struct ModelContent: Equatable, Sendable { // MARK: Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension ModelContent: Codable { enum CodingKeys: String, CodingKey { case role @@ -114,7 +114,7 @@ extension ModelContent: Codable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension ModelContent.InternalPart: Codable { enum CodingKeys: String, CodingKey { case text diff --git a/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift b/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift index 24d11be2c46..9c5a0c7fe77 100644 --- a/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift +++ b/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift @@ -37,7 +37,7 @@ enum ImageConversionError: Error { #if canImport(UIKit) /// Enables images to be representable as ``PartsRepresentable``. - @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension UIImage: PartsRepresentable { public var partsValue: [any Part] { guard let data = jpegData(compressionQuality: imageCompressionQuality) else { @@ -49,7 +49,7 @@ enum ImageConversionError: Error { #elseif canImport(AppKit) /// Enables images to be representable as ``PartsRepresentable``. - @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension NSImage: PartsRepresentable { public var partsValue: [any Part] { guard let cgImage = cgImage(forProposedRect: nil, context: nil, hints: nil) else { diff --git a/FirebaseVertexAI/Sources/PartsRepresentable.swift b/FirebaseVertexAI/Sources/PartsRepresentable.swift index 6ef63d3f182..82d0688df38 100644 --- a/FirebaseVertexAI/Sources/PartsRepresentable.swift +++ b/FirebaseVertexAI/Sources/PartsRepresentable.swift @@ -16,13 +16,13 @@ import Foundation /// A protocol describing any data that could be serialized to model-interpretable input data, /// where the serialization process cannot fail with an error. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public protocol PartsRepresentable { var partsValue: [any Part] { get } } /// Enables a ``Part`` to be used as a ``PartsRepresentable``. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public extension Part { var partsValue: [any Part] { return [self] @@ -31,7 +31,7 @@ public extension Part { /// Enable an `Array` of ``PartsRepresentable`` values to be passed in as a single /// ``PartsRepresentable``. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension [PartsRepresentable]: PartsRepresentable { public var partsValue: [any Part] { return flatMap { $0.partsValue } @@ -39,7 +39,7 @@ extension [PartsRepresentable]: PartsRepresentable { } /// Enables a `String` to be passed in as ``PartsRepresentable``. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension String: PartsRepresentable { public var partsValue: [any Part] { return [TextPart(self)] diff --git a/FirebaseVertexAI/Sources/Safety.swift b/FirebaseVertexAI/Sources/Safety.swift index 655046db98a..decb54ba0e8 100644 --- a/FirebaseVertexAI/Sources/Safety.swift +++ b/FirebaseVertexAI/Sources/Safety.swift @@ -17,7 +17,7 @@ import Foundation /// A type defining potentially harmful media categories and their model-assigned ratings. A value /// of this type may be assigned to a category for every model-generated response, not just /// responses that exceed a certain threshold. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct SafetyRating: Equatable, Hashable, Sendable { /// The category describing the potential harm a piece of content may pose. /// @@ -75,6 +75,7 @@ public struct SafetyRating: Equatable, Hashable, Sendable { /// The probability that a given model output falls under a harmful content category. /// /// > Note: This does not indicate the severity of harm for a piece of content. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct HarmProbability: DecodableProtoEnum, Hashable, Sendable { enum Kind: String { case negligible = "NEGLIGIBLE" @@ -110,6 +111,7 @@ public struct SafetyRating: Equatable, Hashable, Sendable { } /// The magnitude of how harmful a model response might be for the respective ``HarmCategory``. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct HarmSeverity: DecodableProtoEnum, Hashable, Sendable { enum Kind: String { case negligible = "HARM_SEVERITY_NEGLIGIBLE" @@ -143,7 +145,7 @@ public struct SafetyRating: Equatable, Hashable, Sendable { /// A type used to specify a threshold for harmful content, beyond which the model will return a /// fallback response instead of generated content. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct SafetySetting { /// Block at and beyond a specified ``SafetyRating/HarmProbability``. public struct HarmBlockThreshold: EncodableProtoEnum, Sendable { @@ -174,6 +176,7 @@ public struct SafetySetting { } /// The method of computing whether the ``SafetySetting/HarmBlockThreshold`` has been exceeded. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct HarmBlockMethod: EncodableProtoEnum, Sendable { enum Kind: String { case severity = "SEVERITY" @@ -224,6 +227,7 @@ public struct SafetySetting { } /// Categories describing the potential harm a piece of content may pose. +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct HarmCategory: CodableProtoEnum, Hashable, Sendable { enum Kind: String { case harassment = "HARM_CATEGORY_HARASSMENT" @@ -260,7 +264,7 @@ public struct HarmCategory: CodableProtoEnum, Hashable, Sendable { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension SafetyRating: Decodable { enum CodingKeys: CodingKey { case category @@ -287,8 +291,8 @@ extension SafetyRating: Decodable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension SafetySetting.HarmBlockThreshold: Encodable {} -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension SafetySetting: Encodable {} diff --git a/FirebaseVertexAI/Sources/Types/Internal/InternalPart.swift b/FirebaseVertexAI/Sources/Types/Internal/InternalPart.swift index 8a62ae4fdd9..872f394abd1 100644 --- a/FirebaseVertexAI/Sources/Types/Internal/InternalPart.swift +++ b/FirebaseVertexAI/Sources/Types/Internal/InternalPart.swift @@ -14,7 +14,7 @@ import Foundation -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct InlineData: Codable, Equatable, Sendable { let mimeType: String let data: Data @@ -25,7 +25,7 @@ struct InlineData: Codable, Equatable, Sendable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct FileData: Codable, Equatable, Sendable { let fileURI: String let mimeType: String @@ -36,7 +36,7 @@ struct FileData: Codable, Equatable, Sendable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct FunctionCall: Equatable, Sendable { let name: String let args: JSONObject @@ -47,7 +47,7 @@ struct FunctionCall: Equatable, Sendable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct FunctionResponse: Codable, Equatable, Sendable { let name: String let response: JSONObject @@ -58,7 +58,7 @@ struct FunctionResponse: Codable, Equatable, Sendable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) struct ErrorPart: Part, Error { let error: Error @@ -69,7 +69,7 @@ struct ErrorPart: Part, Error { // MARK: - Codable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension FunctionCall: Codable { init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) @@ -82,7 +82,7 @@ extension FunctionCall: Codable { } } -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension ErrorPart: Codable { init(from decoder: any Decoder) throws { fatalError("Decoding an ErrorPart is not supported.") @@ -95,7 +95,7 @@ extension ErrorPart: Codable { // MARK: - Equatable Conformances -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension ErrorPart: Equatable { static func == (lhs: ErrorPart, rhs: ErrorPart) -> Bool { fatalError("Comparing ErrorParts for equality is not supported.") diff --git a/FirebaseVertexAI/Sources/Types/Public/Part.swift b/FirebaseVertexAI/Sources/Types/Public/Part.swift index 8cc25de1db2..41de624c56c 100644 --- a/FirebaseVertexAI/Sources/Types/Public/Part.swift +++ b/FirebaseVertexAI/Sources/Types/Public/Part.swift @@ -17,11 +17,11 @@ import Foundation /// A discrete piece of data in a media format interpretable by an AI model. /// /// Within a single value of ``Part``, different data types may not mix. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public protocol Part: PartsRepresentable, Codable, Sendable, Equatable {} /// A text part containing a string value. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct TextPart: Part { /// Text value. public let text: String @@ -34,7 +34,7 @@ public struct TextPart: Part { /// Data with a specified media type. /// /// > Note: Not all media types may be supported by the AI model. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct InlineDataPart: Part { let inlineData: InlineData @@ -51,7 +51,7 @@ public struct InlineDataPart: Part { } /// File data stored in Cloud Storage for Firebase, referenced by URI. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FileDataPart: Part { let fileData: FileData @@ -77,7 +77,7 @@ public struct FileDataPart: Part { } /// A predicted function call returned from the model. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FunctionCallPart: Part { let functionCall: FunctionCall @@ -109,7 +109,7 @@ public struct FunctionCallPart: Part { /// Contains a string representing the `FunctionDeclaration.name` and a structured JSON object /// containing any output from the function is used as context to the model. This should contain the /// result of a ``FunctionCallPart`` made based on model prediction. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct FunctionResponsePart: Part { let functionResponse: FunctionResponse diff --git a/FirebaseVertexAI/Sources/Types/Public/Schema.swift b/FirebaseVertexAI/Sources/Types/Public/Schema.swift index 9496113a071..93cf4f55127 100644 --- a/FirebaseVertexAI/Sources/Types/Public/Schema.swift +++ b/FirebaseVertexAI/Sources/Types/Public/Schema.swift @@ -18,8 +18,10 @@ import Foundation /// /// These types can be objects, but also primitives and arrays. Represents a select subset of an /// [OpenAPI 3.0 schema object](https://spec.openapis.org/oas/v3.0.3#schema). +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public class Schema { /// Modifiers describing the expected format of a string `Schema`. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct StringFormat: EncodableProtoEnum { // This enum is currently only used to conform `StringFormat` to `ProtoEnum`, which requires // `associatedtype Kind: RawRepresentable`. @@ -37,6 +39,7 @@ public class Schema { } /// Modifiers describing the expected format of an integer `Schema`. + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public struct IntegerFormat: EncodableProtoEnum { enum Kind: String { case int32 @@ -321,6 +324,7 @@ public class Schema { // MARK: - Codable Conformance +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) extension Schema: Encodable { enum CodingKeys: String, CodingKey { case dataType = "type" diff --git a/FirebaseVertexAI/Sources/VertexAI.swift b/FirebaseVertexAI/Sources/VertexAI.swift index 896f2982c61..ad378c067d1 100644 --- a/FirebaseVertexAI/Sources/VertexAI.swift +++ b/FirebaseVertexAI/Sources/VertexAI.swift @@ -21,7 +21,7 @@ import Foundation @_implementationOnly import FirebaseCoreExtension /// The Vertex AI for Firebase SDK provides access to Gemini models directly from your app. -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) public class VertexAI { // MARK: - Public APIs diff --git a/FirebaseVertexAI/Tests/Unit/GenerationConfigTests.swift b/FirebaseVertexAI/Tests/Unit/GenerationConfigTests.swift index 232807d08da..e6bfe7cf09b 100644 --- a/FirebaseVertexAI/Tests/Unit/GenerationConfigTests.swift +++ b/FirebaseVertexAI/Tests/Unit/GenerationConfigTests.swift @@ -16,7 +16,7 @@ import FirebaseVertexAI import Foundation import XCTest -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class GenerationConfigTests: XCTestCase { let encoder = JSONEncoder() diff --git a/FirebaseVertexAI/Tests/Unit/JSONValueTests.swift b/FirebaseVertexAI/Tests/Unit/JSONValueTests.swift index 74196230887..77b88b686e1 100644 --- a/FirebaseVertexAI/Tests/Unit/JSONValueTests.swift +++ b/FirebaseVertexAI/Tests/Unit/JSONValueTests.swift @@ -15,6 +15,7 @@ import XCTest @testable import FirebaseVertexAI +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class JSONValueTests: XCTestCase { let decoder = JSONDecoder() let encoder = JSONEncoder() diff --git a/FirebaseVertexAI/Tests/Unit/PartTests.swift b/FirebaseVertexAI/Tests/Unit/PartTests.swift index 35c3b441d9f..d48600e9013 100644 --- a/FirebaseVertexAI/Tests/Unit/PartTests.swift +++ b/FirebaseVertexAI/Tests/Unit/PartTests.swift @@ -17,7 +17,7 @@ import XCTest @testable import FirebaseVertexAI -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class PartTests: XCTestCase { let decoder = JSONDecoder() let encoder = JSONEncoder() diff --git a/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift b/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift index 859b77f58c7..cf5e6a1eadf 100644 --- a/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift +++ b/FirebaseVertexAI/Tests/Unit/PartsRepresentableTests.swift @@ -25,7 +25,7 @@ import XCTest @testable import FirebaseVertexAI -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class PartsRepresentableTests: XCTestCase { #if !os(watchOS) func testModelContentFromCGImageIsNotEmpty() throws { diff --git a/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift b/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift index f113bb7bf49..56dff8dd02b 100644 --- a/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift +++ b/FirebaseVertexAI/Tests/Unit/VertexAIAPITests.swift @@ -21,7 +21,7 @@ import XCTest import UIKit // For UIImage extensions. #endif -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) final class VertexAIAPITests: XCTestCase { func codeSamples() async throws { let app = FirebaseApp.app() diff --git a/FirebaseVertexAI/Tests/Unit/VertexComponentTests.swift b/FirebaseVertexAI/Tests/Unit/VertexComponentTests.swift index 64a3edcc6b8..bea85bf96e7 100644 --- a/FirebaseVertexAI/Tests/Unit/VertexComponentTests.swift +++ b/FirebaseVertexAI/Tests/Unit/VertexComponentTests.swift @@ -20,7 +20,7 @@ import XCTest @testable import FirebaseVertexAI -@available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) class VertexComponentTests: XCTestCase { static let projectID = "test-project-id" static let apiKey = "test-api-key" From e7ba8900178882b23d27b5fb8890aebb6c542ad6 Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 16 Oct 2024 10:42:43 -0400 Subject: [PATCH 2/3] Add changelog entry --- FirebaseVertexAI/CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/FirebaseVertexAI/CHANGELOG.md b/FirebaseVertexAI/CHANGELOG.md index 95d70ca6c0a..02aa129a852 100644 --- a/FirebaseVertexAI/CHANGELOG.md +++ b/FirebaseVertexAI/CHANGELOG.md @@ -52,6 +52,9 @@ `any(allowedFunctionNames:)`, or `none()` to create a config. (#13873) - [changed] **Breaking Change**: The `CandidateResponse` type is now named `Candidate`. (#13897) +- [changed] **Breaking Change**: The minimum deployment target for the SDK is + now macOS 12.0; all other platform minimums remain the same at iOS 15.0, + macCatalyst 15.0, tvOS 15.0, and watchOS 8.0. (#13903) - [changed] The default request timeout is now 180 seconds instead of the platform-default value of 60 seconds for a `URLRequest`; this timeout may still be customized in `RequestOptions`. (#13722) From 27a46b25f27f13e64cb999036bfd151a211272db Mon Sep 17 00:00:00 2001 From: Andrew Heard Date: Wed, 16 Oct 2024 11:02:03 -0400 Subject: [PATCH 3/3] Fix `PartsRepresentable+Image` annotations --- FirebaseVertexAI/Sources/PartsRepresentable+Image.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift b/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift index 9c5a0c7fe77..5bedeb8f3d1 100644 --- a/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift +++ b/FirebaseVertexAI/Sources/PartsRepresentable+Image.swift @@ -67,7 +67,7 @@ enum ImageConversionError: Error { #if !os(watchOS) // This code does not build on watchOS. /// Enables `CGImages` to be representable as model content. - @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, *) + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) extension CGImage: PartsRepresentable { public var partsValue: [any Part] { let output = NSMutableData() @@ -90,7 +90,7 @@ enum ImageConversionError: Error { #if canImport(CoreImage) /// Enables `CIImages` to be representable as model content. - @available(iOS 15.0, macOS 11.0, macCatalyst 15.0, tvOS 15.0, *) + @available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) extension CIImage: PartsRepresentable { public var partsValue: [any Part] { let context = CIContext()