Skip to content

Commit b2189de

Browse files
committed
Pre-release 0.33.114
1 parent 8e83ed9 commit b2189de

File tree

9 files changed

+119
-48
lines changed

9 files changed

+119
-48
lines changed

Core/Sources/ConversationTab/Chat.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Preferences
66
import Terminal
77
import ConversationServiceProvider
88
import Persist
9+
import GitHubCopilotService
910

1011
public struct DisplayedChatMessage: Equatable {
1112
public enum Role: Equatable {
@@ -142,7 +143,7 @@ struct Chat {
142143
state.typedMessage = ""
143144

144145
let selectedFiles = state.selectedFiles
145-
let selectedModelFamily = AppState.shared.getSelectedModelFamily()
146+
let selectedModelFamily = AppState.shared.getSelectedModelFamily() ?? CopilotModelManager.getDefaultChatLLM()?.modelFamily
146147
return .run { _ in
147148
try await service.send(id, content: message, skillSet: skillSet, references: selectedFiles, model: selectedModelFamily)
148149
}.cancellable(id: CancelID.sendMessage(self.id))
@@ -152,7 +153,7 @@ struct Chat {
152153
let skillSet = state.buildSkillSet()
153154

154155
let selectedFiles = state.selectedFiles
155-
let selectedModelFamily = AppState.shared.getSelectedModelFamily()
156+
let selectedModelFamily = AppState.shared.getSelectedModelFamily() ?? CopilotModelManager.getDefaultChatLLM()?.modelFamily
156157

157158
return .run { _ in
158159
try await service.send(id, content: message, skillSet: skillSet, references: selectedFiles, model: selectedModelFamily)

Core/Sources/ConversationTab/ModelPicker.swift

Lines changed: 73 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import ChatService
33
import Persist
44
import ComposableArchitecture
55
import GitHubCopilotService
6+
import Combine
67

78
public let SELECTED_LLM_KEY = "selectedLLM"
89

@@ -28,6 +29,28 @@ extension AppState {
2829
}
2930
}
3031

32+
class CopilotModelManagerObservable: ObservableObject {
33+
static let shared = CopilotModelManagerObservable()
34+
35+
@Published var availableChatModels: [LLMModel] = []
36+
@Published var defaultModel: LLMModel = .init(modelName: "", modelFamily: "")
37+
private var cancellables = Set<AnyCancellable>()
38+
39+
private init() {
40+
// Initial load
41+
availableChatModels = CopilotModelManager.getAvailableChatLLMs()
42+
43+
// Setup notification to update when models change
44+
NotificationCenter.default.publisher(for: .gitHubCopilotModelsDidChange)
45+
.receive(on: DispatchQueue.main)
46+
.sink { [weak self] _ in
47+
self?.availableChatModels = CopilotModelManager.getAvailableChatLLMs()
48+
self?.defaultModel = CopilotModelManager.getDefaultChatModel()
49+
}
50+
.store(in: &cancellables)
51+
}
52+
}
53+
3154
extension CopilotModelManager {
3255
static func getAvailableChatLLMs() -> [LLMModel] {
3356
let LLMs = CopilotModelManager.getAvailableLLMs()
@@ -37,26 +60,40 @@ extension CopilotModelManager {
3760
LLMModel(modelName: $0.modelName, modelFamily: $0.modelFamily)
3861
}
3962
}
63+
64+
static func getDefaultChatModel() -> LLMModel {
65+
let defaultModel = CopilotModelManager.getDefaultChatLLM()
66+
if let defaultModel = defaultModel {
67+
return LLMModel(modelName: defaultModel.modelName, modelFamily: defaultModel.modelFamily)
68+
}
69+
// Fallback to a hardcoded default if no model has isChatDefault = true
70+
return LLMModel(modelName: "GPT-4.1 (Preview)", modelFamily: "gpt-4.1")
71+
}
4072
}
4173

4274
struct LLMModel: Codable, Hashable {
4375
let modelName: String
4476
let modelFamily: String
4577
}
4678

47-
let defaultModel = LLMModel(modelName: "GPT-4o", modelFamily: "gpt-4o")
4879
struct ModelPicker: View {
49-
@State private var selectedModel = defaultModel.modelName
80+
@State private var selectedModel = ""
5081
@State private var isHovered = false
5182
@State private var isPressed = false
83+
@ObservedObject private var modelManager = CopilotModelManagerObservable.shared
5284
static var lastRefreshModelsTime: Date = .init(timeIntervalSince1970: 0)
5385

5486
init() {
55-
self.updateCurrentModel()
87+
let initialModel = AppState.shared.getSelectedModelName() ?? CopilotModelManager.getDefaultChatModel().modelName
88+
self._selectedModel = State(initialValue: initialModel)
5689
}
5790

5891
var models: [LLMModel] {
59-
CopilotModelManager.getAvailableChatLLMs()
92+
modelManager.availableChatModels
93+
}
94+
95+
var defaultModel: LLMModel {
96+
modelManager.defaultModel
6097
}
6198

6299
func updateCurrentModel() {
@@ -65,44 +102,48 @@ struct ModelPicker: View {
65102

66103
var body: some View {
67104
WithPerceptionTracking {
68-
Menu(selectedModel) {
69-
if models.isEmpty {
70-
Button {
71-
// No action needed
72-
} label: {
73-
Text("Loading...")
74-
}
75-
} else {
76-
ForEach(models, id: \.self) { option in
77-
Button {
78-
selectedModel = option.modelName
79-
AppState.shared.setSelectedModel(option)
80-
} label: {
81-
if selectedModel == option.modelName {
82-
Text("\(option.modelName)")
83-
} else {
84-
Text(" \(option.modelName)")
105+
Group {
106+
if !models.isEmpty && !selectedModel.isEmpty {
107+
Menu(selectedModel) {
108+
ForEach(models, id: \.self) { option in
109+
Button {
110+
selectedModel = option.modelName
111+
AppState.shared.setSelectedModel(option)
112+
} label: {
113+
if selectedModel == option.modelName {
114+
Text("\(option.modelName)")
115+
} else {
116+
Text(" \(option.modelName)")
117+
}
85118
}
86119
}
87120
}
121+
.menuStyle(BorderlessButtonMenuStyle())
122+
.frame(maxWidth: labelWidth())
123+
.padding(4)
124+
.background(
125+
RoundedRectangle(cornerRadius: 5)
126+
.fill(isHovered ? Color.gray.opacity(0.1) : Color.clear)
127+
)
128+
.onHover { hovering in
129+
isHovered = hovering
130+
}
131+
} else {
132+
EmptyView()
88133
}
89134
}
90-
.menuStyle(BorderlessButtonMenuStyle())
91-
.frame(maxWidth: labelWidth())
92-
.padding(4)
93-
.background(
94-
RoundedRectangle(cornerRadius: 5)
95-
.fill(isHovered ? Color.gray.opacity(0.1) : Color.clear)
96-
)
97-
.onHover { hovering in
98-
isHovered = hovering
99-
}
100135
.onAppear() {
101-
updateCurrentModel()
102136
Task {
103137
await refreshModels()
138+
updateCurrentModel()
104139
}
105140
}
141+
.onChange(of: defaultModel) { _ in
142+
updateCurrentModel()
143+
}
144+
.onChange(of: models) { _ in
145+
updateCurrentModel()
146+
}
106147
.help("Pick Model")
107148
}
108149
}

ExtensionService/AppDelegate.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,10 +258,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
258258

259259
func forceAuthStatusCheck() async {
260260
do {
261-
let service = try GitHubCopilotService()
261+
let service = try await GitHubCopilotViewModel.shared.getGitHubCopilotAuthService()
262262
_ = try await service.checkStatus()
263-
try await service.shutdown()
264-
try await service.exit()
265263
} catch {
266264
Logger.service.error("Failed to read auth status: \(error)")
267265
}

Server/package-lock.json

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

Server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
"description": "Package for downloading @github/copilot-language-server",
55
"private": true,
66
"dependencies": {
7-
"@github/copilot-language-server": "^1.298.0"
7+
"@github/copilot-language-server": "^1.310.0"
88
}
99
}

Tool/Sources/ConversationServiceProvider/LSPTypes.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public struct ChatTemplate: Codable, Equatable {
1717
public enum PromptTemplateScope: String, Codable, Equatable {
1818
case chatPanel = "chat-panel"
1919
case editPanel = "edit-panel"
20+
case agentPanel = "agent-panel"
2021
case editor = "editor"
2122
case inline = "inline"
2223
case completion = "completion"
@@ -37,13 +38,30 @@ public struct CopilotModel: Codable, Equatable {
3738
public let modelPolicy: CopilotModelPolicy?
3839
public let scopes: [PromptTemplateScope]
3940
public let preview: Bool
41+
public let isChatDefault: Bool
42+
public let isChatFallback: Bool
43+
public let capabilities: CopilotModelCapabilities
44+
public let billing: CopilotModelBilling?
4045
}
4146

4247
public struct CopilotModelPolicy: Codable, Equatable {
4348
public let state: String
4449
public let terms: String
4550
}
4651

52+
public struct CopilotModelCapabilities: Codable, Equatable {
53+
public let supports: CopilotModelCapabilitiesSupports
54+
}
55+
56+
public struct CopilotModelCapabilitiesSupports: Codable, Equatable {
57+
public let vision: Bool
58+
}
59+
60+
public struct CopilotModelBilling: Codable, Equatable {
61+
public let isPremium: Bool
62+
public let multiplier: Float
63+
}
64+
4765
// MARK: Conversation Agents
4866
public struct ChatAgent: Codable, Equatable {
4967
public let slug: String

Tool/Sources/GitHubCopilotService/GitHubCopilotExtension.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public final class GitHubCopilotExtension: BuiltinExtension {
6464
guard let service = await serviceLocator.getService(from: workspace) else { return }
6565
try await service.notifyOpenTextDocument(fileURL: documentURL, content: content)
6666
} catch {
67-
Logger.gitHubCopilot.error(error.localizedDescription)
67+
Logger.gitHubCopilot.info(error.localizedDescription)
6868
}
6969
}
7070
}
@@ -76,7 +76,7 @@ public final class GitHubCopilotExtension: BuiltinExtension {
7676
guard let service = await serviceLocator.getService(from: workspace) else { return }
7777
try await service.notifySaveTextDocument(fileURL: documentURL)
7878
} catch {
79-
Logger.gitHubCopilot.error(error.localizedDescription)
79+
Logger.gitHubCopilot.info(error.localizedDescription)
8080
}
8181
}
8282
}
@@ -88,7 +88,7 @@ public final class GitHubCopilotExtension: BuiltinExtension {
8888
guard let service = await serviceLocator.getService(from: workspace) else { return }
8989
try await service.notifyCloseTextDocument(fileURL: documentURL)
9090
} catch {
91-
Logger.gitHubCopilot.error(error.localizedDescription)
91+
Logger.gitHubCopilot.info(error.localizedDescription)
9292
}
9393
}
9494
}
@@ -122,10 +122,10 @@ public final class GitHubCopilotExtension: BuiltinExtension {
122122
// Reopen document if it's not found in the language server
123123
self.workspace(workspace, didOpenDocumentAt: documentURL)
124124
default:
125-
Logger.gitHubCopilot.error(error.localizedDescription)
125+
Logger.gitHubCopilot.info(error.localizedDescription)
126126
}
127127
} catch {
128-
Logger.gitHubCopilot.error(error.localizedDescription)
128+
Logger.gitHubCopilot.info(error.localizedDescription)
129129
}
130130
}
131131
}
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
import ConversationServiceProvider
2+
import Foundation
3+
4+
public extension Notification.Name {
5+
static let gitHubCopilotModelsDidChange = Notification
6+
.Name("com.github.CopilotForXcode.CopilotModelsDidChange")
7+
}
28

39
public class CopilotModelManager {
410
private static var availableLLMs: [CopilotModel] = []
511

612
public static func updateLLMs(_ models: [CopilotModel]) {
7-
availableLLMs = models
13+
availableLLMs = models.sorted(by: { $0.modelName.lowercased() < $1.modelName.lowercased()})
14+
NotificationCenter.default.post(name: .gitHubCopilotModelsDidChange, object: nil)
815
}
916

1017
public static func getAvailableLLMs() -> [CopilotModel] {
1118
return availableLLMs
1219
}
1320

21+
public static func getDefaultChatLLM() -> CopilotModel? {
22+
return availableLLMs.first(where: { $0.isChatDefault })
23+
}
24+
1425
public static func hasLLMs() -> Bool {
1526
return !availableLLMs.isEmpty
1627
}
1728

1829
public static func clearLLMs() {
1930
availableLLMs = []
31+
NotificationCenter.default.post(name: .gitHubCopilotModelsDidChange, object: nil)
2032
}
2133
}

Tool/Sources/GitHubCopilotService/LanguageServer/GitHubCopilotService.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,7 @@ public final class GitHubCopilotService:
739739
if status.status == .ok || status.status == .maybeOk {
740740
await Status.shared.updateAuthStatus(.loggedIn, username: status.user)
741741
if !CopilotModelManager.hasLLMs() {
742+
Logger.gitHubCopilot.info("No models found, fetching models...")
742743
let models = try? await models()
743744
if let models = models, !models.isEmpty {
744745
CopilotModelManager.updateLLMs(models)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy