mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
263 lines
11 KiB
Swift
263 lines
11 KiB
Swift
// Copyright 2026 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import Foundation
|
|
|
|
/// An internal data model for `Part`.
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// Type: `GoogleAiGenerativelanguageV1betaPart`
|
|
///
|
|
/// A datatype containing media that is part of a multi-part `Content` message.
|
|
///
|
|
/// A `Part` consists of data which has an associated datatype. A `Part` can only
|
|
/// contain one of the accepted types in `Part.data`.
|
|
///
|
|
/// A `Part` must have a fixed IANA MIME type identifying the type and subtype
|
|
/// of the media if the `inline_data` field is filled with raw bytes.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// Type: `GoogleCloudAiplatformV1beta1Part`
|
|
///
|
|
/// A datatype containing media that is part of a multi-part
|
|
/// Content message.
|
|
///
|
|
/// A `Part` consists of data which has an associated datatype. A `Part` can only
|
|
/// contain one of the accepted types in `Part.data`.
|
|
///
|
|
/// For media types that are not text, `Part` must have a fixed IANA MIME type
|
|
/// identifying the type and subtype of the media if `inline_data` or
|
|
/// `file_data` field is filled with raw bytes.
|
|
package struct Part: Codable, Sendable, Equatable, Hashable {
|
|
/// Server-side tool call. This field is populated when the model
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// Server-side tool call. This field is populated when the model
|
|
/// predicts a tool invocation that should be executed on the server.
|
|
/// The client is expected to echo this message back to the API.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// > Important: This property is not supported in the Gemini Enterprise API.
|
|
package let toolCall: ToolCall?
|
|
|
|
/// The output from a server-side `ToolCall` execution. This field is
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// The output from a server-side `ToolCall` execution. This field is
|
|
/// populated by the client with the results of executing the
|
|
/// corresponding `ToolCall`.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// > Important: This property is not supported in the Gemini Enterprise API.
|
|
package let toolResponse: ToolResponse?
|
|
|
|
/// Optional. Indicates if the part is thought from the model.
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// Optional. Indicates if the part is thought from the model.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// Optional. Indicates whether the `part` represents the model's thought
|
|
/// process or reasoning.
|
|
package let thought: Bool?
|
|
|
|
/// Optional. An opaque signature for the thought so it can be reused in subsequent
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// Optional. An opaque signature for the thought so it can be reused in subsequent
|
|
/// requests.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// Optional. An opaque signature for the thought so it can be reused in
|
|
/// subsequent requests.
|
|
package let thoughtSignature: String?
|
|
|
|
/// Custom metadata associated with the Part.
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// Custom metadata associated with the Part.
|
|
/// Agents using genai.Part as content representation may need to keep track
|
|
/// of the additional information. For example it can be name of a file/source
|
|
/// from which the Part originates or a way to multiplex multiple Part streams.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// > Important: This property is not supported in the Gemini Enterprise API.
|
|
package let partMetadata: [String: JSONValue]?
|
|
|
|
/// Optional. Media resolution for the input media.
|
|
///
|
|
/// ### Gemini Developer API
|
|
///
|
|
/// Optional. Media resolution for the input media.
|
|
///
|
|
/// ### Gemini Enterprise API
|
|
///
|
|
/// per part media resolution.
|
|
/// Media resolution for the input media.
|
|
package let mediaResolution: Part.MediaResolution?
|
|
|
|
package enum PartData: Sendable, Equatable, Hashable {
|
|
case text(String)
|
|
case inlineData(Blob)
|
|
case functionCall(FunctionCall)
|
|
case functionResponse(FunctionResponse)
|
|
case fileData(FileData)
|
|
case executableCode(ExecutableCode)
|
|
case codeExecutionResult(CodeExecutionResult)
|
|
case unrecognized([String: JSONValue])
|
|
}
|
|
|
|
package let data: PartData?
|
|
|
|
/// Creates a new `Part`.
|
|
///
|
|
/// - Parameters:
|
|
/// - toolCall: Server-side tool call. This field is populated when the model (Gemini Developer API only). For more details, see ``toolCall``.
|
|
/// - toolResponse: The output from a server-side `ToolCall` execution. This field is (Gemini Developer API only). For more details, see ``toolResponse``.
|
|
/// - videoMetadata: Optional. Video metadata. The metadata should only be specified while the video (behavior varies by backend). For more details, see ``videoMetadata``.
|
|
/// - thought: Optional. Indicates if the part is thought from the model. (behavior varies by backend). For more details, see ``thought``.
|
|
/// - thoughtSignature: Optional. An opaque signature for the thought so it can be reused in subsequent (behavior varies by backend). For more details, see ``thoughtSignature``.
|
|
/// - partMetadata: Custom metadata associated with the Part. (Gemini Developer API only). For more details, see ``partMetadata``.
|
|
/// - mediaResolution: Optional. Media resolution for the input media. (behavior varies by backend). For more details, see ``mediaResolution``.
|
|
/// - data: One of the oneof data variants.
|
|
package init(
|
|
data: PartData? = nil,
|
|
toolCall: ToolCall? = nil,
|
|
toolResponse: ToolResponse? = nil,
|
|
thought: Bool? = nil,
|
|
thoughtSignature: String? = nil,
|
|
partMetadata: [String: JSONValue]? = nil,
|
|
mediaResolution: Part.MediaResolution? = nil
|
|
) {
|
|
self.data = data
|
|
self.toolCall = toolCall
|
|
self.toolResponse = toolResponse
|
|
self.thought = thought
|
|
self.thoughtSignature = thoughtSignature
|
|
self.partMetadata = partMetadata
|
|
self.mediaResolution = mediaResolution
|
|
}
|
|
enum CodingKeys: String, CodingKey {
|
|
case toolCall = "toolCall"
|
|
case toolResponse = "toolResponse"
|
|
case videoMetadata = "videoMetadata"
|
|
case thought = "thought"
|
|
case thoughtSignature = "thoughtSignature"
|
|
case partMetadata = "partMetadata"
|
|
case mediaResolution = "mediaResolution"
|
|
case text = "text"
|
|
case inlineData = "inlineData"
|
|
case functionCall = "functionCall"
|
|
case functionResponse = "functionResponse"
|
|
case fileData = "fileData"
|
|
case executableCode = "executableCode"
|
|
case codeExecutionResult = "codeExecutionResult"
|
|
}
|
|
private struct DynamicCodingKey: CodingKey {
|
|
var stringValue: String
|
|
var intValue: Int? { nil }
|
|
init?(stringValue: String) { self.stringValue = stringValue }
|
|
init?(intValue: Int) { nil }
|
|
}
|
|
|
|
package init(from decoder: any Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
self.toolCall = try container.decodeIfPresent(ToolCall.self, forKey: .toolCall)
|
|
self.toolResponse = try container.decodeIfPresent(ToolResponse.self, forKey: .toolResponse)
|
|
self.thought = try container.decodeIfPresent(Bool.self, forKey: .thought)
|
|
self.thoughtSignature = try container.decodeIfPresent(String.self, forKey: .thoughtSignature)
|
|
self.partMetadata = try container.decodeIfPresent(
|
|
[String: JSONValue].self, forKey: .partMetadata)
|
|
self.mediaResolution = try container.decodeIfPresent(
|
|
Part.MediaResolution.self, forKey: .mediaResolution)
|
|
|
|
if false {
|
|
self.data = nil
|
|
} else if let text = try container.decodeIfPresent(String.self, forKey: .text) {
|
|
self.data = .text(text)
|
|
} else if let inlineData = try container.decodeIfPresent(Blob.self, forKey: .inlineData) {
|
|
self.data = .inlineData(inlineData)
|
|
} else if let functionCall = try container.decodeIfPresent(
|
|
FunctionCall.self, forKey: .functionCall)
|
|
{
|
|
self.data = .functionCall(functionCall)
|
|
} else if let functionResponse = try container.decodeIfPresent(
|
|
FunctionResponse.self, forKey: .functionResponse)
|
|
{
|
|
self.data = .functionResponse(functionResponse)
|
|
} else if let fileData = try container.decodeIfPresent(FileData.self, forKey: .fileData) {
|
|
self.data = .fileData(fileData)
|
|
} else if let executableCode = try container.decodeIfPresent(
|
|
ExecutableCode.self, forKey: .executableCode)
|
|
{
|
|
self.data = .executableCode(executableCode)
|
|
} else if let codeExecutionResult = try container.decodeIfPresent(
|
|
CodeExecutionResult.self, forKey: .codeExecutionResult)
|
|
{
|
|
self.data = .codeExecutionResult(codeExecutionResult)
|
|
} else {
|
|
let dynamicContainer = try decoder.container(keyedBy: DynamicCodingKey.self)
|
|
var unrecognizedFields = [String: JSONValue]()
|
|
for key in dynamicContainer.allKeys {
|
|
if CodingKeys(stringValue: key.stringValue) == nil,
|
|
let value = try? dynamicContainer.decode(JSONValue.self, forKey: key)
|
|
{
|
|
unrecognizedFields[key.stringValue] = value
|
|
}
|
|
}
|
|
self.data = unrecognizedFields.isEmpty ? nil : .unrecognized(unrecognizedFields)
|
|
}
|
|
}
|
|
|
|
package func encode(to encoder: any Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
try container.encodeIfPresent(toolCall, forKey: .toolCall)
|
|
try container.encodeIfPresent(toolResponse, forKey: .toolResponse)
|
|
try container.encodeIfPresent(thought, forKey: .thought)
|
|
try container.encodeIfPresent(thoughtSignature, forKey: .thoughtSignature)
|
|
try container.encodeIfPresent(partMetadata, forKey: .partMetadata)
|
|
try container.encodeIfPresent(mediaResolution, forKey: .mediaResolution)
|
|
|
|
switch data {
|
|
case .none: break
|
|
case .text(let val): try container.encode(val, forKey: .text)
|
|
case .inlineData(let val): try container.encode(val, forKey: .inlineData)
|
|
case .functionCall(let val): try container.encode(val, forKey: .functionCall)
|
|
case .functionResponse(let val): try container.encode(val, forKey: .functionResponse)
|
|
case .fileData(let val): try container.encode(val, forKey: .fileData)
|
|
case .executableCode(let val): try container.encode(val, forKey: .executableCode)
|
|
case .codeExecutionResult(let val): try container.encode(val, forKey: .codeExecutionResult)
|
|
case .unrecognized(let unrecognizedFields):
|
|
var dynamicContainer = encoder.container(keyedBy: DynamicCodingKey.self)
|
|
for (key, value) in unrecognizedFields {
|
|
if let codingKey = DynamicCodingKey(stringValue: key) {
|
|
try dynamicContainer.encode(value, forKey: codingKey)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|