forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathChatService.swift
More file actions
127 lines (109 loc) · 4.5 KB
/
ChatService.swift
File metadata and controls
127 lines (109 loc) · 4.5 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
import ChatContextCollector
import ChatPlugin
import Combine
import Foundation
import OpenAIService
public final class ChatService: ObservableObject {
public let memory: AutoManagedChatGPTMemory
public let configuration: OverridingChatGPTConfiguration<UserPreferenceChatGPTConfiguration>
public let chatGPTService: any ChatGPTServiceType
public var allPluginCommands: [String] { allPlugins.map { $0.command } }
@Published public internal(set) var isReceivingMessage = false
@Published public internal(set) var systemPrompt = UserDefaults.shared
.value(for: \.defaultChatSystemPrompt)
@Published public internal(set) var extraSystemPrompt = ""
let pluginController: ChatPluginController
let contextController: DynamicContextController
var cancellable = Set<AnyCancellable>()
init<T: ChatGPTServiceType>(
memory: AutoManagedChatGPTMemory,
configuration: OverridingChatGPTConfiguration<UserPreferenceChatGPTConfiguration>,
chatGPTService: T
) {
self.memory = memory
self.configuration = configuration
self.chatGPTService = chatGPTService
pluginController = ChatPluginController(chatGPTService: chatGPTService, plugins: allPlugins)
contextController = DynamicContextController(
memory: memory,
contextCollectors: ActiveDocumentChatContextCollector()
)
pluginController.chatService = self
}
public init() {
configuration = UserPreferenceChatGPTConfiguration().overriding()
memory = AutoManagedChatGPTMemory(systemPrompt: "", configuration: configuration)
chatGPTService = ChatGPTService(memory: memory, configuration: configuration)
pluginController = ChatPluginController(chatGPTService: chatGPTService, plugins: allPlugins)
contextController = DynamicContextController(
memory: memory,
contextCollectors: ActiveDocumentChatContextCollector()
)
pluginController.chatService = self
memory.observeHistoryChange { [weak self] in
self?.objectWillChange.send()
}
}
public func send(content: String) async throws {
guard !isReceivingMessage else { throw CancellationError() }
let handledInPlugin = try await pluginController.handleContent(content)
if handledInPlugin { return }
try await contextController.updatePromptToMatchContent(systemPrompt: """
\(systemPrompt)
\(extraSystemPrompt)
""", content: content)
let stream = try await chatGPTService.send(content: content, summary: nil)
isReceivingMessage = true
for try await _ in stream {}
isReceivingMessage = false
}
public func stopReceivingMessage() async {
await pluginController.stopResponding()
await chatGPTService.stopReceivingMessage()
isReceivingMessage = false
}
public func clearHistory() async {
await pluginController.cancel()
await memory.clearHistory()
await chatGPTService.stopReceivingMessage()
isReceivingMessage = false
}
public func resetPrompt() async {
systemPrompt = UserDefaults.shared.value(for: \.defaultChatSystemPrompt)
extraSystemPrompt = ""
}
public func deleteMessage(id: String) async {
await memory.removeMessage(id)
}
public func resendMessage(id: String) async throws {
if let message = (await memory.history).first(where: { $0.id == id }),
let content = message.content
{
try await send(content: content)
}
}
public func setMessageAsExtraPrompt(id: String) async {
if let message = (await memory.history).first(where: { $0.id == id }),
let content = message.content
{
mutateExtraSystemPrompt(content)
await mutateHistory { history in
history.append(.init(
role: .assistant,
content: "",
summary: "System prompt updated."
))
}
}
}
/// Setting it to `nil` to reset the system prompt
public func mutateSystemPrompt(_ newPrompt: String?) {
systemPrompt = newPrompt ?? UserDefaults.shared.value(for: \.defaultChatSystemPrompt)
}
public func mutateExtraSystemPrompt(_ newPrompt: String) {
extraSystemPrompt = newPrompt
}
public func mutateHistory(_ mutator: @escaping (inout [ChatMessage]) -> Void) async {
await memory.mutateHistory(mutator)
}
}