|
| 1 | +import ChatContextCollector |
1 | 2 | import Foundation |
2 | 3 | import OpenAIService |
3 | | -import SuggestionModel |
4 | | -import XcodeInspector |
5 | 4 | import Preferences |
| 5 | +import XcodeInspector |
6 | 6 |
|
7 | 7 | final class DynamicContextController { |
8 | 8 | let chatGPTService: any ChatGPTServiceType |
| 9 | + let contextCollectors: [ChatContextCollector] |
9 | 10 |
|
10 | | - init(chatGPTService: any ChatGPTServiceType) { |
| 11 | + init(chatGPTService: any ChatGPTServiceType, contextCollectors: ChatContextCollector...) { |
11 | 12 | self.chatGPTService = chatGPTService |
| 13 | + self.contextCollectors = contextCollectors |
12 | 14 | } |
13 | 15 |
|
14 | 16 | func updatePromptToMatchContent(systemPrompt: String) async throws { |
15 | 17 | let language = UserDefaults.shared.value(for: \.chatGPTLanguage) |
16 | | - let content = getEditorInformation() |
17 | | - let relativePath = content.documentURL.path |
18 | | - .replacingOccurrences(of: content.projectURL.path, with: "") |
19 | | - let selectionRange = content.editorContent?.selections.first ?? .outOfScope |
| 18 | + let oldMessages = (await chatGPTService.history).map(\.content) |
20 | 19 | let contextualSystemPrompt = """ |
21 | 20 | \(language.isEmpty ? "" : "You must always reply in \(language)") |
22 | 21 | \(systemPrompt) |
23 | 22 |
|
24 | | - Active Document Context:### |
25 | | - Document Relative Path: \(relativePath) |
26 | | - Selection Range Start: \ |
27 | | - Line \(selectionRange.start.line) \ |
28 | | - Character \(selectionRange.start.character) |
29 | | - Selection Range End: \ |
30 | | - Line \(selectionRange.end.line) \ |
31 | | - Character \(selectionRange.end.character) |
32 | | - Cursor Position: \ |
33 | | - Line \(selectionRange.end.line) \ |
34 | | - Character \(selectionRange.end.character) |
35 | | - Selected Code (start from line \(selectionRange.end.line)):```\(content.language.rawValue) |
36 | | - \(content.selectedContent) |
37 | | - ``` |
38 | | -
|
39 | | - Line Annotations: |
40 | | - \(content.editorContent?.lineAnnotations.map { "- \($0)" }.joined(separator: "\n") ?? "N/A") |
41 | | - ### |
| 23 | + \( |
| 24 | + contextCollectors |
| 25 | + .map { $0.generateSystemPrompt(oldMessages: oldMessages) } |
| 26 | + .joined(separator: "\n") |
| 27 | + ) |
42 | 28 | """ |
43 | 29 | await chatGPTService.mutateSystemPrompt(contextualSystemPrompt) |
44 | 30 | } |
45 | 31 | } |
46 | 32 |
|
47 | | -extension DynamicContextController { |
48 | | - struct Information { |
49 | | - let editorContent: SourceEditor.Content? |
50 | | - let selectedContent: String |
51 | | - let documentURL: URL |
52 | | - let projectURL: URL |
53 | | - let language: CodeLanguage |
54 | | - } |
55 | | - |
56 | | - func getEditorInformation() -> Information { |
57 | | - let editorContent = XcodeInspector.shared.focusedEditor?.content |
58 | | - let documentURL = XcodeInspector.shared.activeDocumentURL |
59 | | - let projectURL = XcodeInspector.shared.activeProjectURL |
60 | | - let language = languageIdentifierFromFileURL(documentURL) |
61 | | - |
62 | | - if let editorContent, let range = editorContent.selections.first { |
63 | | - let startIndex = min( |
64 | | - max(0, range.start.line), |
65 | | - editorContent.lines.endIndex - 1 |
66 | | - ) |
67 | | - let endIndex = min( |
68 | | - max(startIndex, range.end.line), |
69 | | - editorContent.lines.endIndex - 1 |
70 | | - ) |
71 | | - let selectedContent = editorContent.lines[startIndex...endIndex] |
72 | | - return .init( |
73 | | - editorContent: editorContent, |
74 | | - selectedContent: selectedContent.joined(), |
75 | | - documentURL: documentURL, |
76 | | - projectURL: projectURL, |
77 | | - language: language |
78 | | - ) |
79 | | - } |
80 | | - |
81 | | - return .init( |
82 | | - editorContent: editorContent, |
83 | | - selectedContent: "", |
84 | | - documentURL: documentURL, |
85 | | - projectURL: projectURL, |
86 | | - language: language |
87 | | - ) |
88 | | - } |
89 | | -} |
90 | | - |
0 commit comments