Skip to content

Commit f531278

Browse files
committed
Support ChatGPTService in debug window
1 parent 0e8cad3 commit f531278

File tree

4 files changed

+171
-47
lines changed

4 files changed

+171
-47
lines changed

Pro

Submodule Pro updated from ef0377c to 5f31b6c

Tool/Sources/OpenAIService/ChatGPTService.swift

Lines changed: 77 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -98,41 +98,59 @@ public class ChatGPTService: ChatGPTServiceType {
9898
await memory.appendMessage(newMessage)
9999
}
100100

101-
return AsyncThrowingStream<String, Error> { continuation in
102-
Task(priority: .userInitiated) {
103-
do {
104-
var functionCall: ChatMessage.FunctionCall?
105-
var functionCallMessageID = ""
106-
var isInitialCall = true
107-
loop: while functionCall != nil || isInitialCall {
108-
isInitialCall = false
109-
if let call = functionCall {
110-
if !configuration.runFunctionsAutomatically {
111-
break loop
101+
return Debugger.$id.withValue(.init()) {
102+
AsyncThrowingStream<String, Error> { continuation in
103+
Task(priority: .userInitiated) {
104+
do {
105+
var functionCall: ChatMessage.FunctionCall?
106+
var functionCallMessageID = ""
107+
var isInitialCall = true
108+
loop: while functionCall != nil || isInitialCall {
109+
isInitialCall = false
110+
if let call = functionCall {
111+
if !configuration.runFunctionsAutomatically {
112+
break loop
113+
}
114+
functionCall = nil
115+
await runFunctionCall(call, messageId: functionCallMessageID)
112116
}
113-
functionCall = nil
114-
await runFunctionCall(call, messageId: functionCallMessageID)
115-
}
116-
let stream = try await sendMemory()
117-
for try await content in stream {
118-
switch content {
119-
case let .text(text):
120-
continuation.yield(text)
121-
case let .functionCall(call):
122-
if functionCall == nil {
123-
functionCallMessageID = uuidGenerator()
124-
functionCall = call
125-
} else {
126-
functionCall?.name.append(call.name)
127-
functionCall?.arguments.append(call.arguments)
117+
let stream = try await sendMemory()
118+
119+
#if DEBUG
120+
var reply = ""
121+
#endif
122+
123+
for try await content in stream {
124+
switch content {
125+
case let .text(text):
126+
continuation.yield(text)
127+
#if DEBUG
128+
reply.append(text)
129+
#endif
130+
case let .functionCall(call):
131+
if functionCall == nil {
132+
functionCallMessageID = uuidGenerator()
133+
functionCall = call
134+
} else {
135+
functionCall?.name.append(call.name)
136+
functionCall?.arguments.append(call.arguments)
137+
}
138+
await prepareFunctionCall(
139+
call,
140+
messageId: functionCallMessageID
141+
)
128142
}
129-
await prepareFunctionCall(call, messageId: functionCallMessageID)
130143
}
144+
#if DEBUG
145+
Debugger.didReceiveResponse(content: reply)
146+
#endif
131147
}
148+
149+
Debugger.didFinish()
150+
continuation.finish()
151+
} catch {
152+
continuation.finish(throwing: error)
132153
}
133-
continuation.finish()
134-
} catch {
135-
continuation.finish(throwing: error)
136154
}
137155
}
138156
}
@@ -152,22 +170,26 @@ public class ChatGPTService: ChatGPTServiceType {
152170
)
153171
await memory.appendMessage(newMessage)
154172
}
155-
156-
let message = try await sendMemoryAndWait()
157-
var finalResult = message?.content
158-
var functionCall = message?.functionCall
159-
while let call = functionCall {
160-
if !configuration.runFunctionsAutomatically {
161-
break
173+
return try await Debugger.$id.withValue(.init()) {
174+
let message = try await sendMemoryAndWait()
175+
var finalResult = message?.content
176+
var functionCall = message?.functionCall
177+
while let call = functionCall {
178+
if !configuration.runFunctionsAutomatically {
179+
break
180+
}
181+
functionCall = nil
182+
await runFunctionCall(call)
183+
guard let nextMessage = try await sendMemoryAndWait() else { break }
184+
finalResult = nextMessage.content
185+
functionCall = nextMessage.functionCall
162186
}
163-
functionCall = nil
164-
await runFunctionCall(call)
165-
guard let nextMessage = try await sendMemoryAndWait() else { break }
166-
finalResult = nextMessage.content
167-
functionCall = nextMessage.functionCall
168-
}
169187

170-
return finalResult
188+
Debugger.didReceiveResponse(content: finalResult ?? "N/A")
189+
Debugger.didFinish()
190+
191+
return finalResult
192+
}
171193
}
172194

173195
public func stopReceivingMessage() {
@@ -239,6 +261,8 @@ extension ChatGPTService {
239261
requestBody
240262
)
241263

264+
Debugger.didSendRequestBody(body: requestBody)
265+
242266
return AsyncThrowingStream<StreamContent, Error> { continuation in
243267
Task {
244268
do {
@@ -348,6 +372,8 @@ extension ChatGPTService {
348372
requestBody
349373
)
350374

375+
Debugger.didSendRequestBody(body: requestBody)
376+
351377
let response = try await api()
352378

353379
guard let choice = response.choices.first else { return nil }
@@ -388,6 +414,8 @@ extension ChatGPTService {
388414
_ call: ChatMessage.FunctionCall,
389415
messageId: String? = nil
390416
) async -> String {
417+
Debugger.didReceiveFunction(name: call.name, arguments: call.arguments)
418+
391419
let messageId = messageId ?? uuidGenerator()
392420

393421
guard let function = functionProvider.function(named: call.name) else {
@@ -413,6 +441,8 @@ extension ChatGPTService {
413441
}
414442
}
415443

444+
Debugger.didReceiveFunctionResult(result: result.botReadableContent)
445+
416446
await memory.updateMessage(id: messageId) { message in
417447
message.content = result.botReadableContent
418448
}
@@ -421,6 +451,9 @@ extension ChatGPTService {
421451
} catch {
422452
// For errors, use the error message as the result.
423453
let content = "Error: \(error.localizedDescription)"
454+
455+
Debugger.didReceiveFunctionResult(result: content)
456+
424457
await memory.updateMessage(id: messageId) { message in
425458
message.content = content
426459
}

Tool/Sources/OpenAIService/CompletionStreamAPI.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ protocol CompletionStreamAPI {
1313
)
1414
}
1515

16-
public enum FunctionCallStrategy: Encodable, Equatable {
16+
public enum FunctionCallStrategy: Codable, Equatable {
1717
/// Forbid the bot to call any function.
1818
case none
1919
/// Let the bot choose what function to call.
@@ -39,7 +39,7 @@ public enum FunctionCallStrategy: Encodable, Equatable {
3939
}
4040

4141
/// https://platform.openai.com/docs/api-reference/chat/create
42-
struct CompletionRequestBody: Encodable, Equatable {
42+
struct CompletionRequestBody: Codable, Equatable {
4343
struct Message: Codable, Equatable {
4444
/// The role of the message.
4545
var role: ChatMessage.Role
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import AppKit
2+
import Foundation
3+
4+
enum Debugger {
5+
#if DEBUG
6+
@TaskLocal
7+
static var id: UUID?
8+
#endif
9+
10+
static func didSendRequestBody(body: CompletionRequestBody) {
11+
#if DEBUG
12+
13+
do {
14+
let json = try JSONEncoder().encode(body)
15+
let center = NSWorkspace.shared.notificationCenter
16+
center.post(
17+
name: .init("ServiceDebugger.ChatRequestDebug.requestSent"),
18+
object: nil,
19+
userInfo: [
20+
"id": id ?? UUID(),
21+
"data": json,
22+
]
23+
)
24+
} catch {
25+
print("Failed to encode request body: \(error)")
26+
}
27+
28+
#endif
29+
}
30+
31+
static func didReceiveFunction(name: String, arguments: String) {
32+
#if DEBUG
33+
34+
let center = NSWorkspace.shared.notificationCenter
35+
center.post(
36+
name: .init("ServiceDebugger.ChatRequestDebug.receivedFunctionCall"),
37+
object: nil,
38+
userInfo: [
39+
"id": id ?? UUID(),
40+
"name": name,
41+
"arguments": arguments,
42+
]
43+
)
44+
45+
#endif
46+
}
47+
48+
static func didReceiveFunctionResult(result: String) {
49+
#if DEBUG
50+
51+
let center = NSWorkspace.shared.notificationCenter
52+
center.post(
53+
name: .init("ServiceDebugger.ChatRequestDebug.receivedFunctionResult"),
54+
object: nil,
55+
userInfo: [
56+
"id": id ?? UUID(),
57+
"result": result,
58+
]
59+
)
60+
61+
#endif
62+
}
63+
64+
static func didReceiveResponse(content: String) {
65+
#if DEBUG
66+
67+
let center = NSWorkspace.shared.notificationCenter
68+
center.post(
69+
name: .init("ServiceDebugger.ChatRequestDebug.responseReceived"),
70+
object: nil,
71+
userInfo: [
72+
"id": id ?? UUID(),
73+
"response": content,
74+
]
75+
)
76+
77+
#endif
78+
}
79+
80+
static func didFinish() {
81+
let center = NSWorkspace.shared.notificationCenter
82+
center.post(
83+
name: .init("ServiceDebugger.ChatRequestDebug.finished"),
84+
object: nil,
85+
userInfo: [
86+
"id": id ?? UUID(),
87+
]
88+
)
89+
}
90+
}
91+

0 commit comments

Comments
 (0)