Skip to content

Commit 44f5614

Browse files
committed
Merge branch 'release/0.22.0'
2 parents 54faa15 + 5cf302b commit 44f5614

File tree

76 files changed

+2237
-1290
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+2237
-1290
lines changed

Copilot for Xcode.xcworkspace/xcshareddata/swiftpm/Package.resolved

+12-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
{
22
"pins" : [
3+
{
4+
"identity" : "cgeventoverride",
5+
"kind" : "remoteSourceControl",
6+
"location" : "https://github.com/intitni/CGEventOverride",
7+
"state" : {
8+
"revision" : "40b29e804204c461253a52b77adea9c055184aad",
9+
"version" : "1.2.0"
10+
}
11+
},
312
{
413
"identity" : "combine-schedulers",
514
"kind" : "remoteSourceControl",
@@ -30,10 +39,10 @@
3039
{
3140
"identity" : "highlightr",
3241
"kind" : "remoteSourceControl",
33-
"location" : "https://github.com/raspu/Highlightr",
42+
"location" : "https://github.com/intitni/Highlightr",
3443
"state" : {
35-
"revision" : "93199b9e434f04bda956a613af8f571933f9f037",
36-
"version" : "2.1.2"
44+
"branch" : "bump-highlight-js-version",
45+
"revision" : "4ffbb1b0b721378263297cafea6f2838044eb1eb"
3746
}
3847
},
3948
{
@@ -90,15 +99,6 @@
9099
"version" : "2.4.2"
91100
}
92101
},
93-
{
94-
"identity" : "splash",
95-
"kind" : "remoteSourceControl",
96-
"location" : "https://github.com/JohnSundell/Splash",
97-
"state" : {
98-
"branch" : "master",
99-
"revision" : "2e3f17c2d09689c8bf175c4a84ff7f2ad3353301"
100-
}
101-
},
102102
{
103103
"identity" : "swift-argument-parser",
104104
"kind" : "remoteSourceControl",

Core/Package.swift

+16-13
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ let package = Package(
1515
"FileChangeChecker",
1616
"LaunchAgentManager",
1717
"UpdateChecker",
18-
"UserDefaultsObserver",
1918
]
2019
),
2120
.library(
@@ -72,14 +71,15 @@ let package = Package(
7271
"SuggestionService",
7372
"GitHubCopilotService",
7473
"XPCShared",
75-
"CGEventObserver",
7674
"DisplayLink",
7775
"SuggestionWidget",
7876
"ChatService",
7977
"PromptToCodeService",
8078
"ServiceUpdateMigration",
81-
"UserDefaultsObserver",
8279
"ChatGPTChatTab",
80+
.product(name: "CGEventObserver", package: "Tool"),
81+
.product(name: "Workspace", package: "Tool"),
82+
.product(name: "UserDefaultsObserver", package: "Tool"),
8383
.product(name: "AppMonitoring", package: "Tool"),
8484
.product(name: "Environment", package: "Tool"),
8585
.product(name: "SuggestionModel", package: "Tool"),
@@ -91,7 +91,7 @@ let package = Package(
9191
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
9292
.product(name: "Dependencies", package: "swift-dependencies"),
9393
].pro([
94-
"ProChatTabs",
94+
"ProService",
9595
])
9696
),
9797
.testTarget(
@@ -149,7 +149,7 @@ let package = Package(
149149
.target(name: "SuggestionService", dependencies: [
150150
"GitHubCopilotService",
151151
"CodeiumService",
152-
"UserDefaultsObserver",
152+
.product(name: "UserDefaultsObserver", package: "Tool"),
153153
]),
154154

155155
// MARK: - Prompt To Code
@@ -180,6 +180,7 @@ let package = Package(
180180
// context collectors
181181
"WebChatContextCollector",
182182
"ActiveDocumentChatContextCollector",
183+
"SystemInfoChatContextCollector",
183184

184185
.product(name: "AppMonitoring", package: "Tool"),
185186
.product(name: "Environment", package: "Tool"),
@@ -226,7 +227,7 @@ let package = Package(
226227
name: "SuggestionWidget",
227228
dependencies: [
228229
"ChatGPTChatTab",
229-
"UserDefaultsObserver",
230+
.product(name: "UserDefaultsObserver", package: "Tool"),
230231
.product(name: "SharedUIComponents", package: "Tool"),
231232
.product(name: "AppMonitoring", package: "Tool"),
232233
.product(name: "Environment", package: "Tool"),
@@ -241,12 +242,6 @@ let package = Package(
241242

242243
// MARK: - Helpers
243244

244-
.target(
245-
name: "CGEventObserver",
246-
dependencies: [
247-
.product(name: "Logger", package: "Tool"),
248-
]
249-
),
250245
.target(name: "FileChangeChecker"),
251246
.target(name: "LaunchAgentManager"),
252247
.target(name: "DisplayLink"),
@@ -264,7 +259,6 @@ let package = Package(
264259
.product(name: "Preferences", package: "Tool"),
265260
]
266261
),
267-
.target(name: "UserDefaultsObserver"),
268262
.target(
269263
name: "PlusFeatureFlag",
270264
dependencies: [
@@ -353,6 +347,15 @@ let package = Package(
353347
path: "Sources/ChatContextCollectors/WebChatContextCollector"
354348
),
355349

350+
.target(
351+
name: "SystemInfoChatContextCollector",
352+
dependencies: [
353+
"ChatContextCollector",
354+
.product(name: "OpenAIService", package: "Tool"),
355+
],
356+
path: "Sources/ChatContextCollectors/SystemInfoChatContextCollector"
357+
),
358+
356359
.target(
357360
name: "ActiveDocumentChatContextCollector",
358361
dependencies: [

Core/Sources/ChatContextCollectors/ActiveDocumentChatContextCollector/ActiveDocumentChatContextCollector.swift

+10-7
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,15 @@ public final class ActiveDocumentChatContextCollector: ChatContextCollector {
8989
let start = """
9090
## File and Code Scope
9191
92-
You can use the following context to answer user's questions about the editing document or code. The context shows only a part of the code in the editing document, and will change during the conversation, so it may not match our conversation.
92+
You can use the following context to answer my questions about the editing document or code. The context shows only a part of the code in the editing document, and will change during the conversation, so it may not match our conversation.
9393
94-
User Editing Document Context: ###
94+
\(
95+
context.focusedContext == nil
96+
? ""
97+
: "When you don't known what I am asking, I am probably referring to the code."
98+
)
99+
100+
Editing Document Context: ###
95101
"""
96102
let end = "###"
97103
let relativePath = "Document Relative Path: \(context.relativePath)"
@@ -110,10 +116,7 @@ public final class ActiveDocumentChatContextCollector: ChatContextCollector {
110116
let codeRange = "Focused Range [line, character]: \(focusedContext.codeRange)"
111117

112118
let code = """
113-
Focused Code (start from line \(
114-
focusedContext.codeRange.start
115-
.line
116-
)):
119+
Focused Code (start from line \(focusedContext.codeRange.start.line + 1)):
117120
```\(context.language.rawValue)
118121
\(focusedContext.code)
119122
```
@@ -282,7 +285,7 @@ struct ActiveDocumentContext {
282285
selectionRange = info.editorContent?.selections.first ?? .zero
283286
lineAnnotations = info.editorContent?.lineAnnotations ?? []
284287
imports = []
285-
288+
286289
if changed {
287290
moveToFocusedCode()
288291
}

Core/Sources/ChatContextCollectors/ActiveDocumentChatContextCollector/Functions/ExpandFocusRangeFunction.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ struct ExpandFocusRangeFunction: ChatGPTFunction {
1010
var range: CursorRange
1111

1212
var botReadableContent: String {
13-
"User Editing Document Context is updated to display code at \(range)."
13+
"Editing Document Context is updated to display code at \(range)."
1414
}
1515
}
1616

@@ -25,7 +25,7 @@ struct ExpandFocusRangeFunction: ChatGPTFunction {
2525
}
2626

2727
var description: String {
28-
"Call when User Editing Document Context provides too little context to answer a question."
28+
"Call when Editing Document Context provides too little context to answer a question."
2929
}
3030

3131
var argumentSchema: JSONSchemaValue { [

Core/Sources/ChatContextCollectors/ActiveDocumentChatContextCollector/Functions/MoveToCodeAroundLineFunction.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ struct MoveToCodeAroundLineFunction: ChatGPTFunction {
1212
var range: CursorRange
1313

1414
var botReadableContent: String {
15-
"User Editing Document Context is updated to display code at \(range)."
15+
"Editing Document Context is updated to display code at \(range)."
1616
}
1717
}
1818

Core/Sources/ChatContextCollectors/ActiveDocumentChatContextCollector/Functions/MoveToFocusedCodeFunction.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ struct MoveToFocusedCodeFunction: ChatGPTFunction {
1010
var range: CursorRange
1111

1212
var botReadableContent: String {
13-
"User Editing Document Context is updated to display code at \(range)."
13+
"Editing Document Context is updated to display code at \(range)."
1414
}
1515
}
1616

@@ -25,7 +25,7 @@ struct MoveToFocusedCodeFunction: ChatGPTFunction {
2525
}
2626

2727
var description: String {
28-
"Move user editing document context to the selected or focused code"
28+
"Move editing document context to the selected or focused code"
2929
}
3030

3131
var argumentSchema: JSONSchemaValue { [

Core/Sources/ChatContextCollectors/ActiveDocumentChatContextCollector/LegacyActiveDocumentChatContextCollector.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ public struct LegacyActiveDocumentChatContextCollector: ChatContextCollector {
6868

6969
return """
7070
Selected Code Not Available: '''
71-
User has disabled default scope. \
72-
You MUST not answer the user about the selected code because you don't have it.\
73-
Ask user to prepend message with `@selection` to enable selected code to be \
71+
I have disabled default scope. \
72+
You MUST not answer about the selected code because you don't have it.\
73+
Ask me to prepend message with `@selection` to enable selected code to be \
7474
visible by you.
7575
'''
7676
"""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import ChatContextCollector
2+
import Foundation
3+
import OpenAIService
4+
5+
public final class SystemInfoChatContextCollector: ChatContextCollector {
6+
static let dateFormatter: DateFormatter = {
7+
let formatter = DateFormatter()
8+
formatter.dateFormat = "EEEE, yyyy-MM-dd HH:mm:ssZ"
9+
return formatter
10+
}()
11+
12+
public init() {}
13+
14+
public func generateContext(
15+
history: [ChatMessage],
16+
scopes: Set<String>,
17+
content: String
18+
) -> ChatContext? {
19+
return .init(
20+
systemPrompt: """
21+
Current Time: \(Self.dateFormatter.string(from: Date())) (You can use it to calculate time in another time zone)
22+
""",
23+
functions: []
24+
)
25+
}
26+
}
27+

Core/Sources/ChatContextCollectors/WebChatContextCollector/SearchFunction.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct SearchFunction: ChatGPTFunction {
5151
"freshness": [
5252
.type: "string",
5353
.description: .string(
54-
"limit the search result to a specific range, use only when user ask the question about current events. Today is \(today). Format: yyyy-MM-dd..yyyy-MM-dd"
54+
"limit the search result to a specific range, use only when I ask the question about current events. Today is \(today). Format: yyyy-MM-dd..yyyy-MM-dd"
5555
),
5656
.examples: ["1919-10-20..1988-10-20"],
5757
],

Core/Sources/ChatGPTChatTab/ChatContextMenu.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import SharedUIComponents
33
import SwiftUI
44

55
struct ChatContextMenu: View {
6-
let chat: ChatProvider
6+
@ObservedObject var chat: ChatProvider
77
@AppStorage(\.customCommands) var customCommands
88

99
var body: some View {

Core/Sources/ChatGPTChatTab/ChatGPTChatTab.swift

+64-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import ChatService
22
import ChatTab
33
import Combine
4+
import ComposableArchitecture
45
import Foundation
6+
import OpenAIService
57
import Preferences
68
import SwiftUI
79

@@ -13,18 +15,24 @@ public class ChatGPTChatTab: ChatTab {
1315
public let provider: ChatProvider
1416
private var cancellable = Set<AnyCancellable>()
1517

18+
struct RestorableState: Codable {
19+
var history: [OpenAIService.ChatMessage]
20+
var configuration: OverridingChatGPTConfiguration.Overriding
21+
var systemPrompt: String
22+
var extraSystemPrompt: String
23+
}
24+
1625
struct Builder: ChatTabBuilder {
1726
var title: String
18-
var buildable: Bool { true }
1927
var customCommand: CustomCommand?
28+
var afterBuild: (ChatGPTChatTab) async -> Void = { _ in }
2029

21-
func build() -> any ChatTab {
22-
let tab = ChatGPTChatTab()
23-
Task {
24-
if let customCommand {
25-
try await tab.service.handleCustomCommand(customCommand)
26-
}
30+
func build(store: StoreOf<ChatTabItem>) async -> (any ChatTab)? {
31+
let tab = ChatGPTChatTab(store: store)
32+
if let customCommand {
33+
try? await tab.service.handleCustomCommand(customCommand)
2734
}
35+
await afterBuild(tab)
2836
return tab
2937
}
3038
}
@@ -37,6 +45,32 @@ public class ChatGPTChatTab: ChatTab {
3745
ChatContextMenu(chat: provider)
3846
}
3947

48+
public func restorableState() async -> Data {
49+
let state = RestorableState(
50+
history: await service.memory.history,
51+
configuration: service.configuration.overriding,
52+
systemPrompt: service.systemPrompt,
53+
extraSystemPrompt: service.extraSystemPrompt
54+
)
55+
return (try? JSONEncoder().encode(state)) ?? Data()
56+
}
57+
58+
public static func restore(
59+
from data: Data,
60+
externalDependency: Void
61+
) async throws -> any ChatTabBuilder {
62+
let state = try JSONDecoder().decode(RestorableState.self, from: data)
63+
let builder = Builder(title: "Chat") { @MainActor tab in
64+
tab.service.configuration.overriding = state.configuration
65+
tab.service.mutateSystemPrompt(state.systemPrompt)
66+
tab.service.mutateExtraSystemPrompt(state.extraSystemPrompt)
67+
await tab.service.memory.mutateHistory { history in
68+
history = state.history
69+
}
70+
}
71+
return builder
72+
}
73+
4074
public static func chatBuilders(externalDependency: Void) -> [ChatTabBuilder] {
4175
let customCommands = UserDefaults.shared.value(for: \.customCommands).compactMap {
4276
command in
@@ -49,14 +83,33 @@ public class ChatGPTChatTab: ChatTab {
4983
return [Builder(title: "New Chat", customCommand: nil)] + customCommands
5084
}
5185

52-
public init(service: ChatService = .init()) {
86+
public init(service: ChatService = .init(), store: StoreOf<ChatTabItem>) {
5387
self.service = service
5488
provider = .init(service: service)
55-
super.init(id: "Chat-" + provider.id.uuidString, title: "Chat")
89+
super.init(store: store)
90+
}
5691

92+
public func start() {
93+
chatTabViewStore.send(.updateTitle("Chat"))
94+
95+
service.$systemPrompt.removeDuplicates().sink { _ in
96+
Task { @MainActor [weak self] in
97+
self?.chatTabViewStore.send(.tabContentUpdated)
98+
}
99+
}.store(in: &cancellable)
100+
101+
service.$extraSystemPrompt.removeDuplicates().sink { _ in
102+
Task { @MainActor [weak self] in
103+
self?.chatTabViewStore.send(.tabContentUpdated)
104+
}
105+
}.store(in: &cancellable)
106+
57107
provider.$history.sink { [weak self] _ in
58-
if let title = self?.provider.title {
59-
self?.title = title
108+
Task { @MainActor [weak self] in
109+
if let title = self?.provider.title {
110+
self?.chatTabViewStore.send(.updateTitle(title))
111+
}
112+
self?.chatTabViewStore.send(.tabContentUpdated)
60113
}
61114
}.store(in: &cancellable)
62115
}

0 commit comments

Comments
 (0)