Skip to content

Commit 413d387

Browse files
committed
Merge tag '0.13.0' into develop
2 parents 4338145 + 42741a4 commit 413d387

9 files changed

Lines changed: 89 additions & 61 deletions

File tree

Core/Sources/OpenAIService/ChatGPTService.swift

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ public actor ChatGPTService: ChatGPTServiceType {
125125
messages: messages,
126126
temperature: temperature ?? defaultTemperature,
127127
stream: true,
128-
max_tokens: remainingTokens
128+
max_tokens: maxTokenForReply(model: model, remainingTokens: remainingTokens)
129129
)
130130

131131
isReceivingMessage = true
@@ -205,7 +205,7 @@ public actor ChatGPTService: ChatGPTServiceType {
205205
messages: messages,
206206
temperature: temperature ?? defaultTemperature,
207207
stream: true,
208-
max_tokens: remainingTokens
208+
max_tokens: maxTokenForReply(model: model, remainingTokens: remainingTokens)
209209
)
210210

211211
isReceivingMessage = true
@@ -261,7 +261,7 @@ extension ChatGPTService {
261261
}
262262

263263
func combineHistoryWithSystemPrompt(
264-
minimumReplyTokens: Int = 200,
264+
minimumReplyTokens: Int = 300,
265265
maxNumberOfMessages: Int = UserDefaults.shared.value(for: \.chatGPTMaxMessageCount),
266266
maxTokens: Int = UserDefaults.shared.value(for: \.chatGPTMaxToken),
267267
encoder: TokenEncoder = GPTEncoder()
@@ -270,10 +270,11 @@ extension ChatGPTService {
270270
{
271271
var all: [CompletionRequestBody.Message] = []
272272
var allTokensCount = encoder.encode(text: systemPrompt).count
273-
for message in history.reversed() {
273+
for (index, message) in history.enumerated().reversed() {
274274
if maxNumberOfMessages > 0, all.count >= maxNumberOfMessages { break }
275275
if message.content.isEmpty { continue }
276-
let tokensCount = encoder.encode(text: message.content).count
276+
let tokensCount = message.tokensCount ?? encoder.encode(text: message.content).count
277+
history[index].tokensCount = tokensCount
277278
if tokensCount + allTokensCount > maxTokens - minimumReplyTokens {
278279
break
279280
}
@@ -291,3 +292,8 @@ protocol TokenEncoder {
291292
}
292293

293294
extension GPTEncoder: TokenEncoder {}
295+
296+
func maxTokenForReply(model: String, remainingTokens: Int) -> Int {
297+
guard let model = ChatGPTModel(rawValue: model) else { return remainingTokens }
298+
return min(model.maxToken / 2, remainingTokens)
299+
}

Core/Sources/OpenAIService/Models.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,14 @@ public struct ChatMessage: Equatable, Codable {
1515
}
1616

1717
public var role: Role
18-
public var content: String
18+
public var content: String {
19+
didSet {
20+
tokensCount = nil
21+
}
22+
}
1923
public var summary: String?
2024
public var id: String
25+
public var tokensCount: Int?
2126

2227
public init(
2328
id: String = UUID().uuidString,
Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
import AppKit
2-
import SwiftUI
32
import Combine
3+
import SwiftUI
4+
5+
struct CustomScrollViewHeightPreferenceKey: PreferenceKey {
6+
static var defaultValue: Double = 0
7+
static func reduce(value: inout Double, nextValue: () -> Double) {
8+
value = nextValue() + value
9+
}
10+
}
11+
12+
struct CustomScrollViewUpdateHeightModifier: ViewModifier {
13+
func body(content: Content) -> some View {
14+
content
15+
.background {
16+
GeometryReader { proxy in
17+
Color.clear
18+
.preference(
19+
key: CustomScrollViewHeightPreferenceKey.self,
20+
value: proxy.size.height
21+
)
22+
}
23+
}
24+
}
25+
}
426

527
/// Used to workaround a SwiftUI bug. https://github.com/intitni/CopilotForXcode/issues/122
628
struct CustomScrollView<Content: View>: View {
729
@ViewBuilder var content: () -> Content
8-
@State var height: Double = 100
30+
@State var height: Double = 10
931
@AppStorage(\.useCustomScrollViewWorkaround) var useNSScrollViewWrapper
1032

1133
var body: some View {
1234
if useNSScrollViewWrapper {
1335
List {
1436
content()
1537
.listRowInsets(EdgeInsets(top: 0, leading: -8, bottom: 0, trailing: -8))
38+
.modifier(CustomScrollViewUpdateHeightModifier())
1639
}
1740
.listStyle(.plain)
18-
.frame(idealHeight: height)
19-
.background {
20-
ComputeHeight(height: $height) {
21-
content()
22-
}
23-
.frame(maxWidth: .infinity)
24-
.opacity(0)
41+
.frame(idealHeight: max(10, height))
42+
.onPreferenceChange(CustomScrollViewHeightPreferenceKey.self) { newHeight in
43+
height = newHeight
2544
}
2645
} else {
2746
ScrollView {
@@ -30,31 +49,3 @@ struct CustomScrollView<Content: View>: View {
3049
}
3150
}
3251
}
33-
34-
private struct ComputeHeight<Content: View>: NSViewRepresentable {
35-
@Binding var height: Double
36-
@ViewBuilder var content: () -> Content
37-
38-
func makeNSView(context: Context) -> NSView {
39-
let view = NSView()
40-
return view
41-
}
42-
43-
func updateNSView(_ nsView: NSView, context: Context) {
44-
updateHeight(nsView)
45-
}
46-
47-
func updateHeight(_ nsView: NSView) {
48-
let contentView = content()
49-
let hostingView = NSHostingView(
50-
rootView: contentView.frame(width: nsView.frame.width == 0 ? 200 : nsView.frame.width)
51-
)
52-
let size = hostingView.fittingSize
53-
54-
if height != size.height {
55-
Task { @MainActor in
56-
height = size.height
57-
}
58-
}
59-
}
60-
}

Core/Sources/SuggestionWidget/SyntaxHighlighting.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func highlightedCodeBlock(
6161
}
6262
return leadingSpaces
6363
}
64-
64+
6565
// Workaround: Splash has a bug that will insert an extra space at the beginning.
6666
let leadingSpaces = leadingSpacesInCode(code)
6767
let leadingSpacesFormatted = leadingSpacesInCode(formatted.string)
@@ -73,7 +73,7 @@ func highlightedCodeBlock(
7373
)
7474
}
7575
// End of workaround.
76-
76+
7777
return formatted
7878
default:
7979
var language = language
@@ -148,15 +148,16 @@ func convertToCodeLines(
148148
let separatedInput = input.components(separatedBy: "\n")
149149
let commonLeadingSpaceCount = {
150150
if !droppingLeadingSpaces { return 0 }
151-
let splitted = separatedInput
151+
let split = separatedInput
152152
var result = 0
153-
outerLoop: for i in [4, 8, 12, 16, 20, 24] {
154-
for line in splitted {
153+
outerLoop: for i in stride(from: 40, through: 4, by: -4) {
154+
for line in split {
155155
if isEmptyLine(line) { continue }
156-
if i >= line.count { break outerLoop }
157-
if !line.hasPrefix(.init(repeating: " ", count: i)) { break outerLoop }
156+
if i >= line.count { continue outerLoop }
157+
if !line.hasPrefix(.init(repeating: " ", count: i)) { continue outerLoop }
158158
}
159159
result = i
160+
break
160161
}
161162
return result
162163
}()

Core/Tests/OpenAIServiceTests/ChatGPTServiceTests.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ final class ChatGPTServiceTests: XCTestCase {
6262
.init(role: .user, content: "Hello"),
6363
], "System prompt is included")
6464
XCTAssertEqual(all, ["hello", "my", "friends"], "Text stream is correct")
65-
let history = await service.history
65+
var history = await service.history
66+
for (i, _) in history.enumerated() {
67+
history[i].tokensCount = nil
68+
}
6669
XCTAssertEqual(history, [
6770
.init(id: "0", role: .user, content: "Hello"),
6871
.init(id: "1", role: .assistant, content: "hellomyfriends"),

Core/Tests/OpenAIServiceTests/LimitMessagesTests.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,16 @@ final class LimitMessagesTests: XCTestCase {
2323
"hello",
2424
"world",
2525
])
26-
26+
2727
XCTAssertEqual(remainingTokens, 10000 - 12 - 6)
28+
let history = await service.history
29+
XCTAssertEqual(history.map(\.tokensCount), [
30+
2,
31+
5,
32+
5,
33+
])
2834
}
29-
35+
3036
func test_send_max_message_if_not_reached_token_limit() async {
3137
let service = await createService(systemPrompt: "system", messages: [
3238
"hi",
@@ -45,10 +51,10 @@ final class LimitMessagesTests: XCTestCase {
4551
"hello",
4652
"world",
4753
], "Count from end to start.")
48-
54+
4955
XCTAssertEqual(remainingTokens, 10000 - 10 - 6)
5056
}
51-
57+
5258
func test_reached_token_limit() async {
5359
let service = await createService(systemPrompt: "system", messages: [
5460
"hi",
@@ -66,10 +72,10 @@ final class LimitMessagesTests: XCTestCase {
6672
"system",
6773
"world",
6874
])
69-
75+
7076
XCTAssertEqual(remainingTokens, 201)
7177
}
72-
78+
7379
func test_minimum_reply_tokens_count() async {
7480
let service = await createService(systemPrompt: "system", messages: [
7581
"hi",
@@ -86,7 +92,7 @@ final class LimitMessagesTests: XCTestCase {
8692
XCTAssertEqual(messages, [
8793
"system",
8894
])
89-
95+
9096
XCTAssertEqual(remainingTokens, 200)
9197
}
9298
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ If you need to end a plugin, you can just type
163163

164164
Prompt to code commands are not available in comment mode.
165165

166+
### Custom Commands
167+
168+
You can create custom commands that runs Chat and Prompt to Code with custom prompts. This commands can be accessed from the Xcode menu bar and the context menu of the circular widget.
169+
166170
## Key Bindings
167171

168172
It looks like there is no way to add default key bindings to commands, but you can set them up in `Xcode settings > Key Bindings`. You can filter the list by typing `copilot` in the search bar.

Version.xcconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
APP_VERSION = 0.12.0
2-
APP_BUILD = 90
1+
APP_VERSION = 0.13.0
2+
APP_BUILD = 101

appcast.xml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,26 @@
33
<channel>
44
<title>Copilot for Xcode</title>
55

6+
<item>
7+
<title>0.13.0</title>
8+
<pubDate>Sat, 22 Apr 2023 12:20:16 +0800</pubDate>
9+
<sparkle:version>101</sparkle:version>
10+
<sparkle:shortVersionString>0.13.0</sparkle:shortVersionString>
11+
<sparkle:minimumSystemVersion>12.0</sparkle:minimumSystemVersion>
12+
<sparkle:releaseNotesLink>
13+
https://github.com/intitni/CopilotForXcode/releases/tag/0.13.0
14+
</sparkle:releaseNotesLink>
15+
<enclosure url="https://github.com/intitni/CopilotForXcode/releases/download/0.13.0/Copilot.for.Xcode.app.zip" length="20082799" type="application/octet-stream" sparkle:edSignature="5fI7XeXX4gBk/eXZh/rfpKbF67FXChUuusrQR5Z+ly0GhMSpTM9wf9MiWTyFeCSYdbp+GQftYHGQGDfT8TlMBQ=="/>
16+
</item>
17+
618
<item>
719
<title>0.12.0</title>
820
<pubDate>Sat, 15 Apr 2023 14:43:37 +0800</pubDate>
921
<sparkle:version>90</sparkle:version>
1022
<sparkle:shortVersionString>0.12.0</sparkle:shortVersionString>
1123
<sparkle:minimumSystemVersion>12.0</sparkle:minimumSystemVersion>
1224
<sparkle:releaseNotesLink>
13-
https://github.com/intitni/CopilotForXcode/releases/tag/0.11.2
25+
https://github.com/intitni/CopilotForXcode/releases/tag/0.12.0
1426
</sparkle:releaseNotesLink>
1527
<enclosure url="https://github.com/intitni/CopilotForXcode/releases/download/0.12.0/Copilot.for.Xcode.app.zip" length="19259862" type="application/octet-stream" sparkle:edSignature="E1arc0aqs+QEc2O9d/KEOEchBwmxPTamoTaQhl8qng9Z3Kqmvwg8Sc9VTyJ2xgbhY/DaAcJYapz8lR5g8BbZBA=="/>
1628
</item>

0 commit comments

Comments
 (0)