Skip to content

Commit bde28ed

Browse files
committed
[Firebase AI] Conform ModelOutput to ConvertibleToGeneratedContent
1 parent bb3a034 commit bde28ed

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

FirebaseAI/Sources/Protocols/Public/StructuredOutput/ConvertibleFromModelOutput.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,23 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#if canImport(FoundationModels)
16+
public import protocol FoundationModels.ConvertibleFromGeneratedContent
17+
public import struct FoundationModels.GeneratedContent
18+
#endif // canImport(FoundationModels)
19+
1520
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
1621
public protocol ConvertibleFromModelOutput {
1722
init(_ content: ModelOutput) throws
1823
}
24+
25+
#if canImport(FoundationModels)
26+
@available(iOS 26.0, macOS 26.0, *)
27+
@available(tvOS, unavailable)
28+
@available(watchOS, unavailable)
29+
public extension ConvertibleFromModelOutput where Self: ConvertibleFromGeneratedContent {
30+
init(_ content: ModelOutput) throws {
31+
try self.init(try GeneratedContent(content))
32+
}
33+
}
34+
#endif // canImport(FoundationModels)

FirebaseAI/Sources/Protocols/Public/StructuredOutput/ConvertibleToModelOutput.swift

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15+
#if canImport(FoundationModels)
16+
public import protocol FoundationModels.ConvertibleToGeneratedContent
17+
public import struct FoundationModels.GeneratedContent
18+
#endif // canImport(FoundationModels)
19+
1520
#if compiler(>=6.2)
1621
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
1722
public protocol ConvertibleToModelOutput: SendableMetatype {
@@ -23,3 +28,14 @@
2328
var modelOutput: ModelOutput { get }
2429
}
2530
#endif // compiler(>=6.2)
31+
32+
#if canImport(FoundationModels)
33+
@available(iOS 26.0, macOS 26.0, *)
34+
@available(tvOS, unavailable)
35+
@available(watchOS, unavailable)
36+
public extension ConvertibleToModelOutput where Self: ConvertibleToGeneratedContent {
37+
var modelOutput: ModelOutput {
38+
self.generatedContent.modelOutput
39+
}
40+
}
41+
#endif // canImport(FoundationModels)

FirebaseAI/Sources/Types/Public/StructuredOutput/ModelOutput.swift

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@
1313
// limitations under the License.
1414

1515
import Foundation
16+
#if canImport(FoundationModels)
17+
public import protocol FoundationModels.ConvertibleToGeneratedContent
18+
public import struct FoundationModels.GenerationID
19+
public import struct FoundationModels.GeneratedContent
20+
#endif // canImport(FoundationModels)
1621

1722
@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *)
1823
public struct ModelOutput: Sendable, CustomDebugStringConvertible, FirebaseGenerable {
@@ -24,8 +29,9 @@ public struct ModelOutput: Sendable, CustomDebugStringConvertible, FirebaseGener
2429

2530
public var id: ResponseID?
2631

27-
init(kind: Kind) {
32+
init(kind: Kind, id: ResponseID? = nil) {
2833
self.kind = kind
34+
self.id = id
2935
}
3036

3137
public var debugDescription: String {
@@ -173,3 +179,66 @@ public extension ModelOutput {
173179
}
174180
}
175181
}
182+
183+
#if canImport(FoundationModels)
184+
@available(iOS 26.0, macOS 26.0, *)
185+
@available(tvOS, unavailable)
186+
@available(watchOS, unavailable)
187+
extension ModelOutput: ConvertibleToGeneratedContent {
188+
public var generatedContent: GeneratedContent {
189+
let generationID = id?.generationID
190+
191+
switch kind {
192+
case .null:
193+
return GeneratedContent(kind: .null, id: generationID)
194+
case let .bool(value):
195+
return GeneratedContent(kind: .bool(value), id: generationID)
196+
case let .number(value):
197+
return GeneratedContent(kind: .number(value), id: generationID)
198+
case let .string(value):
199+
return GeneratedContent(kind: .string(value), id: generationID)
200+
case let .array(values):
201+
return GeneratedContent(kind: .array(values.map { $0.generatedContent }), id: generationID)
202+
case let .structure(properties: properties, orderedKeys: orderedKeys):
203+
return GeneratedContent(
204+
kind: .structure(
205+
properties: properties.mapValues { $0.generatedContent }, orderedKeys: orderedKeys
206+
),
207+
id: generationID
208+
)
209+
}
210+
}
211+
}
212+
213+
@available(iOS 26.0, macOS 26.0, *)
214+
@available(tvOS, unavailable)
215+
@available(watchOS, unavailable)
216+
extension GeneratedContent: ConvertibleToModelOutput {
217+
public var modelOutput: ModelOutput {
218+
let responseID = self.id.map { ResponseID(generationID: $0) }
219+
220+
switch self.kind {
221+
case .null:
222+
return ModelOutput(kind: .null, id: responseID)
223+
case let .bool(value):
224+
return ModelOutput(kind: .bool(value), id: responseID)
225+
case let .number(value):
226+
return ModelOutput(kind: .number(value), id: responseID)
227+
case let .string(value):
228+
return ModelOutput(kind: .string(value), id: responseID)
229+
case let .array(values):
230+
return ModelOutput(kind: .array(values.map { $0.modelOutput }), id: responseID)
231+
case let .structure(properties: properties, orderedKeys: orderedKeys):
232+
return ModelOutput(
233+
kind: .structure(
234+
properties: properties.mapValues { $0.modelOutput }, orderedKeys: orderedKeys
235+
),
236+
id: responseID
237+
)
238+
@unknown default:
239+
assertionFailure("Unknown `FoundationModels.GeneratedContent` kind: \(kind)")
240+
return ModelOutput(kind: .null, id: responseID)
241+
}
242+
}
243+
}
244+
#endif // canImport(FoundationModels)

FirebaseAI/Sources/Types/Public/StructuredOutput/ResponseID.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,17 @@ public struct ResponseID: Sendable, Hashable {
5050
init(generationID: GenerationID) {
5151
identifier = .generationID(generationID)
5252
}
53+
54+
@available(iOS 26.0, macOS 26.0, *)
55+
@available(tvOS, unavailable)
56+
@available(watchOS, unavailable)
57+
var generationID: GenerationID? {
58+
guard case let .generationID(value) = identifier else {
59+
return nil
60+
}
61+
62+
return value as? GenerationID
63+
}
5364
#endif // canImport(FoundationModels)
5465
}
5566

0 commit comments

Comments
 (0)