Skip to content

Commit 1049020

Browse files
committed
[Firebase AI] Handle empty or unknown Part data
1 parent 176f083 commit 1049020

File tree

2 files changed

+27
-6
lines changed

2 files changed

+27
-6
lines changed

FirebaseAI/Sources/AILog.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ enum AILog {
6262
case decodedInvalidCitationPublicationDate = 3011
6363
case generateContentResponseUnrecognizedContentModality = 3012
6464
case decodedUnsupportedImagenPredictionType = 3013
65+
case decodedUnsupportedPartData = 3014
6566

6667
// SDK State Errors
6768
case generateContentResponseNoCandidates = 4000

FirebaseAI/Sources/ModelContent.swift

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,17 @@ struct InternalPart: Equatable, Sendable {
3939
case fileData(FileData)
4040
case functionCall(FunctionCall)
4141
case functionResponse(FunctionResponse)
42+
43+
struct UnsupportedDataError: Error {
44+
let decodingError: DecodingError
45+
46+
var localizedDescription: String {
47+
decodingError.localizedDescription
48+
}
49+
}
4250
}
4351

44-
let data: OneOfData
52+
let data: OneOfData?
4553

4654
let isThought: Bool?
4755

@@ -65,7 +73,7 @@ public struct ModelContent: Equatable, Sendable {
6573

6674
/// The data parts comprising this ``ModelContent`` value.
6775
public var parts: [any Part] {
68-
return internalParts.map { part -> any Part in
76+
return internalParts.compactMap { part -> (any Part)? in
6977
switch part.data {
7078
case let .text(text):
7179
return TextPart(text, isThought: part.isThought, thoughtSignature: part.thoughtSignature)
@@ -85,6 +93,9 @@ public struct ModelContent: Equatable, Sendable {
8593
return FunctionResponsePart(
8694
functionResponse, isThought: part.isThought, thoughtSignature: part.thoughtSignature
8795
)
96+
case .none:
97+
// Filter out parts that contain missing or unrecognized data
98+
return nil
8899
}
89100
}
90101
}
@@ -179,7 +190,14 @@ extension InternalPart: Codable {
179190
}
180191

181192
public init(from decoder: Decoder) throws {
182-
data = try OneOfData(from: decoder)
193+
do {
194+
data = try OneOfData(from: decoder)
195+
} catch let error as OneOfData.UnsupportedDataError {
196+
AILog.error(code: .decodedUnsupportedPartData, error.localizedDescription)
197+
data = nil
198+
} catch { // Re-throw any other error types
199+
throw error
200+
}
183201
let container = try decoder.container(keyedBy: CodingKeys.self)
184202
isThought = try container.decodeIfPresent(Bool.self, forKey: .isThought)
185203
thoughtSignature = try container.decodeIfPresent(String.self, forKey: .thoughtSignature)
@@ -226,9 +244,11 @@ extension InternalPart.OneOfData: Codable {
226244
self = try .functionResponse(values.decode(FunctionResponse.self, forKey: .functionResponse))
227245
} else {
228246
let unexpectedKeys = values.allKeys.map { $0.stringValue }
229-
throw DecodingError.dataCorrupted(DecodingError.Context(
230-
codingPath: values.codingPath,
231-
debugDescription: "Unexpected Part type(s): \(unexpectedKeys)"
247+
throw UnsupportedDataError(decodingError: DecodingError.dataCorrupted(
248+
DecodingError.Context(
249+
codingPath: values.codingPath,
250+
debugDescription: "Unexpected Part type(s): \(unexpectedKeys)"
251+
)
232252
))
233253
}
234254
}

0 commit comments

Comments
 (0)