@@ -31,41 +31,62 @@ extension [ModelContent] {
31
31
}
32
32
}
33
33
34
- /// A type describing data in media formats interpretable by an AI model. Each generative AI
35
- /// request or response contains an `Array` of ``ModelContent``s, and each ``ModelContent`` value
36
- /// may comprise multiple heterogeneous ``Part``s.
37
34
@available ( iOS 15 . 0 , macOS 12 . 0 , macCatalyst 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
38
- public struct ModelContent : Equatable , Sendable {
39
- enum InternalPart : Equatable , Sendable {
35
+ struct InternalPart : Equatable , Sendable {
36
+ enum OneOfData : Equatable , Sendable {
40
37
case text( String )
41
- case inlineData( mimetype : String , Data )
42
- case fileData( mimetype : String , uri : String )
38
+ case inlineData( InlineData )
39
+ case fileData( FileData )
43
40
case functionCall( FunctionCall )
44
41
case functionResponse( FunctionResponse )
45
42
}
46
43
44
+ let data : OneOfData
45
+
46
+ let isThought : Bool ?
47
+
48
+ let thoughtSignature : String ?
49
+
50
+ init ( _ data: OneOfData , isThought: Bool ? , thoughtSignature: String ? ) {
51
+ self . data = data
52
+ self . isThought = isThought
53
+ self . thoughtSignature = thoughtSignature
54
+ }
55
+ }
56
+
57
+ /// A type describing data in media formats interpretable by an AI model. Each generative AI
58
+ /// request or response contains an `Array` of ``ModelContent``s, and each ``ModelContent`` value
59
+ /// may comprise multiple heterogeneous ``Part``s.
60
+ @available ( iOS 15 . 0 , macOS 12 . 0 , macCatalyst 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
61
+ public struct ModelContent : Equatable , Sendable {
47
62
/// The role of the entity creating the ``ModelContent``. For user-generated client requests,
48
63
/// for example, the role is `user`.
49
64
public let role : String ?
50
65
51
66
/// The data parts comprising this ``ModelContent`` value.
52
67
public var parts : [ any Part ] {
53
- var convertedParts = [ any Part ] ( )
54
- for part in internalParts {
55
- switch part {
68
+ return internalParts. map { part -> any Part in
69
+ switch part. data {
56
70
case let . text( text) :
57
- convertedParts. append ( TextPart ( text) )
58
- case let . inlineData( mimetype, data) :
59
- convertedParts. append ( InlineDataPart ( data: data, mimeType: mimetype) )
60
- case let . fileData( mimetype, uri) :
61
- convertedParts. append ( FileDataPart ( uri: uri, mimeType: mimetype) )
71
+ return TextPart ( text, isThought: part. isThought, thoughtSignature: part. thoughtSignature)
72
+ case let . inlineData( inlineData) :
73
+ return InlineDataPart (
74
+ inlineData, isThought: part. isThought, thoughtSignature: part. thoughtSignature
75
+ )
76
+ case let . fileData( fileData) :
77
+ return FileDataPart (
78
+ fileData, isThought: part. isThought, thoughtSignature: part. thoughtSignature
79
+ )
62
80
case let . functionCall( functionCall) :
63
- convertedParts. append ( FunctionCallPart ( functionCall) )
81
+ return FunctionCallPart (
82
+ functionCall, isThought: part. isThought, thoughtSignature: part. thoughtSignature
83
+ )
64
84
case let . functionResponse( functionResponse) :
65
- convertedParts. append ( FunctionResponsePart ( functionResponse) )
85
+ return FunctionResponsePart (
86
+ functionResponse, isThought: part. isThought, thoughtSignature: part. thoughtSignature
87
+ )
66
88
}
67
89
}
68
- return convertedParts
69
90
}
70
91
71
92
// TODO: Refactor this
@@ -78,17 +99,35 @@ public struct ModelContent: Equatable, Sendable {
78
99
for part in parts {
79
100
switch part {
80
101
case let textPart as TextPart :
81
- convertedParts. append ( . text( textPart. text) )
102
+ convertedParts. append ( InternalPart (
103
+ . text( textPart. text) ,
104
+ isThought: textPart. _isThought,
105
+ thoughtSignature: textPart. thoughtSignature
106
+ ) )
82
107
case let inlineDataPart as InlineDataPart :
83
- let inlineData = inlineDataPart. inlineData
84
- convertedParts. append ( . inlineData( mimetype: inlineData. mimeType, inlineData. data) )
108
+ convertedParts. append ( InternalPart (
109
+ . inlineData( inlineDataPart. inlineData) ,
110
+ isThought: inlineDataPart. _isThought,
111
+ thoughtSignature: inlineDataPart. thoughtSignature
112
+ ) )
85
113
case let fileDataPart as FileDataPart :
86
- let fileData = fileDataPart. fileData
87
- convertedParts. append ( . fileData( mimetype: fileData. mimeType, uri: fileData. fileURI) )
114
+ convertedParts. append ( InternalPart (
115
+ . fileData( fileDataPart. fileData) ,
116
+ isThought: fileDataPart. _isThought,
117
+ thoughtSignature: fileDataPart. thoughtSignature
118
+ ) )
88
119
case let functionCallPart as FunctionCallPart :
89
- convertedParts. append ( . functionCall( functionCallPart. functionCall) )
120
+ convertedParts. append ( InternalPart (
121
+ . functionCall( functionCallPart. functionCall) ,
122
+ isThought: functionCallPart. _isThought,
123
+ thoughtSignature: functionCallPart. thoughtSignature
124
+ ) )
90
125
case let functionResponsePart as FunctionResponsePart :
91
- convertedParts. append ( . functionResponse( functionResponsePart. functionResponse) )
126
+ convertedParts. append ( InternalPart (
127
+ . functionResponse( functionResponsePart. functionResponse) ,
128
+ isThought: functionResponsePart. _isThought,
129
+ thoughtSignature: functionResponsePart. thoughtSignature
130
+ ) )
92
131
default :
93
132
fatalError ( )
94
133
}
@@ -102,6 +141,11 @@ public struct ModelContent: Equatable, Sendable {
102
141
let content = parts. flatMap { $0. partsValue }
103
142
self . init ( role: role, parts: content)
104
143
}
144
+
145
+ init ( role: String ? , parts: [ InternalPart ] ) {
146
+ self . role = role
147
+ internalParts = parts
148
+ }
105
149
}
106
150
107
151
// MARK: Codable Conformances
@@ -121,7 +165,29 @@ extension ModelContent: Codable {
121
165
}
122
166
123
167
@available ( iOS 15 . 0 , macOS 12 . 0 , macCatalyst 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
124
- extension ModelContent . InternalPart : Codable {
168
+ extension InternalPart : Codable {
169
+ enum CodingKeys : String , CodingKey {
170
+ case isThought = " thought "
171
+ case thoughtSignature
172
+ }
173
+
174
+ public func encode( to encoder: Encoder ) throws {
175
+ try data. encode ( to: encoder)
176
+ var container = encoder. container ( keyedBy: CodingKeys . self)
177
+ try container. encodeIfPresent ( isThought, forKey: . isThought)
178
+ try container. encodeIfPresent ( thoughtSignature, forKey: . thoughtSignature)
179
+ }
180
+
181
+ public init ( from decoder: Decoder ) throws {
182
+ data = try OneOfData ( from: decoder)
183
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
184
+ isThought = try container. decodeIfPresent ( Bool . self, forKey: . isThought)
185
+ thoughtSignature = try container. decodeIfPresent ( String . self, forKey: . thoughtSignature)
186
+ }
187
+ }
188
+
189
+ @available ( iOS 15 . 0 , macOS 12 . 0 , macCatalyst 15 . 0 , tvOS 15 . 0 , watchOS 8 . 0 , * )
190
+ extension InternalPart . OneOfData : Codable {
125
191
enum CodingKeys : String , CodingKey {
126
192
case text
127
193
case inlineData
@@ -135,10 +201,10 @@ extension ModelContent.InternalPart: Codable {
135
201
switch self {
136
202
case let . text( text) :
137
203
try container. encode ( text, forKey: . text)
138
- case let . inlineData( mimetype , bytes ) :
139
- try container. encode ( InlineData ( data : bytes , mimeType : mimetype ) , forKey: . inlineData)
140
- case let . fileData( mimetype : mimetype , url ) :
141
- try container. encode ( FileData ( fileURI : url , mimeType : mimetype ) , forKey: . fileData)
204
+ case let . inlineData( inlineData ) :
205
+ try container. encode ( inlineData , forKey: . inlineData)
206
+ case let . fileData( fileData ) :
207
+ try container. encode ( fileData , forKey: . fileData)
142
208
case let . functionCall( functionCall) :
143
209
try container. encode ( functionCall, forKey: . functionCall)
144
210
case let . functionResponse( functionResponse) :
@@ -151,11 +217,9 @@ extension ModelContent.InternalPart: Codable {
151
217
if values. contains ( . text) {
152
218
self = try . text( values. decode ( String . self, forKey: . text) )
153
219
} else if values. contains ( . inlineData) {
154
- let inlineData = try values. decode ( InlineData . self, forKey: . inlineData)
155
- self = . inlineData( mimetype: inlineData. mimeType, inlineData. data)
220
+ self = try . inlineData( values. decode ( InlineData . self, forKey: . inlineData) )
156
221
} else if values. contains ( . fileData) {
157
- let fileData = try values. decode ( FileData . self, forKey: . fileData)
158
- self = . fileData( mimetype: fileData. mimeType, uri: fileData. fileURI)
222
+ self = try . fileData( values. decode ( FileData . self, forKey: . fileData) )
159
223
} else if values. contains ( . functionCall) {
160
224
self = try . functionCall( values. decode ( FunctionCall . self, forKey: . functionCall) )
161
225
} else if values. contains ( . functionResponse) {
0 commit comments