diff --git a/src/routes/(main)/community/(detail)/agent/features/Sidebar/ActionButton/ForkAndChat.tsx b/src/routes/(main)/community/(detail)/agent/features/Sidebar/ActionButton/ForkAndChat.tsx index db6fe97854..f7295891d7 100644 --- a/src/routes/(main)/community/(detail)/agent/features/Sidebar/ActionButton/ForkAndChat.tsx +++ b/src/routes/(main)/community/(detail)/agent/features/Sidebar/ActionButton/ForkAndChat.tsx @@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { SESSION_CHAT_URL } from '@/const/url'; +import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth'; import { agentService } from '@/services/agent'; import { discoverService } from '@/services/discover'; import { marketApiService } from '@/services/marketApi'; @@ -41,6 +42,7 @@ const ForkAndChat = memo<{ mobile?: boolean }>(({ mobile }) => { const { message } = App.useApp(); const navigate = useNavigate(); const { t } = useTranslation('discover'); + const { isAuthenticated, signIn } = useMarketAuth(); const meta = { avatar, @@ -52,6 +54,15 @@ const ForkAndChat = memo<{ mobile?: boolean }>(({ mobile }) => { }; const handleForkAndChat = async () => { + // Check if user is authenticated + if (!isAuthenticated) { + try { + await signIn(); + } catch { + return; + } + } + try { setIsLoading(true); diff --git a/src/routes/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/ForkGroupAndChat.tsx b/src/routes/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/ForkGroupAndChat.tsx index 6ba74db111..729f0b9ceb 100644 --- a/src/routes/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/ForkGroupAndChat.tsx +++ b/src/routes/(main)/community/(detail)/group_agent/features/Sidebar/ActionButton/ForkGroupAndChat.tsx @@ -9,6 +9,7 @@ import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import urlJoin from 'url-join'; +import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth'; import { chatGroupService } from '@/services/chatGroup'; import { discoverService } from '@/services/discover'; import { marketApiService } from '@/services/marketApi'; @@ -47,6 +48,7 @@ const ForkGroupAndChat = memo<{ mobile?: boolean }>(() => { const { t } = useTranslation('discover'); const navigate = useNavigate(); const loadGroups = useAgentGroupStore((s) => s.loadGroups); + const { isAuthenticated, signIn } = useMarketAuth(); const meta = { avatar, @@ -57,6 +59,15 @@ const ForkGroupAndChat = memo<{ mobile?: boolean }>(() => { }; const handleForkAndChat = async () => { + // Check if user is authenticated + if (!isAuthenticated) { + try { + await signIn(); + } catch { + return; + } + } + try { setIsLoading(true); @@ -120,7 +131,6 @@ const ForkGroupAndChat = memo<{ mobile?: boolean }>(() => { }; // Filter out null/undefined values supervisorConfig = Object.fromEntries( - Object.entries(rawConfig).filter(([_, v]) => v != null), ); } diff --git a/src/services/discover.ts b/src/services/discover.ts index 887e352542..6ade4a3a41 100644 --- a/src/services/discover.ts +++ b/src/services/discover.ts @@ -40,6 +40,7 @@ import { cleanObject } from '@/utils/object'; class DiscoverService { private _isRetrying = false; + private _tokenRefreshPromise: Promise | null = null; // ============================== Assistant Market ============================== getAssistantCategories = async ( @@ -389,6 +390,22 @@ class DiscoverService { const tokenStatus = this.getTokenStatusFromCookie(); if (tokenStatus === 'active') return; + // If a token refresh is already in progress, wait for it to complete + if (this._tokenRefreshPromise) { + await this._tokenRefreshPromise; + return; + } + + // Create a new refresh promise and execute + this._tokenRefreshPromise = this._doRefreshToken(); + try { + await this._tokenRefreshPromise; + } finally { + this._tokenRefreshPromise = null; + } + } + + private async _doRefreshToken() { let clientId: string; let clientSecret: string; @@ -444,7 +461,7 @@ class DiscoverService { if (!this._isRetrying) { this._isRetrying = true; try { - await this.injectMPToken(); + await this._doRefreshToken(); } finally { this._isRetrying = false; } @@ -454,12 +471,27 @@ class DiscoverService { return; } + + // 6. Wait for cookie to be set by browser + // The Set-Cookie header processing may have a tiny delay + await this._waitForCookieSet(); } catch (error) { console.error('Failed to register M2M token:', error); - return null; } } + private async _waitForCookieSet(maxRetries = 10, interval = 10): Promise { + for (let i = 0; i < maxRetries; i++) { + if (this.getTokenStatusFromCookie() === 'active') { + return; + } + await new Promise((resolve) => setTimeout(resolve, interval)); + } + // If cookie still not set after retries, continue anyway + // The request might still work if the cookie was set but we couldn't detect it + console.warn('Cookie may not be fully set, proceeding anyway'); + } + private getTokenStatusFromCookie(): string | null { if (typeof document === 'undefined') return null;