From 216cacb1c78fe8a574447825ead1d906c06099ee Mon Sep 17 00:00:00 2001 From: Pascal Freiburghaus Date: Wed, 1 Nov 2023 11:25:25 +0100 Subject: [PATCH] Functions are now working properly: - ChatThread.addFunctionResponse is now public so it can be used - Encoding of Arguments for assistant is now done, so it generates a String containing a JSON Dictionary. Otherwise it will not be accepted by openai - The content field is now encoded to content: null as it always needs to be present --- Sources/CleverBird/chat/ChatMessage.swift | 18 +++++++++--------- Sources/CleverBird/chat/ChatThread.swift | 2 +- Sources/CleverBird/chat/FunctionCall.swift | 6 ++++++ 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Sources/CleverBird/chat/ChatMessage.swift b/Sources/CleverBird/chat/ChatMessage.swift index 58e356e..d0602a3 100644 --- a/Sources/CleverBird/chat/ChatMessage.swift +++ b/Sources/CleverBird/chat/ChatMessage.swift @@ -37,13 +37,6 @@ public struct ChatMessage: Codable, Identifiable { id: String? = nil, functionCall: FunctionCall? = nil) throws { - // Validation: Name is required if role is function, and it should be the name of the function whose response is in the content. - if role == .function { - guard let functionCall = functionCall, let content = content, content.contains(functionCall.name) else { - throw CleverBirdError.invalidFunctionMessage - } - } - // Validation: Content is required for all messages except assistant messages with function calls. if content == nil && !(role == .assistant && functionCall != nil) { throw CleverBirdError.invalidMessageContent @@ -51,8 +44,14 @@ public struct ChatMessage: Codable, Identifiable { self.role = role self.content = content - self.functionCall = functionCall self.name = functionCall?.name + if role == .function { + // Attention: if the role is function I need to set the functionCall to nil, otherwise this will + // be encoded into the message which leads to an error. + self.functionCall = nil + } else { + self.functionCall = functionCall + } if let id = id { self.id = id @@ -79,7 +78,8 @@ public struct ChatMessage: Codable, Identifiable { public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(self.role, forKey: .role) - try container.encodeIfPresent(self.content, forKey: .content) + // The content field needs to be present even if it is nil, in this case encode it to Null + try container.encode(self.content, forKey: .content) try container.encodeIfPresent(self.functionCall, forKey: .functionCall) try container.encodeIfPresent(self.name, forKey: .name) } diff --git a/Sources/CleverBird/chat/ChatThread.swift b/Sources/CleverBird/chat/ChatThread.swift index 3bf8670..bf2355d 100644 --- a/Sources/CleverBird/chat/ChatThread.swift +++ b/Sources/CleverBird/chat/ChatThread.swift @@ -92,7 +92,7 @@ public class ChatThread { } @discardableResult - func addFunctionResponse(_ content: String, for functionCall: FunctionCall) -> ChatThread { + public func addFunctionResponse(_ content: String, for functionCall: FunctionCall) -> ChatThread { do { let responseMessage = try ChatMessage(role: .function, content: content, diff --git a/Sources/CleverBird/chat/FunctionCall.swift b/Sources/CleverBird/chat/FunctionCall.swift index 72f21d1..65b9694 100644 --- a/Sources/CleverBird/chat/FunctionCall.swift +++ b/Sources/CleverBird/chat/FunctionCall.swift @@ -59,4 +59,10 @@ public struct FunctionCall: Codable { self.name = functionName } + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(self.name, forKey: .name) + let argumentsAsString = try String(data: JSONEncoder().encode(self.arguments), encoding: .utf8) ?? "" + try container.encode(argumentsAsString, forKey: .arguments) + } }