Skip to content

Commit 37407e4

Browse files
committedMar 10, 2025·
Pre-release 0.31.106
1 parent b9029ca commit 37407e4

File tree

8 files changed

+83
-25
lines changed

8 files changed

+83
-25
lines changed
 

‎Core/Sources/ConversationTab/ModelPicker.swift

+28-8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import SwiftUI
22
import ChatService
33
import Persist
44
import ComposableArchitecture
5+
import GitHubCopilotService
56

67
public let SELECTED_LLM_KEY = "selectedLLM"
78

@@ -27,6 +28,18 @@ extension AppState {
2728
}
2829
}
2930

31+
extension CopilotModelManager {
32+
static func getAvailableChatLLMs() -> [LLMModel] {
33+
let LLMs = CopilotModelManager.getAvailableLLMs()
34+
let availableModels = LLMs.filter(
35+
{ $0.scopes.contains(.chatPanel) }
36+
).map {
37+
LLMModel(modelName: $0.modelName, modelFamily: $0.modelFamily)
38+
}
39+
return availableModels.isEmpty ? [defaultModel] : availableModels
40+
}
41+
}
42+
3043
struct LLMModel: Codable, Hashable {
3144
let modelName: String
3245
let modelFamily: String
@@ -35,12 +48,15 @@ struct LLMModel: Codable, Hashable {
3548
let defaultModel = LLMModel(modelName: "GPT-4o", modelFamily: "gpt-4o")
3649
struct ModelPicker: View {
3750
@State private var selectedModel = defaultModel.modelName
38-
@State private var models: [LLMModel] = [ defaultModel ]
3951
@State private var isHovered = false
4052
@State private var isPressed = false
4153

4254
init() {
43-
self.updateCurrentModel()
55+
self.updateCurrentModel()
56+
}
57+
58+
var models: [LLMModel] {
59+
CopilotModelManager.getAvailableChatLLMs()
4460
}
4561

4662
func updateCurrentModel() {
@@ -74,13 +90,9 @@ struct ModelPicker: View {
7490
isHovered = hovering
7591
}
7692
.onAppear() {
93+
updateCurrentModel()
7794
Task {
78-
updateCurrentModel()
79-
self.models = await ChatService.shared.copilotModels().filter(
80-
{ $0.scopes.contains(.chatPanel) }
81-
).map {
82-
LLMModel(modelName: $0.modelName, modelFamily: $0.modelFamily)
83-
}
95+
await refreshModels()
8496
}
8597
}
8698
.help("Pick Model")
@@ -93,6 +105,14 @@ struct ModelPicker: View {
93105
let width = selectedModel.size(withAttributes: attributes).width
94106
return CGFloat(width + 20)
95107
}
108+
109+
@MainActor
110+
func refreshModels() async {
111+
let copilotModels = await ChatService.shared.copilotModels()
112+
if !copilotModels.isEmpty {
113+
CopilotModelManager.updateLLMs(copilotModels)
114+
}
115+
}
96116
}
97117

98118
struct ModelPicker_Previews: PreviewProvider {

‎Core/Sources/GitHubCopilotViewModel/GitHubCopilotViewModel.swift

+4
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ public class GitHubCopilotViewModel: ObservableObject {
155155
waitingForSignIn = false
156156
self.username = username
157157
self.status = status
158+
let models = try? await service.models()
159+
if let models = models, !models.isEmpty {
160+
CopilotModelManager.updateLLMs(models)
161+
}
158162
await Status.shared.updateAuthStatus(.loggedIn, username: username)
159163
broadcastStatusChange()
160164
} catch let error as GitHubCopilotError {

‎Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ struct PseudoCommandHandler {
266266
if now.timeIntervalSince(lastBundleNotFoundTime) > 60 * 60 {
267267
Self.lastBundleNotFoundTime = now
268268
toast.toast(
269-
title: "Extension Permission Not Granted",
269+
title: "GitHub Copilot Extension Permission Not Granted",
270270
content: """
271271
Enable Extensions → Xcode Source Editor → GitHub Copilot \
272272
for Xcode for faster and full-featured code completion. \
@@ -287,7 +287,7 @@ struct PseudoCommandHandler {
287287
content: "Quit and restart Xcode to enable extension.",
288288
level: .warning,
289289
button: .init(
290-
title: "Restart",
290+
title: "Restart Xcode",
291291
action: { NSWorkspace.restartXcode() }
292292
)
293293
)

‎Core/Sources/SuggestionWidget/WidgetWindowsController.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ public final class WidgetWindows {
744744
it.isReleasedWhenClosed = false
745745
it.isOpaque = false
746746
it.backgroundColor = .clear
747-
it.level = widgetLevel(0)
747+
it.level = widgetLevel(2)
748748
it.collectionBehavior = [.fullScreenAuxiliary, .transient, .canJoinAllSpaces]
749749
it.hasShadow = false
750750
it.contentView = NSHostingView(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import ConversationServiceProvider
2+
3+
public class CopilotModelManager {
4+
private static var availableLLMs: [CopilotModel] = []
5+
6+
public static func updateLLMs(_ models: [CopilotModel]) {
7+
availableLLMs = models
8+
}
9+
10+
public static func getAvailableLLMs() -> [CopilotModel] {
11+
return availableLLMs
12+
}
13+
14+
public static func hasLLMs() -> Bool {
15+
return !availableLLMs.isEmpty
16+
}
17+
18+
public static func clearLLMs() {
19+
availableLLMs = []
20+
}
21+
}

‎Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift

+8
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,12 @@ public final class GitHubCopilotService:
683683
private func updateServiceAuthStatus(_ status: GitHubCopilotRequest.CheckStatus.Response) async {
684684
Logger.gitHubCopilot.info("check status response: \(status)")
685685
if status.status == .ok || status.status == .maybeOk {
686+
if !CopilotModelManager.hasLLMs() {
687+
let models = try? await models()
688+
if let models = models, !models.isEmpty {
689+
CopilotModelManager.updateLLMs(models)
690+
}
691+
}
686692
await Status.shared.updateAuthStatus(.loggedIn, username: status.user)
687693
await unwatchAuthStatus()
688694
} else if status.status == .notAuthorized {
@@ -874,6 +880,8 @@ public final class GitHubCopilotService:
874880

875881
if let signoutError {
876882
throw signoutError
883+
} else {
884+
CopilotModelManager.clearLLMs()
877885
}
878886
}
879887
}

‎Tool/Sources/Toast/NotificationView.swift

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ struct AutoDismissMessage: View {
1515
message.level.color as Color,
1616
in: RoundedRectangle(cornerRadius: 8)
1717
)
18+
.frame(minWidth: 300)
1819
}
1920
}
2021

@@ -53,7 +54,10 @@ public struct NotificationView: View {
5354
Spacer()
5455

5556
if let button = message.button {
56-
Button(action: button.action) {
57+
Button(action: {
58+
button.action()
59+
onDismiss()
60+
}) {
5761
Text(button.title)
5862
.padding(.horizontal, 7)
5963
.padding(.vertical, 3)
@@ -76,10 +80,6 @@ public struct NotificationView: View {
7680
} else {
7781
AutoDismissMessage(message: message)
7882
.frame(maxWidth: .infinity)
79-
.overlay {
80-
RoundedRectangle(cornerRadius: 8)
81-
.stroke(Color.black.opacity(0.3), lineWidth: 1)
82-
}
8383
}
8484
}
8585
}

‎Tool/Sources/Toast/Toast.swift

+14-9
Original file line numberDiff line numberDiff line change
@@ -271,15 +271,20 @@ public extension NSWorkspace {
271271
}
272272
NSWorkspace.shared.open(URL(string: urlString)!)
273273
} else {
274-
let script = NSAppleScript(
275-
source: """
276-
tell application "System Preferences"
277-
activate
278-
set the current pane to pane id "com.apple.preferences.extensions"
279-
end tell
280-
"""
281-
)
282-
script?.executeAndReturnError(nil)
274+
let process = Process()
275+
process.executableURL = URL(fileURLWithPath: "/usr/bin/open")
276+
process.arguments = [
277+
"-b",
278+
"com.apple.systempreferences",
279+
"/System/Library/PreferencePanes/Extensions.prefPane"
280+
]
281+
282+
do {
283+
try process.run()
284+
} catch {
285+
// Handle error silently
286+
return
287+
}
283288
}
284289
}
285290

0 commit comments

Comments
 (0)
Please sign in to comment.