diff --git a/api/app/clients/OpenAIClient.js b/api/app/clients/OpenAIClient.js index d3bf5ddd122..3554f4d6543 100644 --- a/api/app/clients/OpenAIClient.js +++ b/api/app/clients/OpenAIClient.js @@ -1324,6 +1324,11 @@ ${convo} /** @type {(value: void | PromiseLike) => void} */ let streamResolve; + if (this.isO1Model === true && this.azure && modelOptions.stream) { + delete modelOptions.stream; + delete modelOptions.stop; + } + if (modelOptions.stream) { streamPromise = new Promise((resolve) => { streamResolve = resolve; diff --git a/client/src/components/Messages/Content/RunCode.tsx b/client/src/components/Messages/Content/RunCode.tsx index b2190834682..e80c589bd1a 100644 --- a/client/src/components/Messages/Content/RunCode.tsx +++ b/client/src/components/Messages/Content/RunCode.tsx @@ -21,7 +21,12 @@ const RunCode: React.FC = React.memo(({ lang, codeRef, blockIndex const { messageId, conversationId, partIndex } = useMessageContext(); const normalizedLang = useMemo(() => normalizeLanguage(lang), [lang]); - const { data } = useVerifyAgentToolAuth({ toolId: Tools.execute_code }); + const { data } = useVerifyAgentToolAuth( + { toolId: Tools.execute_code }, + { + retry: 1, + }, + ); const authType = useMemo(() => data?.message ?? false, [data?.message]); const isAuthenticated = useMemo(() => data?.authenticated ?? false, [data?.authenticated]); const { methods, onSubmit, isDialogOpen, setIsDialogOpen, handleRevokeApiKey } = diff --git a/client/src/hooks/AuthContext.tsx b/client/src/hooks/AuthContext.tsx index 36dea258b9c..5624df138e9 100644 --- a/client/src/hooks/AuthContext.tsx +++ b/client/src/hooks/AuthContext.tsx @@ -53,7 +53,7 @@ const AuthContextProvider = ({ //@ts-ignore - ok for token to be undefined initially setTokenHeader(token); setIsAuthenticated(isAuthenticated); - if (redirect) { + if (redirect != null && redirect) { navigate(redirect, { replace: true }); } }, @@ -83,7 +83,7 @@ const AuthContextProvider = ({ }); const logout = useCallback(() => logoutUser.mutate(undefined), [logoutUser]); - const userQuery = useGetUserQuery({ enabled: !!token }); + const userQuery = useGetUserQuery({ enabled: !!(token ?? '') }); const refreshToken = useRefreshTokenMutation(); const login = (data: TLoginUser) => { @@ -102,18 +102,18 @@ const AuthContextProvider = ({ }; const silentRefresh = useCallback(() => { - if (authConfig?.test) { + if (authConfig?.test === true) { console.log('Test mode. Skipping silent refresh.'); return; } refreshToken.mutate(undefined, { - onSuccess: (data: TLoginResponse) => { - const { user, token } = data; + onSuccess: (data: TLoginResponse | undefined) => { + const { user, token = '' } = data ?? {}; if (token) { setUserContext({ token, isAuthenticated: true, user }); } else { console.log('Token is not present. User is not authenticated.'); - if (authConfig?.test) { + if (authConfig?.test === true) { return; } navigate('/login'); @@ -121,7 +121,7 @@ const AuthContextProvider = ({ }, onError: (error) => { console.log('refreshToken mutation error:', error); - if (authConfig?.test) { + if (authConfig?.test === true) { return; } navigate('/login'); @@ -136,10 +136,10 @@ const AuthContextProvider = ({ doSetError((userQuery.error as Error).message); navigate('/login', { replace: true }); } - if (error && isAuthenticated) { + if (error != null && error && isAuthenticated) { doSetError(undefined); } - if (!token || !isAuthenticated) { + if (token == null || !token || !isAuthenticated) { silentRefresh(); } }, [ @@ -149,7 +149,9 @@ const AuthContextProvider = ({ userQuery.isError, userQuery.error, error, + setUser, navigate, + silentRefresh, setUserContext, ]); diff --git a/client/src/hooks/Input/useQueryParams.ts b/client/src/hooks/Input/useQueryParams.ts index 1d70eb75d33..343f2141690 100644 --- a/client/src/hooks/Input/useQueryParams.ts +++ b/client/src/hooks/Input/useQueryParams.ts @@ -14,13 +14,11 @@ export default function useQueryParams({ const maxAttempts = 50; // 5 seconds maximum (50 * 100ms) useEffect(() => { - const promptParam = searchParams.get('prompt'); - if (!promptParam) { + const decodedPrompt = searchParams.get('prompt') ?? ''; + if (!decodedPrompt) { return; } - const decodedPrompt = decodeURIComponent(promptParam); - const intervalId = setInterval(() => { // If already processed or max attempts reached, clear interval and stop if (processedRef.current || attemptsRef.current >= maxAttempts) { diff --git a/client/src/hooks/useTimeout.tsx b/client/src/hooks/useTimeout.tsx index 2d325940e01..456dfd1800c 100644 --- a/client/src/hooks/useTimeout.tsx +++ b/client/src/hooks/useTimeout.tsx @@ -16,7 +16,7 @@ function useTimeout({ callback, delay = 400 }: TUseTimeoutParams) { } // Set new timeout - if (value) { + if (value != null && value) { console.log(value); timeout.current = setTimeout(() => { callback(value); diff --git a/package-lock.json b/package-lock.json index 58ca8f621d9..c19afac0b25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -665,9 +665,9 @@ } }, "api/node_modules/@langchain/openai": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.3.12.tgz", - "integrity": "sha512-z8y0zdKovjY6bB0D3D+K99bPAN+wFRQcrWDfHfX7yVmYwq1O8GOIzQgCBth0vbhbzeuaJ4dz3+oqN/4Q2PCpHg==", + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.3.14.tgz", + "integrity": "sha512-lNWjUo1tbvsss45IF7UQtMu1NJ6oUKvhgPYWXnX9f/d6OmuLu7D99HQ3Y88vLcUo9XjjOy417olYHignMduMjA==", "license": "MIT", "dependencies": { "js-tiktoken": "^1.0.12", diff --git a/packages/data-provider/src/react-query/react-query-service.ts b/packages/data-provider/src/react-query/react-query-service.ts index 0394addf5e9..9dcdfc681e5 100644 --- a/packages/data-provider/src/react-query/react-query-service.ts +++ b/packages/data-provider/src/react-query/react-query-service.ts @@ -338,7 +338,7 @@ export const useRegisterUserMutation = ( }; export const useRefreshTokenMutation = (): UseMutationResult< - t.TRefreshTokenResponse, + t.TRefreshTokenResponse | undefined, unknown, unknown, unknown diff --git a/packages/data-provider/src/request.ts b/packages/data-provider/src/request.ts index c19d60f78a5..239e8e89544 100644 --- a/packages/data-provider/src/request.ts +++ b/packages/data-provider/src/request.ts @@ -2,6 +2,7 @@ import axios, { AxiosError, AxiosRequestConfig } from 'axios'; import * as endpoints from './api-endpoints'; import { setTokenHeader } from './headers-helpers'; +import type * as t from './types'; async function _get(url: string, options?: AxiosRequestConfig): Promise { const response = await axios.get(url, { ...options }); @@ -63,7 +64,8 @@ async function _patch(url: string, data?: any) { let isRefreshing = false; let failedQueue: { resolve: (value?: any) => void; reject: (reason?: any) => void }[] = []; -const refreshToken = (retry?: boolean) => _post(endpoints.refreshToken(retry)); +const refreshToken = (retry?: boolean): Promise => + _post(endpoints.refreshToken(retry)); const dispatchTokenUpdatedEvent = (token: string) => { setTokenHeader(token); @@ -90,6 +92,7 @@ axios.interceptors.response.use( } if (error.response.status === 401 && !originalRequest._retry) { + console.warn('401 error, refreshing token'); originalRequest._retry = true; if (isRefreshing) { @@ -107,16 +110,22 @@ axios.interceptors.response.use( isRefreshing = true; try { - const { token } = await refreshToken( + const response = await refreshToken( // Handle edge case where we get a blank screen if the initial 401 error is from a refresh token request - originalRequest.url?.includes('api/auth/refresh') ? true : false, + originalRequest.url?.includes('api/auth/refresh') === true ? true : false, ); + const token = response?.token ?? ''; + if (token) { originalRequest.headers['Authorization'] = 'Bearer ' + token; dispatchTokenUpdatedEvent(token); processQueue(null, token); return await axios(originalRequest); + } else if (window.location.href.includes('share/')) { + console.log( + `Refresh token failed from shared link, attempting request to ${originalRequest.url}`, + ); } else { window.location.href = '/login'; }