-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathConversationServiceProvider.swift
More file actions
239 lines (207 loc) · 7.89 KB
/
ConversationServiceProvider.swift
File metadata and controls
239 lines (207 loc) · 7.89 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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
import CopilotForXcodeKit
import Foundation
import CodableWrappers
import LanguageServerProtocol
public protocol ConversationServiceType {
func createConversation(_ request: ConversationRequest, workspace: WorkspaceInfo) async throws
func createTurn(with conversationId: String, request: ConversationRequest, workspace: WorkspaceInfo) async throws
func cancelProgress(_ workDoneToken: String, workspace: WorkspaceInfo) async throws
func rateConversation(turnId: String, rating: ConversationRating, workspace: WorkspaceInfo) async throws
func copyCode(request: CopyCodeRequest, workspace: WorkspaceInfo) async throws
func templates(workspace: WorkspaceInfo) async throws -> [ChatTemplate]?
func models(workspace: WorkspaceInfo) async throws -> [CopilotModel]?
func notifyDidChangeWatchedFiles(_ event: DidChangeWatchedFilesEvent, workspace: WorkspaceInfo) async throws
func agents(workspace: WorkspaceInfo) async throws -> [ChatAgent]?
}
public protocol ConversationServiceProvider {
func createConversation(_ request: ConversationRequest, workspaceURL: URL?) async throws
func createTurn(with conversationId: String, request: ConversationRequest, workspaceURL: URL?) async throws
func stopReceivingMessage(_ workDoneToken: String, workspaceURL: URL?) async throws
func rateConversation(turnId: String, rating: ConversationRating, workspaceURL: URL?) async throws
func copyCode(_ request: CopyCodeRequest, workspaceURL: URL?) async throws
func templates() async throws -> [ChatTemplate]?
func models() async throws -> [CopilotModel]?
func notifyDidChangeWatchedFiles(_ event: DidChangeWatchedFilesEvent, workspace: WorkspaceInfo) async throws
func agents() async throws -> [ChatAgent]?
}
public struct FileReference: Hashable, Codable, Equatable {
public let url: URL
public let relativePath: String?
public let fileName: String?
public var isCurrentEditor: Bool = false
public init(url: URL, relativePath: String?, fileName: String?, isCurrentEditor: Bool = false) {
self.url = url
self.relativePath = relativePath
self.fileName = fileName
self.isCurrentEditor = isCurrentEditor
}
public init(url: URL, isCurrentEditor: Bool = false) {
self.url = url
self.relativePath = nil
self.fileName = nil
self.isCurrentEditor = isCurrentEditor
}
public func hash(into hasher: inout Hasher) {
hasher.combine(url)
hasher.combine(isCurrentEditor)
}
public static func == (lhs: FileReference, rhs: FileReference) -> Bool {
return lhs.url == rhs.url && lhs.isCurrentEditor == rhs.isCurrentEditor
}
}
extension FileReference {
public func getPathRelativeToHome() -> String {
let filePath = url.path
guard !filePath.isEmpty else { return "" }
let homeDirectory = FileManager.default.homeDirectoryForCurrentUser.path
if !homeDirectory.isEmpty {
return filePath.replacingOccurrences(of: homeDirectory, with: "~")
}
return filePath
}
}
public struct TurnSchema: Codable {
public var request: String
public var response: String?
public var agentSlug: String?
public var turnId: String?
public init(request: String, response: String? = nil, agentSlug: String? = nil, turnId: String? = nil) {
self.request = request
self.response = response
self.agentSlug = agentSlug
self.turnId = turnId
}
}
public struct ConversationRequest {
public var workDoneToken: String
public var content: String
public var workspaceFolder: String
public var activeDoc: Doc?
public var skills: [String]
public var ignoredSkills: [String]?
public var references: [FileReference]?
public var model: String?
public var turns: [TurnSchema]
public var agentMode: Bool = false
public var userLanguage: String? = nil
public var turnId: String? = nil
public init(
workDoneToken: String,
content: String,
workspaceFolder: String,
activeDoc: Doc? = nil,
skills: [String],
ignoredSkills: [String]? = nil,
references: [FileReference]? = nil,
model: String? = nil,
turns: [TurnSchema] = [],
agentMode: Bool = false,
userLanguage: String?,
turnId: String? = nil
) {
self.workDoneToken = workDoneToken
self.content = content
self.workspaceFolder = workspaceFolder
self.activeDoc = activeDoc
self.skills = skills
self.ignoredSkills = ignoredSkills
self.references = references
self.model = model
self.turns = turns
self.agentMode = agentMode
self.userLanguage = userLanguage
self.turnId = turnId
}
}
public struct CopyCodeRequest {
public var turnId: String
public var codeBlockIndex: Int
public var copyType: CopyKind
public var copiedCharacters: Int
public var totalCharacters: Int
public var copiedText: String
init(turnId: String, codeBlockIndex: Int, copyType: CopyKind, copiedCharacters: Int, totalCharacters: Int, copiedText: String) {
self.turnId = turnId
self.codeBlockIndex = codeBlockIndex
self.copyType = copyType
self.copiedCharacters = copiedCharacters
self.totalCharacters = totalCharacters
self.copiedText = copiedText
}
}
public enum ConversationRating: Int, Codable {
case unrated = 0
case helpful = 1
case unhelpful = -1
}
public enum CopyKind: Int, Codable {
case keyboard = 1
case toolbar = 2
}
public struct ConversationFollowUp: Codable, Equatable {
public var message: String
public var id: String
public var type: String
public init(message: String, id: String, type: String) {
self.message = message
self.id = id
self.type = type
}
}
public struct ConversationProgressStep: Codable, Equatable, Identifiable {
public enum StepStatus: String, Codable {
case running, completed, failed, cancelled
}
public struct StepError: Codable, Equatable {
public let message: String
}
public let id: String
public let title: String
public let description: String?
public var status: StepStatus
public let error: StepError?
public init(id: String, title: String, description: String?, status: StepStatus, error: StepError?) {
self.id = id
self.title = title
self.description = description
self.status = status
self.error = error
}
}
public struct DidChangeWatchedFilesEvent: Codable {
public var workspaceUri: String
public var changes: [FileEvent]
public init(workspaceUri: String, changes: [FileEvent]) {
self.workspaceUri = workspaceUri
self.changes = changes
}
}
public struct AgentRound: Codable, Equatable {
public let roundId: Int
public var reply: String
public var toolCalls: [AgentToolCall]?
public init(roundId: Int, reply: String, toolCalls: [AgentToolCall]? = []) {
self.roundId = roundId
self.reply = reply
self.toolCalls = toolCalls
}
}
public struct AgentToolCall: Codable, Equatable, Identifiable {
public let id: String
public let name: String
public var progressMessage: String?
public var status: ToolCallStatus
public var error: String?
public var invokeParams: InvokeClientToolParams?
public enum ToolCallStatus: String, Codable {
case waitForConfirmation, accepted, running, completed, error, cancelled
}
public init(id: String, name: String, progressMessage: String? = nil, status: ToolCallStatus, error: String? = nil, invokeParams: InvokeClientToolParams? = nil) {
self.id = id
self.name = name
self.progressMessage = progressMessage
self.status = status
self.error = error
self.invokeParams = invokeParams
}
}