Skip to content

Commit 86477f0

Browse files
committed
Merge branch 'feature/modification-customization-update' into develop
2 parents 308df4a + 658e77e commit 86477f0

18 files changed

Lines changed: 340 additions & 238 deletions

Core/Sources/PromptToCodeService/OpenAIPromptToCodeService.swift

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
import Foundation
2+
import ModificationBasic
23
import OpenAIService
34
import Preferences
45
import SuggestionBasic
56
import XcodeInspector
67

7-
public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
8-
var service: (any LegacyChatGPTServiceType)?
8+
public final class SimpleModificationAgent: ModificationAgent {
9+
public func send(_ request: Request) -> AsyncThrowingStream<Response, any Error> {
10+
AsyncThrowingStream { continuation in
11+
let task = Task {
12+
do {
13+
let stream = try await modifyCode(
14+
code: request.code,
15+
requirement: request.requirement,
16+
source: .init(
17+
language: request.source.language,
18+
documentURL: request.source.documentURL,
19+
projectRootURL: request.source.projectRootURL,
20+
content: request.source.content,
21+
lines: request.source.lines,
22+
range: request.range
23+
),
24+
isDetached: request.isDetached,
25+
extraSystemPrompt: request.extraSystemPrompt,
26+
generateDescriptionRequirement: false
27+
)
928

10-
public init() {}
29+
for try await (code, description) in stream {
30+
continuation.yield(.code(code))
31+
}
32+
33+
continuation.finish()
34+
} catch {
35+
continuation.finish(throwing: error)
36+
}
37+
}
1138

12-
public func stopResponding() {
13-
Task { await service?.stopReceivingMessage() }
39+
continuation.onTermination = { _ in
40+
task.cancel()
41+
}
42+
}
1443
}
1544

16-
public func modifyCode(
45+
public init() {}
46+
47+
func modifyCode(
1748
code: String,
1849
requirement: String,
1950
source: PromptToCodeSource,
@@ -37,7 +68,7 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
3768
content: source.content,
3869
lines: source.lines,
3970
selections: [source.range],
40-
cursorPosition: .outOfScope,
71+
cursorPosition: .outOfScope,
4172
cursorOffset: -1,
4273
lineAnnotations: []
4374
),
@@ -176,24 +207,32 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
176207
let configuration =
177208
UserPreferenceChatGPTConfiguration(chatModelKey: \.promptToCodeChatModelId)
178209
.overriding(.init(temperature: 0))
210+
179211
let memory = AutoManagedChatGPTMemory(
180212
systemPrompt: systemPrompt,
181213
configuration: configuration,
182-
functionProvider: NoChatGPTFunctionProvider(),
214+
functionProvider: NoChatGPTFunctionProvider(),
183215
maxNumberOfMessages: .max
184216
)
185-
let chatGPTService = LegacyChatGPTService(
186-
memory: memory,
187-
configuration: configuration
217+
let chatGPTService = ChatGPTService(
218+
configuration: configuration,
219+
functionProvider: NoChatGPTFunctionProvider()
188220
)
189-
service = chatGPTService
221+
190222
if let firstMessage {
191223
await memory.mutateHistory { history in
192224
history.append(.init(role: .user, content: firstMessage))
193225
history.append(.init(role: .assistant, content: secondMessage))
226+
history.append(.init(role: .user, content: requirement))
194227
}
195228
}
196-
let stream = try await chatGPTService.send(content: requirement)
229+
let stream = chatGPTService.send(memory).compactMap { response in
230+
switch response {
231+
case let .partialText(token): return token
232+
default: return nil
233+
}
234+
}.eraseToThrowingStream()
235+
197236
return .init { continuation in
198237
Task {
199238
var content = ""
@@ -219,7 +258,7 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
219258

220259
// MAKR: - Internal
221260

222-
extension OpenAIPromptToCodeService {
261+
extension SimpleModificationAgent {
223262
func extractCodeAndDescription(from content: String)
224263
-> (code: String, description: String)
225264
{

Core/Sources/PromptToCodeService/PreviewPromptToCodeService.swift

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,47 @@
11
import Foundation
2+
import ModificationBasic
23
import SuggestionBasic
34

4-
public final class PreviewPromptToCodeService: PromptToCodeServiceType {
5+
public final class PreviewModificationAgent: ModificationAgent {
6+
public func send(_ request: Request) -> AsyncThrowingStream<Response, any Error> {
7+
AsyncThrowingStream { continuation in
8+
let task = Task {
9+
do {
10+
let stream = try await modifyCode(
11+
code: request.code,
12+
requirement: request.requirement,
13+
source: .init(
14+
language: request.source.language,
15+
documentURL: request.source.documentURL,
16+
projectRootURL: request.source.projectRootURL,
17+
content: request.source.content,
18+
lines: request.source.lines,
19+
range: request.range
20+
),
21+
isDetached: request.isDetached,
22+
extraSystemPrompt: request.extraSystemPrompt,
23+
generateDescriptionRequirement: false
24+
)
25+
26+
for try await (code, description) in stream {
27+
continuation.yield(.code(code))
28+
}
29+
30+
continuation.finish()
31+
} catch {
32+
continuation.finish(throwing: error)
33+
}
34+
}
35+
36+
continuation.onTermination = { _ in
37+
task.cancel()
38+
}
39+
}
40+
}
41+
542
public init() {}
643

7-
public func modifyCode(
44+
func modifyCode(
845
code: String,
946
requirement: String,
1047
source: PromptToCodeSource,

Core/Sources/PromptToCodeService/PromptToCodeServiceType.swift

Lines changed: 0 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,6 @@ import Dependencies
22
import Foundation
33
import SuggestionBasic
44

5-
public protocol PromptToCodeServiceType {
6-
func modifyCode(
7-
code: String,
8-
requirement: String,
9-
source: PromptToCodeSource,
10-
isDetached: Bool,
11-
extraSystemPrompt: String?,
12-
generateDescriptionRequirement: Bool?
13-
) async throws -> AsyncThrowingStream<(code: String, description: String), Error>
14-
15-
func stopResponding()
16-
}
17-
185
public struct PromptToCodeSource {
196
public var language: CodeLanguage
207
public var documentURL: URL
@@ -39,78 +26,3 @@ public struct PromptToCodeSource {
3926
self.range = range
4027
}
4128
}
42-
43-
public struct PromptToCodeServiceDependencyKey: DependencyKey {
44-
public static let liveValue: PromptToCodeServiceType = PreviewPromptToCodeService()
45-
public static let previewValue: PromptToCodeServiceType = PreviewPromptToCodeService()
46-
}
47-
48-
public extension DependencyValues {
49-
var promptToCodeService: PromptToCodeServiceType {
50-
get { self[PromptToCodeServiceDependencyKey.self] }
51-
set { self[PromptToCodeServiceDependencyKey.self] = newValue }
52-
}
53-
54-
var promptToCodeServiceFactory: () -> PromptToCodeServiceType {
55-
get { self[PromptToCodeServiceFactoryDependencyKey.self] }
56-
set { self[PromptToCodeServiceFactoryDependencyKey.self] = newValue }
57-
}
58-
}
59-
60-
#if canImport(ContextAwarePromptToCodeService)
61-
62-
import ContextAwarePromptToCodeService
63-
64-
extension ContextAwarePromptToCodeService: PromptToCodeServiceType {
65-
public func stopResponding() {}
66-
67-
public func modifyCode(
68-
code: String,
69-
requirement: String,
70-
source: PromptToCodeSource,
71-
isDetached: Bool,
72-
extraSystemPrompt: String?,
73-
generateDescriptionRequirement: Bool?
74-
) async throws -> AsyncThrowingStream<(code: String, description: String), Error> {
75-
try await modifyCode(
76-
code: code,
77-
requirement: requirement,
78-
source: ContextAwarePromptToCodeService.Source(
79-
language: source.language,
80-
documentURL: source.documentURL,
81-
projectRootURL: source.projectRootURL,
82-
content: source.content,
83-
lines: source.lines,
84-
range: source.range
85-
),
86-
isDetached: isDetached,
87-
extraSystemPrompt: extraSystemPrompt,
88-
generateDescriptionRequirement: generateDescriptionRequirement
89-
)
90-
}
91-
}
92-
93-
public struct PromptToCodeServiceFactoryDependencyKey: DependencyKey {
94-
public static let liveValue: () -> PromptToCodeServiceType = {
95-
ContextAwarePromptToCodeService()
96-
}
97-
98-
public static let previewValue: () -> PromptToCodeServiceType = {
99-
PreviewPromptToCodeService()
100-
}
101-
}
102-
103-
#else
104-
105-
public struct PromptToCodeServiceFactoryDependencyKey: DependencyKey {
106-
public static let liveValue: () -> PromptToCodeServiceType = {
107-
OpenAIPromptToCodeService()
108-
}
109-
110-
public static let previewValue: () -> PromptToCodeServiceType = {
111-
PreviewPromptToCodeService()
112-
}
113-
}
114-
115-
#endif
116-

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ public final class GraphicalUserInterfaceController {
337337
self?.store.send(.openChatPanel(forceDetach: false, activateThisApp: true))
338338
}
339339
}
340+
suggestionDependency.onOpenModificationButtonClicked = {
341+
Task {
342+
guard let content = await PseudoCommandHandler().getEditorContent(sourceEditor: nil)
343+
else { return }
344+
_ = try await WindowBaseCommandHandler().promptToCode(editor: content)
345+
}
346+
}
340347
suggestionDependency.onCustomCommandClicked = { command in
341348
Task {
342349
let commandHandler = PseudoCommandHandler()

Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -273,21 +273,13 @@ struct PseudoCommandHandler: CommandHandler {
273273
}
274274

275275
func presentModification(state: Shared<ModificationState>) async {
276-
do {
277-
@Dependency(\.workspacePool) var workspacePool
278-
let (_, filespace) = try await workspacePool
279-
.fetchOrCreateWorkspaceAndFilespace(fileURL: state.wrappedValue.source.documentURL)
280-
let store = await Service.shared.guiController.store
281-
await store.send(.promptToCodeGroup(.createPromptToCode(.init(
282-
promptToCodeState: state,
283-
indentSize: filespace.codeMetadata.indentSize ?? 4,
284-
usesTabsForIndentation: filespace.codeMetadata.usesTabsForIndentation ?? false,
285-
commandName: nil,
286-
isContinuous: false
287-
), sendImmediately: false)))
288-
} catch {
289-
toast.toast(content: error.localizedDescription, type: .error)
290-
}
276+
let store = await Service.shared.guiController.store
277+
await store.send(.promptToCodeGroup(.createPromptToCode(.init(
278+
promptToCodeState: state,
279+
instruction: nil,
280+
commandName: nil,
281+
isContinuous: false
282+
), sendImmediately: false)))
291283
}
292284

293285
func acceptSuggestion() async {

Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,10 @@ extension WindowBaseCommandHandler {
472472
lines: editor.lines
473473
),
474474
snippets: IdentifiedArray(uniqueElements: snippets),
475-
instruction: newPrompt ?? "",
476475
extraSystemPrompt: newExtraSystemPrompt ?? "",
477476
isAttachedToTarget: true
478477
)),
479-
indentSize: filespace.codeMetadata.indentSize ?? 4,
480-
usesTabsForIndentation: filespace.codeMetadata.usesTabsForIndentation ?? false,
478+
instruction: newPrompt,
481479
commandName: name,
482480
isContinuous: isContinuous
483481
))))

Core/Sources/SuggestionWidget/FeatureReducers/CircularWidget.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public struct CircularWidget {
2424
case widgetClicked
2525
case detachChatPanelToggleClicked
2626
case openChatButtonClicked
27+
case openModificationButtonClicked
2728
case runCustomCommandButtonClicked(CustomCommand)
2829
case markIsProcessing
2930
case endIsProcessing
@@ -45,6 +46,11 @@ public struct CircularWidget {
4546
suggestionWidgetControllerDependency.onOpenChatClicked()
4647
}
4748

49+
case .openModificationButtonClicked:
50+
return .run { _ in
51+
suggestionWidgetControllerDependency.onOpenModificationButtonClicked()
52+
}
53+
4854
case let .runCustomCommandButtonClicked(command):
4955
return .run { _ in
5056
suggestionWidgetControllerDependency.onCustomCommandClicked(command)

Core/Sources/SuggestionWidget/FeatureReducers/PromptToCodeGroup.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public struct PromptToCodeGroup {
4545
case activePromptToCode(PromptToCodePanel.Action)
4646
}
4747

48-
@Dependency(\.promptToCodeServiceFactory) var promptToCodeServiceFactory
4948
@Dependency(\.activatePreviousActiveXcode) var activatePreviousActiveXcode
5049

5150
public var body: some ReducerOf<Self> {
@@ -64,7 +63,9 @@ public struct PromptToCodeGroup {
6463
// insert at 0 so it has high priority then the other detached prompt to codes
6564
state.promptToCodes.insert(newPromptToCode, at: 0)
6665
return .run { send in
67-
if sendImmediately, !newPromptToCode.promptToCodeState.instruction.isEmpty {
66+
if sendImmediately,
67+
!newPromptToCode.contextInputController.instruction.string.isEmpty
68+
{
6869
await send(.promptToCode(newPromptToCode.id, .modifyCodeButtonTapped))
6970
}
7071
}.cancellable(
@@ -102,11 +103,9 @@ public struct PromptToCodeGroup {
102103
}
103104
.ifLet(\.activePromptToCode, action: \.activePromptToCode) {
104105
PromptToCodePanel()
105-
.dependency(\.promptToCodeService, promptToCodeServiceFactory())
106106
}
107107
.forEach(\.promptToCodes, action: /Action.promptToCode, element: {
108108
PromptToCodePanel()
109-
.dependency(\.promptToCodeService, promptToCodeServiceFactory())
110109
})
111110

112111
Reduce { state, action in

0 commit comments

Comments
 (0)