@@ -18,7 +18,7 @@ import SystemUtils
18
18
19
19
public protocol ChatServiceType {
20
20
var memory : ContextAwareAutoManagedChatMemory { get set }
21
- func send( _ id: String , content: String , skillSet: [ ConversationSkill ] , references: [ FileReference ] , model: String ? , agentMode: Bool , userLanguage: String ? , turnId: String ? ) async throws
21
+ func send( _ id: String , content: String , contentImages : [ ChatCompletionContentPartImage ] , contentImageReferences : [ ImageReference ] , skillSet: [ ConversationSkill ] , references: [ FileReference ] , model: String ? , agentMode: Bool , userLanguage: String ? , turnId: String ? ) async throws
22
22
func stopReceivingMessage( ) async
23
23
func upvote( _ id: String , _ rating: ConversationRating ) async
24
24
func downvote( _ id: String , _ rating: ConversationRating ) async
@@ -316,10 +316,23 @@ public final class ChatService: ChatServiceType, ObservableObject {
316
316
}
317
317
}
318
318
}
319
+
320
+ public enum ChatServiceError : Error , LocalizedError {
321
+ case conflictingImageFormats( String )
322
+
323
+ public var errorDescription : String ? {
324
+ switch self {
325
+ case . conflictingImageFormats( let message) :
326
+ return message
327
+ }
328
+ }
329
+ }
319
330
320
331
public func send(
321
332
_ id: String ,
322
333
content: String ,
334
+ contentImages: Array < ChatCompletionContentPartImage > = [ ] ,
335
+ contentImageReferences: Array < ImageReference > = [ ] ,
323
336
skillSet: Array < ConversationSkill > ,
324
337
references: Array < FileReference > ,
325
338
model: String ? = nil ,
@@ -331,11 +344,31 @@ public final class ChatService: ChatServiceType, ObservableObject {
331
344
let workDoneToken = UUID ( ) . uuidString
332
345
activeRequestId = workDoneToken
333
346
347
+ let finalImageReferences : [ ImageReference ]
348
+ let finalContentImages : [ ChatCompletionContentPartImage ]
349
+
350
+ if !contentImageReferences. isEmpty {
351
+ // User attached images are all parsed as ImageReference
352
+ finalImageReferences = contentImageReferences
353
+ finalContentImages = contentImageReferences
354
+ . map {
355
+ ChatCompletionContentPartImage (
356
+ url: $0. dataURL ( imageType: $0. source == . screenshot ? " png " : " " )
357
+ )
358
+ }
359
+ } else {
360
+ // In current implementation, only resend message will have contentImageReferences
361
+ // No need to convert ChatCompletionContentPartImage to ImageReference for persistence
362
+ finalImageReferences = [ ]
363
+ finalContentImages = contentImages
364
+ }
365
+
334
366
var chatMessage = ChatMessage (
335
367
id: id,
336
368
chatTabID: self . chatTabInfo. id,
337
369
role: . user,
338
370
content: content,
371
+ contentImageReferences: finalImageReferences,
339
372
references: references. toConversationReferences ( )
340
373
)
341
374
@@ -406,6 +439,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
406
439
let request = createConversationRequest (
407
440
workDoneToken: workDoneToken,
408
441
content: content,
442
+ contentImages: finalContentImages,
409
443
activeDoc: activeDoc,
410
444
references: references,
411
445
model: model,
@@ -417,12 +451,13 @@ public final class ChatService: ChatServiceType, ObservableObject {
417
451
418
452
self . lastUserRequest = request
419
453
self . skillSet = validSkillSet
420
- try await send ( request)
454
+ try await sendConversationRequest ( request)
421
455
}
422
456
423
457
private func createConversationRequest(
424
458
workDoneToken: String ,
425
459
content: String ,
460
+ contentImages: [ ChatCompletionContentPartImage ] = [ ] ,
426
461
activeDoc: Doc ? ,
427
462
references: [ FileReference ] ,
428
463
model: String ? = nil ,
@@ -443,6 +478,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
443
478
return ConversationRequest (
444
479
workDoneToken: workDoneToken,
445
480
content: newContent,
481
+ contentImages: contentImages,
446
482
workspaceFolder: " " ,
447
483
activeDoc: activeDoc,
448
484
skills: skillCapabilities,
@@ -504,6 +540,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
504
540
try await send (
505
541
id,
506
542
content: lastUserRequest. content,
543
+ contentImages: lastUserRequest. contentImages,
507
544
skillSet: skillSet,
508
545
references: lastUserRequest. references ?? [ ] ,
509
546
model: model != nil ? model : lastUserRequest. model,
@@ -720,12 +757,14 @@ public final class ChatService: ChatServiceType, ObservableObject {
720
757
await Status . shared
721
758
. updateCLSStatus ( . warning, busy: false , message: CLSError . message)
722
759
let errorMessage = buildErrorMessage (
723
- turnId: progress. turnId,
760
+ turnId: progress. turnId,
724
761
panelMessages: [ . init( type: . error, title: String ( CLSError . code ?? 0 ) , message: CLSError . message, location: . Panel) ] )
725
762
// will persist in resetongoingRequest()
726
763
await memory. appendMessage ( errorMessage)
727
764
728
- if let lastUserRequest {
765
+ if let lastUserRequest,
766
+ let currentUserPlan = await Status . shared. currentUserPlan ( ) ,
767
+ currentUserPlan != " free " {
729
768
guard let fallbackModel = CopilotModelManager . getFallbackLLM (
730
769
scope: lastUserRequest. agentMode ? . agentPanel : . chatPanel
731
770
) else {
@@ -852,7 +891,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
852
891
}
853
892
}
854
893
855
- private func send ( _ request: ConversationRequest ) async throws {
894
+ private func sendConversationRequest ( _ request: ConversationRequest ) async throws {
856
895
guard !isReceivingMessage else { throw CancellationError ( ) }
857
896
isReceivingMessage = true
858
897
@@ -892,7 +931,7 @@ public final class ChatService: ChatServiceType, ObservableObject {
892
931
893
932
switch fileEdit. toolName {
894
933
case . insertEditIntoFile:
895
- try InsertEditIntoFileTool . applyEdit ( for: fileURL, content: fileEdit. originalContent, contextProvider: self )
934
+ InsertEditIntoFileTool . applyEdit ( for: fileURL, content: fileEdit. originalContent, contextProvider: self )
896
935
case . createFile:
897
936
try CreateFileTool . undo ( for: fileURL)
898
937
default :
0 commit comments