11import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/hooks/useRecoilComponentValue' ;
2- import { useRecoilState , useRecoilValue } from 'recoil' ;
2+ import { useRecoilState , useRecoilValue , useSetRecoilState } from 'recoil' ;
33
44import { agentChatSelectedFilesState } from '@/ai/states/agentChatSelectedFilesState' ;
55import { agentChatUploadedFilesState } from '@/ai/states/agentChatUploadedFilesState' ;
66import { currentAIChatThreadState } from '@/ai/states/currentAIChatThreadState' ;
77import { isAgentChatCurrentContextActiveState } from '@/ai/states/isAgentChatCurrentContextActiveState' ;
88
99import { getTokenPair } from '@/apollo/utils/getTokenPair' ;
10+ import { renewToken } from '@/auth/services/AuthService' ;
11+ import { tokenPairState } from '@/auth/states/tokenPairState' ;
1012import { contextStoreCurrentObjectMetadataItemIdComponentState } from '@/context-store/states/contextStoreCurrentObjectMetadataItemIdComponentState' ;
1113import { useGetObjectMetadataItemById } from '@/object-metadata/hooks/useGetObjectMetadataItemById' ;
1214import { type ObjectRecord } from '@/object-record/types/ObjectRecord' ;
@@ -15,10 +17,14 @@ import { useChat } from '@ai-sdk/react';
1517import { DefaultChatTransport } from 'ai' ;
1618import { type ExtendedUIMessage } from 'twenty-shared/ai' ;
1719import { isDefined } from 'twenty-shared/utils' ;
20+ import { REACT_APP_SERVER_BASE_URL } from '~/config' ;
21+ import { cookieStorage } from '~/utils/cookie-storage' ;
1822import { REST_API_BASE_URL } from '../../apollo/constant/rest-api-base-url' ;
1923import { agentChatInputState } from '../states/agentChatInputState' ;
2024
2125export const useAgentChat = ( uiMessages : ExtendedUIMessage [ ] ) => {
26+ const setTokenPair = useSetRecoilState ( tokenPairState ) ;
27+
2228 const { getObjectMetadataItemById } = useGetObjectMetadataItemById ( ) ;
2329
2430 const contextStoreCurrentObjectMetadataItemId = useRecoilComponentValue (
@@ -45,12 +51,68 @@ export const useAgentChat = (uiMessages: ExtendedUIMessage[]) => {
4551 const { scrollWrapperHTMLElement } =
4652 useScrollWrapperHTMLElement ( scrollWrapperId ) ;
4753
54+ const retryFetchWithRenewedToken = async (
55+ input : RequestInfo | URL ,
56+ init ?: RequestInit ,
57+ ) => {
58+ const tokenPair = getTokenPair ( ) ;
59+
60+ if ( ! isDefined ( tokenPair ) ) {
61+ return null ;
62+ }
63+
64+ try {
65+ const renewedTokens = await renewToken (
66+ `${ REACT_APP_SERVER_BASE_URL } /graphql` ,
67+ tokenPair ,
68+ ) ;
69+
70+ if ( ! isDefined ( renewedTokens ) ) {
71+ setTokenPair ( null ) ;
72+ return null ;
73+ }
74+
75+ const renewedAccessToken =
76+ renewedTokens . accessOrWorkspaceAgnosticToken ?. token ;
77+
78+ if ( ! isDefined ( renewedAccessToken ) ) {
79+ setTokenPair ( null ) ;
80+ return null ;
81+ }
82+
83+ cookieStorage . setItem ( 'tokenPair' , JSON . stringify ( renewedTokens ) ) ;
84+ setTokenPair ( renewedTokens ) ;
85+
86+ const updatedHeaders = new Headers ( init ?. headers ?? { } ) ;
87+ updatedHeaders . set ( 'Authorization' , `Bearer ${ renewedAccessToken } ` ) ;
88+
89+ return fetch ( input , {
90+ ...init ,
91+ headers : updatedHeaders ,
92+ } ) ;
93+ } catch {
94+ setTokenPair ( null ) ;
95+ return null ;
96+ }
97+ } ;
98+
4899 const { sendMessage, messages, status, error, regenerate } = useChat ( {
49100 transport : new DefaultChatTransport ( {
50101 api : `${ REST_API_BASE_URL } /agent-chat/stream` ,
51102 headers : ( ) => ( {
52103 Authorization : `Bearer ${ getTokenPair ( ) ?. accessOrWorkspaceAgnosticToken . token } ` ,
53104 } ) ,
105+ fetch : async ( input , init ) => {
106+ const response = await fetch ( input , init ) ;
107+
108+ if ( response . status !== 401 ) {
109+ return response ;
110+ }
111+
112+ const retriedResponse = await retryFetchWithRenewedToken ( input , init ) ;
113+
114+ return retriedResponse ?? response ;
115+ } ,
54116 } ) ,
55117 messages : uiMessages ,
56118 id : `${ currentAIChatThread } -${ uiMessages . length } ` ,
0 commit comments