-
-
Notifications
You must be signed in to change notification settings - Fork 427
Expand file tree
/
Copy pathChatContextCollector.swift
More file actions
98 lines (87 loc) · 2.5 KB
/
ChatContextCollector.swift
File metadata and controls
98 lines (87 loc) · 2.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
import ChatBasic
import Foundation
import OpenAIService
import Parsing
public struct ChatContext {
public enum Scope: String, Equatable, CaseIterable, Codable, Sendable {
case file
case code
case sense
case project
case web
}
public struct RetrievedContent: Sendable {
public var document: ChatMessage.Reference
public var priority: Int
public init(document: ChatMessage.Reference, priority: Int) {
self.document = document
self.priority = priority
}
}
public var systemPrompt: String
public var retrievedContent: [RetrievedContent]
public var functions: [any ChatGPTFunction]
public init(
systemPrompt: String,
retrievedContent: [RetrievedContent],
functions: [any ChatGPTFunction]
) {
self.systemPrompt = systemPrompt
self.retrievedContent = retrievedContent
self.functions = functions
}
public static var empty: Self {
.init(systemPrompt: "", retrievedContent: [], functions: [])
}
}
public extension ChatContext.Scope {
init?(text: String) {
for scope in Self.allCases {
if scope.rawValue.hasPrefix(text.lowercased()) {
self = scope
return
}
}
return nil
}
}
public protocol ChatContextCollector {
func generateContext(
history: [ChatMessage],
scopes: Set<ChatContext.Scope>,
content: String,
configuration: ChatGPTConfiguration
) async -> ChatContext
}
public struct MessageScopeParser {
public init() {}
public func callAsFunction(_ content: inout String) -> Set<ChatContext.Scope> {
return parseScopes(&content)
}
func parseScopes(_ prompt: inout String) -> Set<ChatContext.Scope> {
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).compactMap(ChatContext.Scope.init(text:)))
} catch {
return []
}
}
}