Skip to content

Commit 13f4cbd

Browse files
committed
LangChain in Swift and a working version of the search plugin
1 parent df8a478 commit 13f4cbd

File tree

27 files changed

+1200
-137
lines changed

27 files changed

+1200
-137
lines changed

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

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Core/Package.swift

Lines changed: 28 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ let package = Package(
1515
"FileChangeChecker",
1616
"LaunchAgentManager",
1717
"UpdateChecker",
18-
"Logger",
1918
"UserDefaultsObserver",
2019
"XcodeInspector",
2120
]
@@ -26,7 +25,6 @@ let package = Package(
2625
"SuggestionModel",
2726
"Client",
2827
"XPCShared",
29-
"Logger",
3028
]
3129
),
3230
.library(
@@ -38,9 +36,7 @@ let package = Package(
3836
"Client",
3937
"XPCShared",
4038
"LaunchAgentManager",
41-
"Logger",
4239
"UpdateChecker",
43-
"OpenAIService",
4440
]
4541
),
4642
],
@@ -52,7 +48,6 @@ let package = Package(
5248
.package(url: "https://github.com/JohnSundell/Splash", branch: "master"),
5349
.package(url: "https://github.com/gonzalezreal/swift-markdown-ui", from: "2.1.0"),
5450
.package(url: "https://github.com/sparkle-project/Sparkle", from: "2.0.0"),
55-
.package(url: "https://github.com/alfianlosari/GPTEncoder", from: "1.0.4"),
5651
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess", from: "4.2.2"),
5752
.package(url: "https://github.com/pvieito/PythonKit.git", branch: "master"),
5853
],
@@ -64,8 +59,8 @@ let package = Package(
6459
dependencies: [
6560
"SuggestionModel",
6661
"XPCShared",
67-
"Logger",
6862
"GitHubCopilotService",
63+
.product(name: "Logger", package: "Tool"),
6964
.product(name: "Preferences", package: "Tool"),
7065
]
7166
),
@@ -75,7 +70,6 @@ let package = Package(
7570
"SuggestionModel",
7671
"SuggestionService",
7772
"GitHubCopilotService",
78-
"OpenAIService",
7973
"XPCShared",
8074
"CGEventObserver",
8175
"DisplayLink",
@@ -84,11 +78,12 @@ let package = Package(
8478
"Environment",
8579
"SuggestionWidget",
8680
"AXExtension",
87-
"Logger",
8881
"ChatService",
82+
.product(name: "Logger", package: "Tool"),
8983
"PromptToCodeService",
9084
"ServiceUpdateMigration",
9185
"UserDefaultsObserver",
86+
.product(name: "OpenAIService", package: "Tool"),
9287
.product(name: "Preferences", package: "Tool"),
9388
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
9489
.product(name: "PythonKit", package: "PythonKit"),
@@ -125,6 +120,7 @@ let package = Package(
125120
"CodeiumService",
126121
"SuggestionModel",
127122
"LaunchAgentManager",
123+
.product(name: "OpenAIService", package: "Tool"),
128124
.product(name: "Preferences", package: "Tool"),
129125
]
130126
),
@@ -164,8 +160,12 @@ let package = Package(
164160

165161
.target(
166162
name: "PromptToCodeService",
167-
dependencies: ["OpenAIService", "Environment", "GitHubCopilotService",
168-
"SuggestionModel"]
163+
dependencies: [
164+
"Environment",
165+
"GitHubCopilotService",
166+
"SuggestionModel",
167+
.product(name: "OpenAIService", package: "Tool"),
168+
]
169169
),
170170
.testTarget(name: "PromptToCodeServiceTests", dependencies: ["PromptToCodeService"]),
171171

@@ -176,33 +176,33 @@ let package = Package(
176176
dependencies: [
177177
"ChatPlugin",
178178
"ChatContextCollector",
179-
"OpenAIService",
180179
"Environment",
181180
"XcodeInspector",
182181

183182
// plugins
184183
"MathChatPlugin",
185184
"SearchChatPlugin",
186185

186+
.product(name: "OpenAIService", package: "Tool"),
187187
.product(name: "Preferences", package: "Tool"),
188188
]
189189
),
190190
.target(
191191
name: "ChatPlugin",
192192
dependencies: [
193-
"OpenAIService",
194193
"Environment",
194+
.product(name: "OpenAIService", package: "Tool"),
195195
.product(name: "Terminal", package: "Tool"),
196196
.product(name: "PythonKit", package: "PythonKit"),
197197
]
198198
),
199199
.target(
200200
name: "ChatContextCollector",
201201
dependencies: [
202-
"OpenAIService",
203202
"Environment",
204203
"SuggestionModel",
205204
"XcodeInspector",
205+
.product(name: "OpenAIService", package: "Tool"),
206206
.product(name: "Preferences", package: "Tool"),
207207
]
208208
),
@@ -218,8 +218,8 @@ let package = Package(
218218
"Highlightr",
219219
"Splash",
220220
"UserDefaultsObserver",
221-
"Logger",
222221
"XcodeInspector",
222+
.product(name: "Logger", package: "Tool"),
223223
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
224224
.product(name: "MarkdownUI", package: "swift-markdown-ui"),
225225
]
@@ -229,7 +229,6 @@ let package = Package(
229229
// MARK: - Helpers
230230

231231
.target(name: "CGEventObserver"),
232-
.target(name: "Logger"),
233232
.target(name: "FileChangeChecker"),
234233
.target(name: "LaunchAgentManager"),
235234
.target(name: "DisplayLink"),
@@ -238,8 +237,8 @@ let package = Package(
238237
.target(
239238
name: "UpdateChecker",
240239
dependencies: [
241-
"Logger",
242240
"Sparkle",
241+
.product(name: "Logger", package: "Tool"),
243242
]
244243
),
245244
.target(name: "AXExtension"),
@@ -256,8 +255,8 @@ let package = Package(
256255
dependencies: [
257256
"AXExtension",
258257
"Environment",
259-
"Logger",
260258
"AXNotificationStream",
259+
.product(name: "Logger", package: "Tool"),
261260
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
262261
]
263262
),
@@ -279,22 +278,6 @@ let package = Package(
279278
dependencies: ["GitHubCopilotService"]
280279
),
281280

282-
// MARK: - OpenAI
283-
284-
.target(
285-
name: "OpenAIService",
286-
dependencies: [
287-
"Logger",
288-
"GPTEncoder",
289-
.product(name: "Preferences", package: "Tool"),
290-
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
291-
]
292-
),
293-
.testTarget(
294-
name: "OpenAIServiceTests",
295-
dependencies: ["OpenAIService"]
296-
),
297-
298281
// MARK: - Codeium
299282

300283
.target(
@@ -314,23 +297,23 @@ let package = Package(
314297
name: "MathChatPlugin",
315298
dependencies: [
316299
"ChatPlugin",
317-
"OpenAIService",
300+
.product(name: "OpenAIService", package: "Tool"),
318301
.product(name: "LangChain", package: "Tool"),
319302
.product(name: "PythonKit", package: "PythonKit"),
320303
],
321304
path: "Sources/ChatPlugins/MathChatPlugin"
322305
),
323-
324-
.target(
325-
name: "SearchChatPlugin",
326-
dependencies: [
327-
"ChatPlugin",
328-
"OpenAIService",
329-
.product(name: "LangChain", package: "Tool"),
330-
.product(name: "PythonKit", package: "PythonKit"),
331-
],
332-
path: "Sources/ChatPlugins/SearchChatPlugin"
333-
),
306+
307+
.target(
308+
name: "SearchChatPlugin",
309+
dependencies: [
310+
"ChatPlugin",
311+
.product(name: "OpenAIService", package: "Tool"),
312+
.product(name: "LangChain", package: "Tool"),
313+
.product(name: "PythonKit", package: "PythonKit"),
314+
],
315+
path: "Sources/ChatPlugins/SearchChatPlugin"
316+
),
334317
]
335318
)
336319

Core/Sources/ChatPlugins/MathChatPlugin/MathChatPlugin.swift

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,24 @@ public actor MathChatPlugin: ChatPlugin {
3434
do {
3535
let result = try await solveMathProblem(content)
3636
let formattedResult = "\(await translatedAnswer) \(result)"
37-
await chatGPTService.mutateHistory { history in
38-
if history.last?.id == id {
39-
history.removeLast()
37+
if !isCancelled {
38+
await chatGPTService.mutateHistory { history in
39+
if history.last?.id == id {
40+
history.removeLast()
41+
}
42+
reply.content = formattedResult
43+
history.append(reply)
4044
}
41-
reply.content = formattedResult
42-
history.append(reply)
4345
}
4446
} catch {
45-
await chatGPTService.mutateHistory { history in
46-
if history.last?.id == id {
47-
history.removeLast()
47+
if !isCancelled {
48+
await chatGPTService.mutateHistory { history in
49+
if history.last?.id == id {
50+
history.removeLast()
51+
}
52+
reply.content = error.localizedDescription
53+
history.append(reply)
4854
}
49-
reply.content = error.localizedDescription
50-
history.append(reply)
5155
}
5256
}
5357

Core/Sources/ChatPlugins/SearchChatPlugin/SearchAgent.swift

Lines changed: 0 additions & 9 deletions
This file was deleted.

Core/Sources/ChatPlugins/SearchChatPlugin/SearchChatPlugin.swift

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,58 @@ public actor SearchChatPlugin: ChatPlugin {
2121
delegate?.pluginDidStartResponding(self)
2222

2323
let id = "\(Self.command)-\(UUID().uuidString)"
24-
var reply = ChatMessage(id: id, role: .assistant, content: "Calculating...")
24+
var reply = ChatMessage(id: id, role: .assistant, content: "")
2525

2626
await chatGPTService.mutateHistory { history in
2727
history.append(.init(role: .user, content: originalMessage, summary: content))
28-
history.append(reply)
2928
}
3029

3130
do {
32-
let result = try await search(content)
33-
await chatGPTService.mutateHistory { history in
34-
if history.last?.id == id {
35-
history.removeLast()
31+
let eventStream = try await search(content)
32+
33+
var actions = [String]()
34+
var finishedActions = Set<String>()
35+
var message = ""
36+
37+
for try await event in eventStream {
38+
guard !isCancelled else { return }
39+
switch event {
40+
case let .startAction(content):
41+
actions.append(content)
42+
case let .endAction(content):
43+
finishedActions.insert(content)
44+
case let .answerToken(token):
45+
message.append(token)
46+
case let .finishAnswer(answer, links):
47+
message = """
48+
\(answer)
49+
50+
\(links.map { "- [\($0.title)](\($0.link))" }.joined(separator: "\n"))
51+
"""
52+
}
53+
54+
await chatGPTService.mutateHistory { history in
55+
if history.last?.id == id {
56+
history.removeLast()
57+
}
58+
59+
let actionString = actions.map {
60+
"> \(finishedActions.contains($0) ? "" : "🔍") \($0)"
61+
}.joined(separator: "\n>\n")
62+
63+
if message.isEmpty {
64+
reply.content = actionString
65+
} else {
66+
reply.content = """
67+
\(actionString)
68+
69+
\(message)
70+
"""
71+
}
72+
history.append(reply)
3673
}
37-
reply.content = result
38-
history.append(reply)
3974
}
75+
4076
} catch {
4177
await chatGPTService.mutateHistory { history in
4278
if history.last?.id == id {

0 commit comments

Comments
 (0)