@@ -245,14 +245,19 @@ struct ChatHistory: View {
245245 ) )
246246 . padding ( . vertical, 4 )
247247 case . assistant:
248- BotMessage ( id: message. id, text: text, chat: chat)
249- . listRowInsets ( EdgeInsets (
250- top: 0 ,
251- leading: - 8 ,
252- bottom: 0 ,
253- trailing: - 8
254- ) )
255- . padding ( . vertical, 4 )
248+ BotMessage (
249+ id: message. id,
250+ text: text,
251+ references: message. references,
252+ chat: chat
253+ )
254+ . listRowInsets ( EdgeInsets (
255+ top: 0 ,
256+ leading: - 8 ,
257+ bottom: 0 ,
258+ trailing: - 8
259+ ) )
260+ . padding ( . vertical, 4 )
256261 case . function:
257262 FunctionMessage ( id: message. id, text: text)
258263 case . ignored:
@@ -427,50 +432,82 @@ private struct UserMessage: View {
427432private struct BotMessage : View {
428433 let id : String
429434 let text : String
435+ let references : [ DisplayedChatMessage . Reference ]
430436 let chat : StoreOf < Chat >
431437 @Environment ( \. colorScheme) var colorScheme
432438 @AppStorage ( \. chatFontSize) var chatFontSize
433439 @AppStorage ( \. chatCodeFontSize) var chatCodeFontSize
434440
441+ @State var isReferencesPresented = false
442+ @State var isReferencesHovered = false
443+
435444 var body : some View {
436445 HStack ( alignment: . bottom, spacing: 2 ) {
437- Markdown ( text)
438- . textSelection ( . enabled)
439- . markdownTheme ( . custom( fontSize: chatFontSize) )
440- . markdownCodeSyntaxHighlighter (
441- ChatCodeSyntaxHighlighter (
442- brightMode: colorScheme != . dark,
443- fontSize: chatCodeFontSize
444- )
445- )
446- . frame ( alignment: . trailing)
447- . padding ( )
448- . background {
449- RoundedCorners ( tl: r, tr: r, bl: 0 , br: r)
450- . fill ( Color . contentBackground)
446+ VStack ( alignment: . leading, spacing: 16 ) {
447+ if !references. isEmpty {
448+ Button ( action: {
449+ isReferencesPresented. toggle ( )
450+ } , label: {
451+ HStack ( spacing: 4 ) {
452+ Image ( systemName: " plus.circle " )
453+ Text ( " Used \( references. count) references " )
454+ }
455+ . padding ( 8 )
456+ . background {
457+ RoundedRectangle ( cornerRadius: r - 4 )
458+ . foregroundStyle ( Color ( isReferencesHovered ? . black : . clear) )
459+
460+ }
461+ . overlay {
462+ RoundedRectangle ( cornerRadius: r - 4 )
463+ . stroke ( Color ( nsColor: . separatorColor) , lineWidth: 1 )
464+ }
465+ . foregroundStyle ( . secondary)
466+ } )
467+ . buttonStyle ( . plain)
468+ . popover ( isPresented: $isReferencesPresented, arrowEdge: . trailing) {
469+ ReferenceList ( references: references)
470+ }
451471 }
452- . overlay {
453- RoundedCorners ( tl: r, tr: r, bl: 0 , br: r)
454- . stroke ( Color ( nsColor: . separatorColor) , lineWidth: 1 )
472+
473+ Markdown ( text)
474+ . textSelection ( . enabled)
475+ . markdownTheme ( . custom( fontSize: chatFontSize) )
476+ . markdownCodeSyntaxHighlighter (
477+ ChatCodeSyntaxHighlighter (
478+ brightMode: colorScheme != . dark,
479+ fontSize: chatCodeFontSize
480+ )
481+ )
482+ }
483+ . frame ( alignment: . trailing)
484+ . padding ( )
485+ . background {
486+ RoundedCorners ( tl: r, tr: r, bl: 0 , br: r)
487+ . fill ( Color . contentBackground)
488+ }
489+ . overlay {
490+ RoundedCorners ( tl: r, tr: r, bl: 0 , br: r)
491+ . stroke ( Color ( nsColor: . separatorColor) , lineWidth: 1 )
492+ }
493+ . padding ( . leading, 8 )
494+ . shadow ( color: . black. opacity ( 0.1 ) , radius: 2 )
495+ . contextMenu {
496+ Button ( " Copy " ) {
497+ NSPasteboard . general. clearContents ( )
498+ NSPasteboard . general. setString ( text, forType: . string)
455499 }
456- . padding ( . leading, 8 )
457- . shadow ( color: . black. opacity ( 0.1 ) , radius: 2 )
458- . contextMenu {
459- Button ( " Copy " ) {
460- NSPasteboard . general. clearContents ( )
461- NSPasteboard . general. setString ( text, forType: . string)
462- }
463500
464- Button ( " Set as Extra System Prompt " ) {
465- chat. send ( . setAsExtraPromptButtonTapped( id) )
466- }
501+ Button ( " Set as Extra System Prompt " ) {
502+ chat. send ( . setAsExtraPromptButtonTapped( id) )
503+ }
467504
468- Divider ( )
505+ Divider ( )
469506
470- Button ( " Delete " ) {
471- chat. send ( . deleteMessageButtonTapped( id) )
472- }
507+ Button ( " Delete " ) {
508+ chat. send ( . deleteMessageButtonTapped( id) )
473509 }
510+ }
474511
475512 CopyButton {
476513 NSPasteboard . general. clearContents ( )
@@ -482,6 +519,26 @@ private struct BotMessage: View {
482519 }
483520}
484521
522+ struct ReferenceList : View {
523+ let references : [ DisplayedChatMessage . Reference ]
524+ var body : some View {
525+ ScrollView {
526+ VStack {
527+ ForEach ( 0 ..< references. endIndex, id: \. self) { index in
528+ let reference = references [ index]
529+ HStack ( spacing: 8 ) {
530+ Text ( reference. title)
531+ Text ( reference. subtitle)
532+ . foregroundStyle ( . secondary)
533+ }
534+ }
535+ }
536+ . padding ( )
537+ . frame ( maxHeight: 500 )
538+ }
539+ }
540+ }
541+
485542struct FunctionMessage : View {
486543 let id : String
487544 let text : String
@@ -539,7 +596,8 @@ struct ChatPanelInputArea: View {
539596 chat,
540597 removeDuplicates: {
541598 $0. typedMessage == $1. typedMessage && $0. focusedField == $1. focusedField
542- } ) { viewStore in
599+ }
600+ ) { viewStore in
543601 AutoresizingCustomTextEditor (
544602 text: viewStore. $typedMessage,
545603 font: . systemFont( ofSize: 14 ) ,
@@ -680,7 +738,8 @@ struct ChatPanel_Preview: PreviewProvider {
680738 . init(
681739 id: " 1 " ,
682740 role: . user,
683- text: " **Hello** "
741+ text: " **Hello** " ,
742+ references: [ ]
684743 ) ,
685744 . init(
686745 id: " 2 " ,
@@ -690,18 +749,45 @@ struct ChatPanel_Preview: PreviewProvider {
690749 func foo() {}
691750 ```
692751 **Hey**! What can I do for you?**Hey**! What can I do for you?**Hey**! What can I do for you?**Hey**! What can I do for you?
693- """
752+ """ ,
753+ references: [
754+ . init(
755+ title: " Hello Hello Hello Hello " ,
756+ subtitle: " Hi Hi Hi Hi " ,
757+ uri: " https://google.com "
758+ ) ,
759+ ]
760+ ) ,
761+ . init(
762+ id: " 7 " ,
763+ role: . ignored,
764+ text: " Ignored " ,
765+ references: [ ]
766+ ) ,
767+ . init(
768+ id: " 6 " ,
769+ role: . function,
770+ text: """
771+ Searching for something...
772+ - abc
773+ - [def](https://1.com)
774+ > hello
775+ > hi
776+ """ ,
777+ references: [ ]
778+ ) ,
779+ . init(
780+ id: " 5 " ,
781+ role: . assistant,
782+ text: " Yooo " ,
783+ references: [ ]
784+ ) ,
785+ . init(
786+ id: " 4 " ,
787+ role: . user,
788+ text: " Yeeeehh " ,
789+ references: [ ]
694790 ) ,
695- . init( id: " 7 " , role: . ignored, text: " Ignored " ) ,
696- . init( id: " 6 " , role: . function, text: """
697- Searching for something...
698- - abc
699- - [def](https://1.com)
700- > hello
701- > hi
702- """ ) ,
703- . init( id: " 5 " , role: . assistant, text: " Yooo " ) ,
704- . init( id: " 4 " , role: . user, text: " Yeeeehh " ) ,
705791 . init(
706792 id: " 3 " ,
707793 role: . user,
@@ -718,7 +804,8 @@ struct ChatPanel_Preview: PreviewProvider {
718804 ```objectivec
719805 - (void)bar {}
720806 ```
721- """#
807+ """# ,
808+ references: [ ]
722809 ) ,
723810 ]
724811
0 commit comments