Skip to content

Commit

Permalink
feat: add tool_calls to message
Browse files Browse the repository at this point in the history
Signed-off-by: rawnly <[email protected]>
  • Loading branch information
rawnly committed Nov 19, 2023
1 parent 378d985 commit 098aeb7
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 2 deletions.
41 changes: 41 additions & 0 deletions Sources/OpenAI/Public/Models/Chat/ChatTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,44 @@ extension ChatTool {
}
}

public struct ToolCall: Codable, Equatable {
public let index: Int
public let id: String
public let type: ChatTool.ToolType
public let value: ToolCallValue

public enum ToolCallValue: Codable, Equatable {
case function(Function)

public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()

switch self {
case .function(let function):
try container.encode(function)
break
}
}


public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()

if let function = try? container.decode(Function.self) {
self = .function(function)
} else {
throw DecodingError.dataCorrupted(
DecodingError.Context(
codingPath: decoder.codingPath,
debugDescription: "Invalid data encountered when decoding StringOrCodable<T>"
)
)
}
}
}

public struct Function : Codable, Equatable {
public let name: String
public let arguments: String
}
}
51 changes: 49 additions & 2 deletions Sources/OpenAI/Public/Models/Chat/Message.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ public struct Message: Codable, Equatable {

/// The name of the author of this message. `name` is required if role is `function`, and it should be the name of the function whose response is in the `content`. May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.
public let name: String?

@available(*, deprecated, message: "use toolCalls instead")
public let functionCall: ChatFunctionCall?

public let toolCalls: [ToolCall]?

public enum Role: String, Codable, Equatable {
case system
case assistant
Expand All @@ -30,9 +34,34 @@ public struct Message: Codable, Equatable {
case content
case name
case functionCall = "function_call"
case toolCalls = "tool_calls"
}

public init(role: Role, content codable: StringOrChatContent? = nil, name: String? = nil, functionCall: ChatFunctionCall? = nil) {
public init(
role: Role,
content codable: StringOrChatContent? = nil,
name: String? = nil,
toolCalls: [ToolCall]? = nil
) {
let stringOrCodable: StringOrCodable<[ChatContent]>?

if let string = codable as? String {
stringOrCodable = .string(string)
} else if let arr = codable as? [ChatContent] {
stringOrCodable = .object(arr)
} else {
stringOrCodable = nil
}

self.init(role: role, content: stringOrCodable, name: name, toolCalls: toolCalls)
}

public init(
role: Role,
content codable: StringOrChatContent? = nil,
name: String? = nil,
functionCall: ChatFunctionCall? = nil
) {
let stringOrCodable: StringOrCodable<[ChatContent]>?

if let string = codable as? String {
Expand All @@ -51,6 +80,20 @@ public struct Message: Codable, Equatable {
self.content = content
self.name = name
self.functionCall = functionCall
self.toolCalls = nil
}

public init(
role: Role,
content: StringOrCodable<[ChatContent]>? = nil,
name: String? = nil,
toolCalls: [ToolCall]? = nil
) {
self.role = role
self.content = content
self.name = name
self.toolCalls = toolCalls
self.functionCall = nil
}

public func encode(to encoder: Encoder) throws {
Expand All @@ -64,10 +107,14 @@ public struct Message: Codable, Equatable {
if let functionCall = functionCall {
try container.encode(functionCall, forKey: .functionCall)
}

if let toolCalls = toolCalls {
try container.encode(toolCalls, forKey: .toolCalls)
}

// Should add 'nil' to 'content' property for function calling response
// See https://openai.com/blog/function-calling-and-other-api-updates
if content != nil || (role == .assistant && functionCall != nil) {
if content != nil || (role == .assistant && toolCalls != nil && functionCall != nil) {
try container.encode(content, forKey: .content)
}
}
Expand Down

0 comments on commit 098aeb7

Please sign in to comment.