Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitb9029ca

Browse files
committed
Pre-release 0.31.105
1 parent090e1e6 commitb9029ca

File tree

49 files changed

+1285
-362
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1285
-362
lines changed

‎Core/Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ let package = Package(
191191
.product(name:"Cache",package:"Tool"),
192192
.product(name:"MarkdownUI",package:"swift-markdown-ui"),
193193
.product(name:"ComposableArchitecture",package:"swift-composable-architecture"),
194-
.product(name:"SwiftUIFlowLayout",package:"swiftui-flow-layout")
194+
.product(name:"SwiftUIFlowLayout",package:"swiftui-flow-layout"),
195+
.product(name:"Persist",package:"Tool")
195196
]
196197
),
197198
.testTarget(

‎Core/Sources/ChatService/ChatService.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Status
1010

1111
publicprotocolChatServiceType{
1212
varmemory:ContextAwareAutoManagedChatMemory{getset}
13-
func send(_ id:String, content:String, skillSet:[ConversationSkill], references:[FileReference])asyncthrows
13+
func send(_ id:String, content:String, skillSet:[ConversationSkill], references:[FileReference], model:String?)asyncthrows
1414
func stopReceivingMessage()async
1515
func upvote(_ id:String, _ rating:ConversationRating)async
1616
func downvote(_ id:String, _ rating:ConversationRating)async
@@ -82,7 +82,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
8282
returnChatService(provider: provider)
8383
}
8484

85-
publicfunc send(_ id:String, content:String, skillSet:Array<ConversationSkill>, references:Array<FileReference>)asyncthrows{
85+
publicfunc send(_ id:String, content:String, skillSet:Array<ConversationSkill>, references:Array<FileReference>, model:String?=nil)asyncthrows{
8686
guard activeRequestId==nilelse{return}
8787
letworkDoneToken=UUID().uuidString
8888
activeRequestId= workDoneToken
@@ -115,7 +115,8 @@ public final class ChatService: ChatServiceType, ObservableObject {
115115
workspaceFolder:"",
116116
skills: skillCapabilities,
117117
ignoredSkills: ignoredSkills,
118-
references: references)
118+
references: references,
119+
model: model)
119120
self.skillSet= skillSet
120121
tryawaitsend(request)
121122
}
@@ -258,6 +259,11 @@ public final class ChatService: ChatServiceType, ObservableObject {
258259
returnnil
259260
}
260261

262+
publicfunc copilotModels()async->[CopilotModel]{
263+
guardlet models=try?await conversationProvider?.models()else{return[]}
264+
return models
265+
}
266+
261267
publicfunc handleSingleRoundDialogCommand(
262268
systemPrompt:String?,
263269
overwriteSystemPrompt:Bool,
@@ -334,6 +340,16 @@ public final class ChatService: ChatServiceType, ObservableObject {
334340
await memory.removeMessage(progress.turnId)
335341
await memory.appendMessage(errorMessage)
336342
}
343+
}elseifCLSError.code==400 &&CLSError.message.contains("model is not supported"){
344+
Task{
345+
leterrorMessage=ChatMessage(
346+
id: progress.turnId,
347+
role:.assistant,
348+
content:"",
349+
errorMessage:"Oops, the model is not supported. Please enable it first in [GitHub Copilot settings](https://github.com/settings/copilot)."
350+
)
351+
await memory.appendMessage(errorMessage)
352+
}
337353
}else{
338354
Task{
339355
leterrorMessage=ChatMessage(

‎Core/Sources/ConversationTab/Chat.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import ChatAPIService
55
import Preferences
66
import Terminal
77
import ConversationServiceProvider
8+
import Persist
89

910
publicstructDisplayedChatMessage:Equatable{
1011
publicenumRole:Equatable{
@@ -140,19 +141,20 @@ struct Chat {
140141
state.typedMessage=""
141142

142143
letselectedFiles= state.selectedFiles
143-
144+
letselectedModelFamily=AppState.shared.getSelectedModelFamily()
144145
return.run{ _in
145-
tryawait service.send(id, content: message, skillSet: skillSet, references: selectedFiles)
146+
tryawait service.send(id, content: message, skillSet: skillSet, references: selectedFiles, model: selectedModelFamily)
146147
}.cancellable(id:CancelID.sendMessage(self.id))
147148

148149
caselet.followUpButtonClicked(id, message):
149150
guard !message.isEmptyelse{return.none}
150151
letskillSet= state.buildSkillSet()
151152

152153
letselectedFiles= state.selectedFiles
154+
letselectedModelFamily=AppState.shared.getSelectedModelFamily()
153155

154156
return.run{ _in
155-
tryawait service.send(id, content: message, skillSet: skillSet, references: selectedFiles)
157+
tryawait service.send(id, content: message, skillSet: skillSet, references: selectedFiles, model: selectedModelFamily)
156158
}.cancellable(id:CancelID.sendMessage(self.id))
157159

158160
case.returnButtonTapped:

‎Core/Sources/ConversationTab/ChatPanel.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public struct ChatPanel: View {
3131
}else{
3232
ChatPanelMessages(chat: chat)
3333
.accessibilityElement(children:.combine)
34-
.accessibilityLabel("ChatMesessages Group")
34+
.accessibilityLabel("ChatMessages Group")
3535

3636
if chat.history.last?.role==.system{
3737
ChatCLSError(chat: chat).padding(.trailing,16)
@@ -567,6 +567,7 @@ struct ChatPanelInputArea: View {
567567

568568
Spacer()
569569

570+
ModelPicker()
570571
Button(action:{
571572
submitChatMessage()
572573
}){
@@ -676,7 +677,7 @@ struct ChatPanelInputArea: View {
676677
id:"releaseNotes",
677678
description:"What's New",
678679
shortDescription:"What's New",
679-
scopes:[ChatPromptTemplateScope.chatPanel]
680+
scopes:[PromptTemplateScope.chatPanel]
680681
)
681682

682683
guard !promptTemplates.isEmptyelse{

‎Core/Sources/ConversationTab/ChatTemplateDropdownView.swift

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import ConversationServiceProvider
22
import AppKit
33
import SwiftUI
4+
import ComposableArchitecture
45

56
publicstructChatTemplateDropdownView:View{
67
@Bindingvartemplates:[ChatTemplate]
@@ -10,76 +11,78 @@ public struct ChatTemplateDropdownView: View {
1011
@StateprivatevarlocalMonitor:Any?=nil
1112

1213
publicvarbody:someView{
13-
VStack(alignment:.leading, spacing:0){
14-
ForEach(Array(templates.enumerated()), id: \.element.id){ index, templatein
15-
HStack{
16-
Text("/"+ template.id)
17-
.hoverPrimaryForeground(isHovered: selectedIndex== index)
18-
Spacer()
19-
Text(template.shortDescription)
20-
.hoverSecondaryForeground(isHovered: selectedIndex== index)
21-
}
22-
.padding(.horizontal,8)
23-
.padding(.vertical,6)
24-
.contentShape(Rectangle())
25-
.onTapGesture{
26-
onSelect(template)
27-
}
28-
.hoverBackground(isHovered: selectedIndex== index)
29-
.onHover{ isHoveredin
30-
if isHovered{
31-
selectedIndex= index
14+
WithPerceptionTracking{
15+
VStack(alignment:.leading, spacing:0){
16+
ForEach(Array(templates.enumerated()), id: \.element.id){ index, templatein
17+
HStack{
18+
Text("/"+ template.id)
19+
.hoverPrimaryForeground(isHovered: selectedIndex== index)
20+
Spacer()
21+
Text(template.shortDescription)
22+
.hoverSecondaryForeground(isHovered: selectedIndex== index)
23+
}
24+
.padding(.horizontal,8)
25+
.padding(.vertical,6)
26+
.contentShape(Rectangle())
27+
.onTapGesture{
28+
onSelect(template)
29+
}
30+
.hoverBackground(isHovered: selectedIndex== index)
31+
.onHover{ isHoveredin
32+
if isHovered{
33+
selectedIndex= index
34+
}
3235
}
3336
}
3437
}
35-
}
36-
.background(
37-
GeometryReader{ geometryin
38-
Color.clear
39-
.onAppear{ frameHeight= geometry.size.height}
40-
.onChange(of: geometry.size.height){ newHeightin
41-
frameHeight= newHeight
42-
}
38+
.background(
39+
GeometryReader{ geometryin
40+
Color.clear
41+
.onAppear{ frameHeight= geometry.size.height}
42+
.onChange(of: geometry.size.height){ newHeightin
43+
frameHeight= newHeight
44+
}
45+
}
46+
)
47+
.background(.ultraThickMaterial)
48+
.cornerRadius(6)
49+
.shadow(radius:2)
50+
.overlay(
51+
RoundedRectangle(cornerRadius:6)
52+
.stroke(Color(nsColor:.separatorColor), lineWidth:1)
53+
)
54+
.frame(maxWidth:.infinity)
55+
.offset(y:-1* frameHeight)
56+
.onChange(of: templates){ _in
57+
selectedIndex=0
4358
}
44-
)
45-
.background(.ultraThickMaterial)
46-
.cornerRadius(6)
47-
.shadow(radius:2)
48-
.overlay(
49-
RoundedRectangle(cornerRadius:6)
50-
.stroke(Color(nsColor:.separatorColor), lineWidth:1)
51-
)
52-
.frame(maxWidth:.infinity)
53-
.offset(y:-1* frameHeight)
54-
.onChange(of: templates){ _in
55-
selectedIndex=0
56-
}
57-
.onAppear{
58-
selectedIndex=0
59-
localMonitor=NSEvent.addLocalMonitorForEvents(matching:.keyDown){ eventin
60-
switch event.keyCode{
61-
case126: // Up arrow
62-
moveSelection(up:true)
63-
returnnil
64-
case125: // Down arrow
65-
moveSelection(up:false)
66-
returnnil
67-
case36: // Return key
68-
handleEnter()
69-
returnnil
70-
case48: // Tab key
71-
handleTab()
72-
returnnil // not forwarding the Tab Event which will replace the typed message to "\t"
73-
default:
74-
break
59+
.onAppear{
60+
selectedIndex=0
61+
localMonitor=NSEvent.addLocalMonitorForEvents(matching:.keyDown){ eventin
62+
switch event.keyCode{
63+
case126: // Up arrow
64+
moveSelection(up:true)
65+
returnnil
66+
case125: // Down arrow
67+
moveSelection(up:false)
68+
returnnil
69+
case36: // Return key
70+
handleEnter()
71+
returnnil
72+
case48: // Tab key
73+
handleTab()
74+
returnnil // not forwarding the Tab Event which will replace the typed message to "\t"
75+
default:
76+
break
77+
}
78+
return event
7579
}
76-
return event
7780
}
78-
}
79-
.onDisappear{
80-
iflet monitor= localMonitor{
81-
NSEvent.removeMonitor(monitor)
82-
localMonitor=nil
81+
.onDisappear{
82+
iflet monitor= localMonitor{
83+
NSEvent.removeMonitor(monitor)
84+
localMonitor=nil
85+
}
8386
}
8487
}
8588
}

‎Core/Sources/ConversationTab/ContextUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import XcodeInspector
33
import Foundation
44
import Logger
55

6-
publicletsupportedFileExtensions:Set<String>=["swift","m","mm","h","cpp","c","js","py","rb","java","applescript","scpt","plist","entitlements"]
6+
publicletsupportedFileExtensions:Set<String>=["swift","m","mm","h","cpp","c","js","py","rb","java","applescript","scpt","plist","entitlements","md","json","xml","txt","yaml","yml"]
77
privateletskipPatterns:[String]=[
88
".git",
99
".svn",
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import SwiftUI
2+
import ChatService
3+
import Persist
4+
import ComposableArchitecture
5+
6+
publicletSELECTED_LLM_KEY="selectedLLM"
7+
8+
extensionAppState{
9+
func getSelectedModelFamily()->String?{
10+
iflet savedModel=get(key: SELECTED_LLM_KEY),
11+
let modelFamily=savedModel["modelFamily"]?.stringValue{
12+
return modelFamily
13+
}
14+
returnnil
15+
}
16+
17+
func getSelectedModelName()->String?{
18+
iflet savedModel=get(key: SELECTED_LLM_KEY),
19+
let modelName=savedModel["modelName"]?.stringValue{
20+
return modelName
21+
}
22+
returnnil
23+
}
24+
25+
func setSelectedModel(_ model:LLMModel){
26+
update(key: SELECTED_LLM_KEY, value: model)
27+
}
28+
}
29+
30+
structLLMModel:Codable,Hashable{
31+
letmodelName:String
32+
letmodelFamily:String
33+
}
34+
35+
letdefaultModel=LLMModel(modelName:"GPT-4o", modelFamily:"gpt-4o")
36+
structModelPicker:View{
37+
@StateprivatevarselectedModel= defaultModel.modelName
38+
@Stateprivatevarmodels:[LLMModel]=[ defaultModel]
39+
@StateprivatevarisHovered=false
40+
@StateprivatevarisPressed=false
41+
42+
init(){
43+
self.updateCurrentModel()
44+
}
45+
46+
func updateCurrentModel(){
47+
selectedModel=AppState.shared.getSelectedModelName()?? defaultModel.modelName
48+
}
49+
50+
varbody:someView{
51+
WithPerceptionTracking{
52+
Menu(selectedModel){
53+
ForEach(models, id: \.self){ optionin
54+
Button{
55+
selectedModel= option.modelName
56+
AppState.shared.setSelectedModel(option)
57+
} label:{
58+
if selectedModel== option.modelName{
59+
Text("\(option.modelName)")
60+
}else{
61+
Text("\(option.modelName)")
62+
}
63+
}
64+
}
65+
}
66+
.menuStyle(BorderlessButtonMenuStyle())
67+
.frame(maxWidth:labelWidth())
68+
.padding(4)
69+
.background(
70+
RoundedRectangle(cornerRadius:5)
71+
.fill(isHovered?Color.gray.opacity(0.1):Color.clear)
72+
)
73+
.onHover{ hoveringin
74+
isHovered= hovering
75+
}
76+
.onAppear(){
77+
Task{
78+
updateCurrentModel()
79+
self.models=awaitChatService.shared.copilotModels().filter(
80+
{ $0.scopes.contains(.chatPanel)}
81+
).map{
82+
LLMModel(modelName: $0.modelName, modelFamily: $0.modelFamily)
83+
}
84+
}
85+
}
86+
.help("Pick Model")
87+
}
88+
}
89+
90+
func labelWidth()->CGFloat{
91+
letfont=NSFont.systemFont(ofSize:NSFont.systemFontSize)
92+
letattributes=[NSAttributedString.Key.font: font]
93+
letwidth= selectedModel.size(withAttributes: attributes).width
94+
returnCGFloat(width+20)
95+
}
96+
}
97+
98+
structModelPicker_Previews:PreviewProvider{
99+
staticvarpreviews:someView{
100+
ModelPicker()
101+
}
102+
}

‎Core/Sources/ConversationTab/Views/BotMessage.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,7 @@ struct BotMessage: View {
120120
if errorMessage!=nil{
121121
HStack(spacing:4){
122122
Image(systemName:"info.circle")
123-
Text(errorMessage!)
124-
.font(.system(size: chatFontSize))
123+
ThemedMarkdownText(text: errorMessage!, chat: chat)
125124
}
126125
}
127126

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp