-
-
Notifications
You must be signed in to change notification settings - Fork 426
Expand file tree
/
Copy pathChatGPTFunction.swift
More file actions
130 lines (111 loc) · 4.34 KB
/
ChatGPTFunction.swift
File metadata and controls
130 lines (111 loc) · 4.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import Foundation
public enum ChatGPTFunctionCallPhase {
case detected
case processing(argumentsJsonString: String)
case ended(argumentsJsonString: String, result: ChatGPTFunctionResult)
case error(argumentsJsonString: String, result: Error)
}
public enum ChatGPTFunctionResultUserReadableContent: Sendable {
public struct ListItem: Sendable {
public enum Detail: Sendable {
case link(URL)
case text(String)
}
public var title: String
public var description: String?
public var detail: Detail?
public init(title: String, description: String? = nil, detail: Detail? = nil) {
self.title = title
self.description = description
self.detail = detail
}
}
case text(String)
case list([ListItem])
case searchResult([ListItem], queries: [String])
}
public protocol ChatGPTFunctionResult {
var botReadableContent: String { get }
var userReadableContent: ChatGPTFunctionResultUserReadableContent { get }
}
extension String: ChatGPTFunctionResult {
public var botReadableContent: String { self }
public var userReadableContent: ChatGPTFunctionResultUserReadableContent {
.text(self)
}
}
public struct NoChatGPTFunctionArguments: Decodable {}
public protocol ChatGPTFunction {
typealias NoArguments = NoChatGPTFunctionArguments
associatedtype Arguments: Decodable
associatedtype Result: ChatGPTFunctionResult
typealias ReportProgress = @Sendable (String) async -> Void
/// The name of this function.
/// May contain a-z, A-Z, 0-9, and underscores, with a maximum length of 64 characters.
var name: String { get }
/// A short description telling the bot when it should use this function.
var description: String { get }
/// The arguments schema that the function take in [JSON schema](https://json-schema.org).
var argumentSchema: JSONSchemaValue { get }
/// Prepare to call the function
func prepare(reportProgress: @escaping ReportProgress) async
/// Call the function with the given arguments.
func call(arguments: Arguments, reportProgress: @escaping ReportProgress) async throws
-> Result
}
public extension ChatGPTFunction {
/// Call the function with the given arguments in JSON.
func call(
argumentsJsonString: String,
reportProgress: @escaping ReportProgress
) async throws -> Result {
let arguments = try await {
do {
return try JSONDecoder()
.decode(Arguments.self, from: argumentsJsonString.data(using: .utf8) ?? Data())
} catch {
await reportProgress(
"Error: Failed to decode arguments. \(error.localizedDescription)"
)
throw error
}
}()
return try await call(arguments: arguments, reportProgress: reportProgress)
}
}
public extension ChatGPTFunction where Arguments == NoArguments {
var argumentSchema: JSONSchemaValue {
[.type: "object", .properties: [:]]
}
}
/// This kind of function is only used to get a structured output from the bot.
public protocol ChatGPTArgumentsCollectingFunction: ChatGPTFunction where Result == String {}
public extension ChatGPTArgumentsCollectingFunction {
func prepare(reportProgress: @escaping ReportProgress = { _ in }) async {
assertionFailure("This function is only used to get a structured output from the bot.")
}
func call(
arguments: Arguments,
reportProgress: @escaping ReportProgress = { _ in }
) async throws -> Result {
assertionFailure("This function is only used to get a structured output from the bot.")
return ""
}
func call(
argumentsJsonString: String,
reportProgress: @escaping ReportProgress
) async throws -> Result {
assertionFailure("This function is only used to get a structured output from the bot.")
return ""
}
}
public struct ChatGPTFunctionSchema: Codable, Equatable, Sendable {
public var name: String
public var description: String
public var parameters: JSONSchemaValue
public init(name: String, description: String, parameters: JSONSchemaValue) {
self.name = name
self.description = description
self.parameters = parameters
}
}