forked from intitni/CopilotForXcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDynamicContextController.swift
More file actions
96 lines (88 loc) · 2.9 KB
/
DynamicContextController.swift
File metadata and controls
96 lines (88 loc) · 2.9 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
import ChatContextCollector
import Foundation
import OpenAIService
import Parsing
import Preferences
import XcodeInspector
final class DynamicContextController {
let contextCollectors: [ChatContextCollector]
let memory: AutoManagedChatGPTMemory
let functionProvider: ChatFunctionProvider
let configuration: ChatGPTConfiguration
var defaultScopes = [] as Set<String>
convenience init(
memory: AutoManagedChatGPTMemory,
functionProvider: ChatFunctionProvider,
configuration: ChatGPTConfiguration,
contextCollectors: ChatContextCollector...
) {
self.init(
memory: memory,
functionProvider: functionProvider,
configuration: configuration,
contextCollectors: contextCollectors
)
}
init(
memory: AutoManagedChatGPTMemory,
functionProvider: ChatFunctionProvider,
configuration: ChatGPTConfiguration,
contextCollectors: [ChatContextCollector]
) {
self.memory = memory
self.functionProvider = functionProvider
self.configuration = configuration
self.contextCollectors = contextCollectors
}
func updatePromptToMatchContent(systemPrompt: String, content: String) async throws {
var content = content
var scopes = Self.parseScopes(&content)
scopes.formUnion(defaultScopes)
functionProvider.removeAll()
let language = UserDefaults.shared.value(for: \.chatGPTLanguage)
let oldMessages = await memory.history
let contexts = contextCollectors.compactMap {
$0.generateContext(
history: oldMessages,
scopes: scopes,
content: content,
configuration: configuration
)
}
let contextualSystemPrompt = """
\(language.isEmpty ? "" : "You must always reply in \(language)")
\(systemPrompt)
\(contexts.map(\.systemPrompt).filter { !$0.isEmpty }.joined(separator: "\n\n"))
"""
await memory.mutateSystemPrompt(contextualSystemPrompt)
functionProvider.append(functions: contexts.flatMap(\.functions))
}
}
extension DynamicContextController {
static func parseScopes(_ prompt: inout String) -> Set<String> {
guard !prompt.isEmpty else { return [] }
do {
let parser = Parse {
"@"
Many {
Prefix { $0.isLetter }
} separator: {
"+"
} terminator: {
" "
}
Skip {
Many {
" "
}
}
Rest()
}
let (scopes, rest) = try parser.parse(prompt)
prompt = String(rest)
return Set(scopes.map(String.init))
} catch {
return []
}
}
}