1- import { useMemo , useCallback } from 'react' ;
1+ import { useMemo , useCallback , useState } from 'react' ;
22import { EModelEndpoint , Constants } from 'librechat-data-provider' ;
3+ import type { TModelSpec } from 'librechat-data-provider' ;
34import { useChatContext , useAgentsMapContext , useAssistantsMapContext } from '~/Providers' ;
4- import { useGetAssistantDocsQuery , useGetEndpointsQuery } from '~/data-provider' ;
5+ import {
6+ useGetAssistantDocsQuery ,
7+ useGetEndpointsQuery ,
8+ useGetStartupConfig ,
9+ } from '~/data-provider' ;
510import { getIconEndpoint , getEntity } from '~/utils' ;
611import { useSubmitMessage } from '~/hooks' ;
712
@@ -10,6 +15,8 @@ const ConversationStarters = () => {
1015 const agentsMap = useAgentsMapContext ( ) ;
1116 const assistantMap = useAssistantsMapContext ( ) ;
1217 const { data : endpointsConfig } = useGetEndpointsQuery ( ) ;
18+ const { data : startupConfig } = useGetStartupConfig ( ) ;
19+ const [ showExamples , setShowExamples ] = useState ( false ) ;
1320
1421 const endpointType = useMemo ( ( ) => {
1522 let ep = conversation ?. endpoint ?? '' ;
@@ -41,7 +48,31 @@ const ConversationStarters = () => {
4148 assistant_id : conversation ?. assistant_id ,
4249 } ) ;
4350
51+ const currentSpec = useMemo ( ( ) => {
52+ const specs = startupConfig ?. modelSpecs ?. list ?? [ ] ;
53+ return specs . find (
54+ ( spec : TModelSpec ) =>
55+ spec . name === conversation ?. spec || spec . preset ?. agent_id === conversation ?. agent_id ,
56+ ) ;
57+ } , [ startupConfig ?. modelSpecs ?. list , conversation ?. spec , conversation ?. agent_id ] ) ;
58+
59+ const conversationStarterCategories = useMemo ( ( ) => {
60+ return (
61+ currentSpec ?. conversationStarterCategories ?. filter (
62+ ( category ) => category . label && category . starters ?. length ,
63+ ) ?? [ ]
64+ ) ;
65+ } , [ currentSpec ?. conversationStarterCategories ] ) ;
66+
4467 const conversation_starters = useMemo ( ( ) => {
68+ if ( conversationStarterCategories . length ) {
69+ return [ ] ;
70+ }
71+
72+ if ( currentSpec ?. conversation_starters ?. length ) {
73+ return currentSpec . conversation_starters ;
74+ }
75+
4576 if ( entity ?. conversation_starters ?. length ) {
4677 return entity . conversation_starters ;
4778 }
@@ -51,18 +82,57 @@ const ConversationStarters = () => {
5182 }
5283
5384 return documentsMap . get ( entity ?. id ?? '' ) ?. conversation_starters ?? [ ] ;
54- } , [ documentsMap , isAgent , entity ] ) ;
85+ } , [ conversationStarterCategories . length , currentSpec , documentsMap , isAgent , entity ] ) ;
5586
5687 const { submitMessage } = useSubmitMessage ( ) ;
5788 const sendConversationStarter = useCallback (
5889 ( text : string ) => submitMessage ( { text } ) ,
5990 [ submitMessage ] ,
6091 ) ;
6192
62- if ( ! conversation_starters . length ) {
93+ if ( ! conversation_starters . length && ! conversationStarterCategories . length ) {
6394 return null ;
6495 }
6596
97+ if ( conversationStarterCategories . length ) {
98+ return (
99+ < div className = "mt-6 flex w-full max-w-5xl flex-col items-center px-4" >
100+ < button
101+ type = "button"
102+ onClick = { ( ) => setShowExamples ( ( value ) => ! value ) }
103+ className = "rounded-full border border-border-light bg-surface-secondary px-4 py-2 text-sm font-medium text-text-primary transition-colors duration-200 hover:bg-surface-tertiary"
104+ aria-expanded = { showExamples }
105+ >
106+ { showExamples ? 'Hide examples' : 'Show examples' }
107+ </ button >
108+ { showExamples && (
109+ < div className = "mt-5 grid w-full grid-cols-1 gap-4 md:grid-cols-3" >
110+ { conversationStarterCategories . map ( ( category ) => (
111+ < section key = { category . label } className = "flex min-w-0 flex-col gap-3" >
112+ < h2 className = "text-center text-sm font-medium text-text-secondary" >
113+ { category . label }
114+ </ h2 >
115+ < div className = "flex flex-col gap-2" >
116+ { category . starters . map ( ( text : string , index : number ) => (
117+ < button
118+ key = { `${ category . label } -${ index } ` }
119+ onClick = { ( ) => sendConversationStarter ( text ) }
120+ className = "relative min-h-20 w-full cursor-pointer rounded-lg border border-border-medium px-3 py-3 text-left text-sm shadow-[0_0_2px_0_rgba(0,0,0,0.05),0_4px_6px_0_rgba(0,0,0,0.02)] transition-colors duration-300 ease-in-out fade-in hover:bg-surface-tertiary"
121+ >
122+ < span className = "line-clamp-3 overflow-hidden break-words text-text-secondary" >
123+ { text }
124+ </ span >
125+ </ button >
126+ ) ) }
127+ </ div >
128+ </ section >
129+ ) ) }
130+ </ div >
131+ ) }
132+ </ div >
133+ ) ;
134+ }
135+
66136 return (
67137 < div className = "mt-8 flex flex-wrap justify-center gap-3 px-4" >
68138 { conversation_starters
0 commit comments