Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bc165be

Browse files
authored
🐛 fix: the klavis in onboarding connect timeout fixed (lobehub#11918)
fix: the klavis in onboarding connect timeout fixed
1 parent a074f48 commit bc165be

File tree

6 files changed

+79
-23
lines changed

6 files changed

+79
-23
lines changed

src/app/[variants]/(main)/agent/features/Conversation/AgentWelcome/ToolAuthAlert.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ const KlavisToolAuthItem = memo<KlavisToolAuthItemProps>(({ tool, onAuthComplete
104104
try {
105105
await refreshKlavisServerTools(identifier);
106106
} catch (error) {
107-
console.error('[Klavis] Failed to check auth status:', error);
107+
console.debug('[Klavis] Polling check (expected during auth):', error);
108108
}
109109
}, POLL_INTERVAL_MS);
110110

@@ -129,7 +129,8 @@ const KlavisToolAuthItem = memo<KlavisToolAuthItemProps>(({ tool, onAuthComplete
129129
windowCheckIntervalRef.current = null;
130130
}
131131
oauthWindowRef.current = null;
132-
refreshKlavisServerTools(identifier);
132+
// Start polling after window closes
133+
startFallbackPolling(identifier);
133134
}
134135
} catch {
135136
if (windowCheckIntervalRef.current) {

src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ const KlavisSkillItem = memo<KlavisSkillItemProps>(({ serverType, server }) => {
120120
try {
121121
await refreshKlavisServerTools(serverName);
122122
} catch (error) {
123-
console.error('[Klavis] Failed to check auth status:', error);
123+
console.debug('[Klavis] Polling check (expected during auth):', error);
124124
}
125125
}, POLL_INTERVAL_MS);
126126

@@ -145,8 +145,8 @@ const KlavisSkillItem = memo<KlavisSkillItemProps>(({ serverType, server }) => {
145145
windowCheckIntervalRef.current = null;
146146
}
147147
oauthWindowRef.current = null;
148-
await refreshKlavisServerTools(serverName);
149-
setIsWaitingAuth(false);
148+
// Start polling after window closes
149+
startFallbackPolling(serverName);
150150
}
151151
} catch {
152152
console.log('[Klavis] COOP blocked window.closed access, falling back to polling');

src/app/[variants]/onboarding/components/KlavisServerList/hooks/useKlavisOAuth.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { KlavisServerStatus } from '@/store/tool/slices/klavisStore';
55

66
const POLL_INTERVAL_MS = 1000;
77
const POLL_TIMEOUT_MS = 15_000;
8+
const WINDOW_CLOSED_POLL_TIMEOUT_MS = 4000; // Shorter timeout when window is closed
89

910
interface UseKlavisOAuthProps {
1011
serverStatus?: KlavisServerStatus;
@@ -50,14 +51,14 @@ export const useKlavisOAuth = ({ serverStatus }: UseKlavisOAuthProps) => {
5051
}, [serverStatus, isWaitingAuth, cleanup]);
5152

5253
const startFallbackPolling = useCallback(
53-
(serverName: string) => {
54+
(serverName: string, timeoutMs: number = POLL_TIMEOUT_MS) => {
5455
if (pollIntervalRef.current) return;
5556

5657
pollIntervalRef.current = setInterval(async () => {
5758
try {
5859
await refreshKlavisServerTools(serverName);
5960
} catch (error) {
60-
console.error('[Klavis] Failed to check auth status:', error);
61+
console.debug('[Klavis] Polling check (expected during auth):', error);
6162
}
6263
}, POLL_INTERVAL_MS);
6364

@@ -67,7 +68,7 @@ export const useKlavisOAuth = ({ serverStatus }: UseKlavisOAuthProps) => {
6768
pollIntervalRef.current = null;
6869
}
6970
setIsWaitingAuth(false);
70-
}, POLL_TIMEOUT_MS);
71+
}, timeoutMs);
7172
},
7273
[refreshKlavisServerTools],
7374
);
@@ -77,23 +78,29 @@ export const useKlavisOAuth = ({ serverStatus }: UseKlavisOAuthProps) => {
7778
windowCheckIntervalRef.current = setInterval(() => {
7879
try {
7980
if (oauthWindow.closed) {
81+
// Stop monitoring window
8082
if (windowCheckIntervalRef.current) {
8183
clearInterval(windowCheckIntervalRef.current);
8284
windowCheckIntervalRef.current = null;
8385
}
8486
oauthWindowRef.current = null;
85-
refreshKlavisServerTools(serverName);
87+
88+
// Start polling to check auth status after window closes
89+
// Use shorter timeout since user has closed the window
90+
// Keep loading state until we confirm success or timeout
91+
startFallbackPolling(serverName, WINDOW_CLOSED_POLL_TIMEOUT_MS);
8692
}
8793
} catch {
8894
if (windowCheckIntervalRef.current) {
8995
clearInterval(windowCheckIntervalRef.current);
9096
windowCheckIntervalRef.current = null;
9197
}
98+
// Use default timeout for fallback polling
9299
startFallbackPolling(serverName);
93100
}
94101
}, 500);
95102
},
96-
[refreshKlavisServerTools, startFallbackPolling],
103+
[startFallbackPolling],
97104
);
98105

