11import { useUpdatableState } from '../../hooks' ;
22import { useSuspenseTanQuery } from '../../hooks/reactQueryAlias' ;
3- import { AIAgent , useAIAgent } from '../../hooks/useAIAgent' ;
3+ import { useAIAgent } from '../../hooks/useAIAgent' ;
44import PureChatHeader from './ChatHeader' ;
55import PureChatInput from './ChatInput' ;
66import ChatMessages from './ChatMessages' ;
@@ -12,7 +12,7 @@ import {
1212 Model ,
1313} from './ChatModel' ;
1414import { CustomModelForm } from './CustomModelForm' ;
15- import { ChatCard_endpoint$key } from './__generated__/ChatCard_endpoint .graphql' ;
15+ import { ChatCardQuery } from './__generated__/ChatCardQuery .graphql' ;
1616import { createOpenAI } from '@ai-sdk/openai' ;
1717import { useChat } from '@ai-sdk/react' ;
1818import { extractReasoningMiddleware , streamText , wrapLanguageModel } from 'ai' ;
@@ -21,20 +21,21 @@ import { createStyles } from 'antd-style';
2121import graphql from 'babel-plugin-relay/macro' ;
2222import _ from 'lodash' ;
2323import React , {
24- startTransition ,
2524 useEffect ,
2625 useMemo ,
2726 useRef ,
2827 useState ,
2928 useTransition ,
3029} from 'react' ;
31- import { useFragment } from 'react-relay' ;
30+ import { useTranslation } from 'react-i18next' ;
31+ import { useLazyLoadQuery } from 'react-relay' ;
3232
3333interface ChatCardProps extends CardProps , ChatLifecycleEventType {
3434 chat : ChatType ;
35- selectedEndpoint : ChatCard_endpoint$key | null ;
35+ onUpdateChat ?: ( partialChat : DeepPartial < ChatType > ) => void ;
3636 closable ?: boolean ;
3737 fetchOnClient ?: boolean ;
38+ defaultEndpointId ?: string ;
3839}
3940
4041const useStyles = createStyles ( ( { token, css } ) => ( {
@@ -66,23 +67,6 @@ const useStyles = createStyles(({ token, css }) => ({
6667 ` ,
6768} ) ) ;
6869
69- function useEndpoint ( selectedEndpoint ?: ChatCard_endpoint$key | null ) {
70- const [ endpointKey , setEndpoint ] = useState < ChatCard_endpoint$key | null > (
71- selectedEndpoint || null ,
72- ) ;
73- const endpoint = useFragment (
74- graphql `
75- fragment ChatCard_endpoint on Endpoint {
76- endpoint_id
77- url
78- }
79- ` ,
80- endpointKey ,
81- ) ;
82-
83- return { endpoint, setEndpoint } as const ;
84- }
85-
8670function createModelsURL ( baseURL : string ) {
8771 const { origin, port, pathname : path } = new URL ( baseURL . trim ( ) ) ;
8872 const host = port . length > 0 ? `${ origin } :${ port } ` : origin ;
@@ -95,7 +79,6 @@ function useModels(
9579 provider : ChatProviderType ,
9680 fetchKey : string ,
9781 baseURL ?: string ,
98- token ?: string ,
9982) {
10083 const { t } = useTranslation ( ) ;
10184 const getModelsErrorMessage = ( status ?: number ) => {
@@ -116,17 +99,11 @@ function useModels(
11699 const { data : modelsResult } = useSuspenseTanQuery < {
117100 data : Array < Model > ;
118101 } > ( {
119- queryKey : [ 'models' , fetchKey , baseURL , token ] ,
102+ queryKey : [ 'models' , fetchKey , baseURL , provider . apiKey ] ,
120103 queryFn : async ( ) => {
121- try {
122- if ( baseURL ) {
123- const url = createModelsURL ( baseURL ) ;
124- const authToken = token || provider . apiKey ;
125- const res = await fetch ( url , {
126- headers : {
127- Authorization : authToken ? `Bearer ${ authToken } ` : '' ,
128- } ,
129- } ) ;
104+ if ( ! baseURL ) {
105+ return { data : [ ] } ;
106+ }
130107
131108 const url = createModelsURL ( baseURL ) ;
132109 const authToken = provider . apiKey ;
@@ -149,7 +126,7 @@ function useModels(
149126 name : m . id ,
150127 } ) ) as BAIModel [ ] ;
151128
152- const selectedModelId = useMemo (
129+ const modelId = useMemo (
153130 ( ) =>
154131 provider . modelId &&
155132 _ . includes ( _ . map ( modelsResult ?. data || [ ] , 'id' ) , provider . modelId )
@@ -158,39 +135,17 @@ function useModels(
158135 [ modelsResult ?. data , provider . modelId ] ,
159136 ) ;
160137
161- const [ modelId , setModelId ] = useState < string > ( selectedModelId ) ;
138+ const modelsError =
139+ modelsResult . error && getModelsErrorMessage ( modelsResult . error ) ;
162140
163- useEffect ( ( ) => {
164- setModelId ( selectedModelId ) ;
165- } , [ selectedModelId ] ) ;
166-
167- return { models , modelId , setModelId } as const ;
141+ return {
142+ models ,
143+ modelId ,
144+ modelsError ,
145+ } as const ;
168146}
169147
170- function useAgents ( provider : ChatProviderType ) {
171- const { agents } = useAIAgent ( ) ;
172- const [ agent , setAgent ] = useState < AIAgent | undefined > ( undefined ) ;
173-
174- const selectedAgent = useMemo ( ( ) => {
175- return agents . find ( ( a ) => a . id === provider . agentId ) ;
176- } , [ agents , provider . agentId ] ) ;
177-
178- useEffect ( ( ) => {
179- setAgent ( selectedAgent ) ;
180- } , [ selectedAgent ] ) ;
181-
182- return { agents, agent, setAgent } as const ;
183- }
184-
185- const ChatHeader = React . memo ( PureChatHeader , ( prev , next ) => {
186- if ( prev . modelId !== next . modelId ) return false ;
187- if ( prev . endpoint !== next . endpoint ) return false ;
188- if ( prev . agent !== next . agent ) return false ;
189- if ( prev . fetchKey !== next . fetchKey ) return false ;
190- if ( prev . sync !== next . sync ) return false ;
191- if ( prev . closable !== next . closable ) return false ;
192- return true ;
193- } ) ;
148+ const ChatHeader = PureChatHeader ;
194149
195150const ChatInput = React . memo ( PureChatInput ) ;
196151
@@ -200,12 +155,32 @@ function createBaseURL(basePath: string, endpointUrl?: string | null) {
200155
201156const ChatCard : React . FC < ChatCardProps > = ( {
202157 chat,
203- selectedEndpoint ,
158+ onUpdateChat ,
204159 closable,
205160 fetchOnClient,
206161 onRequestClose,
207162 onCreateNewChat,
208163} ) => {
164+ const endpointResult = useLazyLoadQuery < ChatCardQuery > (
165+ graphql `
166+ query ChatCardQuery($endpointId: UUID!) {
167+ endpoint(endpoint_id: $endpointId) @catch {
168+ endpoint_id
169+ url
170+ ...ChatHeader_Endpoint
171+ }
172+ }
173+ ` ,
174+ {
175+ endpointId : chat . provider . endpointId || '' ,
176+ } ,
177+ {
178+ fetchPolicy : chat . provider . endpointId ? 'store-or-network' : 'store-only' ,
179+ } ,
180+ ) ;
181+ const endpoint = endpointResult . endpoint . ok
182+ ? endpointResult . endpoint . value
183+ : null ;
209184 const {
210185 styles : { chatCard : chatCardStyle , alert : alertStyle , ...chatCardStyles } ,
211186 } = useStyles ( ) ;
@@ -215,19 +190,14 @@ const ChatCard: React.FC<ChatCardProps> = ({
215190 const [ fetchKey , updateFetchKey ] = useUpdatableState ( 'first' ) ;
216191 const [ startTime , setStartTime ] = useState < number | null > ( null ) ;
217192
218- const { endpoint, setEndpoint } = useEndpoint ( selectedEndpoint ) ;
219- const [ baseURL , setBaseURL ] = useState < string | undefined > (
220- createBaseURL ( chat . provider . basePath , endpoint ?. url ) ,
221- ) ;
222- const [ token , setToken ] = useState < string | undefined > ( ) ;
223- const { models, modelId, setModelId } = useModels (
193+ const baseURL = createBaseURL ( chat . provider . basePath , endpoint ?. url ) ;
194+ const { models, modelId, modelsError } = useModels (
224195 chat . provider ,
225196 fetchKey ,
226197 baseURL ,
227- token ,
228198 ) ;
229- const { agents, agent , setAgent } = useAgents ( chat . provider ) ;
230- const [ sync , setSync ] = useState ( chat . sync ) ;
199+ const { agents } = useAIAgent ( ) ;
200+ const agent = agents . find ( ( a ) => a . id === chat . provider . agentId ) ;
231201
232202 const {
233203 error,
@@ -251,7 +221,7 @@ const ChatCard: React.FC<ChatCardProps> = ({
251221 const body = JSON . parse ( init ?. body as string ) ;
252222 const provider = createOpenAI ( {
253223 baseURL : baseURL ,
254- apiKey : token || chat . provider . apiKey || 'dummy' ,
224+ apiKey : chat . provider . apiKey || 'dummy' ,
255225 } ) ;
256226 const result = streamText ( {
257227 abortSignal : init ?. signal || undefined ,
@@ -274,14 +244,6 @@ const ChatCard: React.FC<ChatCardProps> = ({
274244 } ,
275245 } ) ;
276246
277- useEffect ( ( ) => {
278- startTransition ( ( ) => {
279- setBaseURL ( createBaseURL ( chat . provider . basePath , endpoint ?. url ) ) ;
280- setToken ( undefined ) ;
281- updateFetchKey ( 'first' ) ;
282- } ) ;
283- } , [ endpoint ?. url , chat . provider . basePath , updateFetchKey ] ) ;
284-
285247 const isStreaming = status === 'streaming' || status === 'submitted' ;
286248
287249 return (
@@ -291,37 +253,74 @@ const ChatCard: React.FC<ChatCardProps> = ({
291253 classNames = { chatCardStyles }
292254 title = {
293255 < ChatHeader
294- chat = { chat }
256+ // model
295257 models = { models }
296258 modelId = { modelId }
297- setModelId = { setModelId }
298- endpoint = { endpoint }
299- setEndpoint = { setEndpoint }
259+ onChangeModel = { ( modelId ) => {
260+ onUpdateChat ?.( {
261+ provider : {
262+ modelId,
263+ } ,
264+ } ) ;
265+ } }
266+ // agent
300267 agents = { agents }
301268 agent = { agent }
302- setAgent = { setAgent }
303- sync = { sync }
304- setSync = { setSync }
269+ onChangeAgent = { ( agent ) => {
270+ onUpdateChat ?.( {
271+ provider : {
272+ agentId : agent . id ,
273+ endpointId : agent . endpoint_id ,
274+ } ,
275+ } ) ;
276+ } }
277+ // endpoint
278+ endpointFrgmt = { endpoint }
279+ onChangeEndpoint = { ( endpointId ) => {
280+ onUpdateChat ?.( {
281+ provider : {
282+ endpointId,
283+ } ,
284+ } ) ;
285+ } }
286+ // sync
287+ sync = { chat . sync }
288+ onChangeSync = { ( sync ) => {
289+ onUpdateChat ?.( {
290+ sync,
291+ } ) ;
292+ } }
293+ // others
305294 fetchKey = { fetchKey }
306295 closable = { closable }
307- onCreateNewChat = { onCreateNewChat }
308- onRequestClose = { onRequestClose }
309- setMessages = { setMessages }
296+ onClickCreate = { onCreateNewChat }
297+ onClickClose = { ( ) => {
298+ onRequestClose ?.( chat ) ;
299+ } }
300+ onClickDeleteChatHistory = { ( ) => {
301+ setMessages ( [ ] ) ;
302+ } }
310303 />
311304 }
312305 ref = { dropContainerRef }
313306 >
314- { _ . isEmpty ( models ) && (
307+ { endpoint && _ . isEmpty ( models ) && (
315308 < CustomModelForm
316309 baseURL = { baseURL }
317- token = { token }
310+ token = { chat . provider . apiKey }
318311 endpointId = { endpoint ?. endpoint_id }
319312 loading = { isPendingUpdate }
320313 onSubmit = { ( data ) => {
321314 startUpdateTransition ( ( ) => {
322315 updateFetchKey ( ) ;
323- setBaseURL ( data . baseURL ) ;
324- setToken ( data . token ) ;
316+ onUpdateChat ?.( {
317+ ...chat ,
318+ provider : {
319+ ...chat . provider ,
320+ baseURL : data . baseURL ,
321+ apiKey : data . token ,
322+ } ,
323+ } ) ;
325324 } ) ;
326325 } }
327326 />
@@ -342,7 +341,7 @@ const ChatCard: React.FC<ChatCardProps> = ({
342341 startTime = { startTime }
343342 />
344343 < ChatInput
345- sync = { sync }
344+ sync = { chat . sync }
346345 input = { input }
347346 setInput = { setInput }
348347 stop = { stop }
0 commit comments