99106
const openOAuthWindow = useCallback(

src/features/ChatInput/ActionBar/Tools/KlavisServerItem.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ const KlavisServerItem = memo<KlavisServerItemProps>(
8888
try {
8989
await refreshKlavisServerTools(serverName);
9090
} catch (error) {
91-
console.error('[Klavis] Failed to check auth status:', error);
91+
console.debug('[Klavis] Polling check (expected during auth):', error);
9292
}
9393
}, POLL_INTERVAL_MS);
9494

@@ -121,8 +121,8 @@ const KlavisServerItem = memo<KlavisServerItemProps>(
121121
}
122122
oauthWindowRef.current = null;
123123

124-
// 窗口关闭后立即检查一次认证状态
125-
refreshKlavisServerTools(serverName);
124+
// 窗口关闭后开始轮询检查认证状态
125+
startFallbackPolling(serverName);
126126
}
127127
} catch {
128128
// COOP 阻止了访问,降级到轮询方案

src/server/routers/lambda/klavis.ts

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ export const klavisRouter = router({
124124

125125
/**
126126
* Get server instance status from Klavis API
127+
* Returns error object instead of throwing on auth errors (useful for polling)
127128
*/
128129
getServerInstance: klavisProcedure
129130
.input(
@@ -132,16 +133,43 @@ export const klavisRouter = router({
132133
}),
133134
)
134135
.query(async ({ input, ctx }) => {
135-
const response = await ctx.klavisClient.mcpServer.getServerInstance(input.instanceId);
136-
return {
137-
authNeeded: response.authNeeded,
138-
externalUserId: response.externalUserId,
139-
instanceId: response.instanceId,
140-
isAuthenticated: response.isAuthenticated,
141-
oauthUrl: response.oauthUrl,
142-
platform: response.platform,
143-
serverName: response.serverName,
144-
};
136+
try {
137+
const response = await ctx.klavisClient.mcpServer.getServerInstance(input.instanceId);
138+
return {
139+
authNeeded: response.authNeeded,
140+
error: undefined,
141+
externalUserId: response.externalUserId,
142+
instanceId: response.instanceId,
143+
isAuthenticated: response.isAuthenticated,
144+
oauthUrl: response.oauthUrl,
145+
platform: response.platform,
146+
serverName: response.serverName,
147+
};
148+
} catch (error) {
149+
// Check if this is an authentication error
150+
const errorMessage = error instanceof Error ? error.message : String(error);
151+
const isAuthError =
152+
errorMessage.includes('Invalid API key or instance ID') ||
153+
errorMessage.includes('Status code: 401');
154+
155+
// For auth errors, return error object instead of throwing
156+
// This prevents 500 errors in logs during polling
157+
if (isAuthError) {
158+
return {
159+
authNeeded: true,
160+
error: 'AUTH_ERROR',
161+
externalUserId: undefined,
162+
instanceId: input.instanceId,
163+
isAuthenticated: false,
164+
oauthUrl: undefined,
165+
platform: undefined,
166+
serverName: undefined,
167+
};
168+
}
169+
170+
// For other errors, still throw
171+
throw error;
172+
}
145173
}),
146174

147175
getUserIntergrations: klavisProcedure

src/store/tool/slices/klavisStore/action.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,30 @@ export const createKlavisStoreSlice: StateCreator<
210210
instanceId: server.instanceId,
211211
});
212212

213+
// If server returned an auth error (during polling), silently return
214+
// This happens when user is still in the process of authorizing
215+
if (instanceStatus.error === 'AUTH_ERROR') {
216+
set(
217+
produce((draft: KlavisStoreState) => {
218+
draft.loadingServerIds.delete(identifier);
219+
}),
220+
false,
221+
n('refreshKlavisServerTools/pendingAuth'),
222+
);
223+
return;
224+
}
225+
213226
// If authentication failed, remove server and reset status
214227
if (!instanceStatus.isAuthenticated) {
215228
if (!instanceStatus.authNeeded) {
216229
// If no authentication needed, all is well
230+
set(
231+
produce((draft: KlavisStoreState) => {
232+
draft.loadingServerIds.delete(identifier);
233+
}),
234+
false,
235+
n('refreshKlavisServerTools/noAuthNeeded'),
236+
);
217237
return;
218238
}
219239

0 commit comments

Comments
 (0)