fix: prevent repeated 404 errors when accessing deleted sessions (#5644)

Signed-off-by: sheikhlimon <sheikhlimon404@gmail.com>
This commit is contained in:
Sheikh Limon
2025-11-10 20:43:06 +06:00
committed by GitHub
parent 623e03f744
commit e8c895bbf8
2 changed files with 141 additions and 29 deletions
+48 -2
View File
@@ -62,12 +62,58 @@ export default function Pair({
return prev; return prev;
}); });
} catch (error) { } catch (error) {
console.log(error); console.error('Agent initialization failed:', error);
setFatalError(`Agent init failure: ${error instanceof Error ? error.message : '' + error}`);
// Clear deleted session from URL and retry
if (
error instanceof Error &&
(error.message.includes('Session not found') || error.message.includes('404'))
) {
console.log('Clearing invalid session ID from URL');
setSearchParams((prev) => {
prev.delete('resumeSessionId');
return prev;
});
try {
const chat = await loadCurrentChat({
setAgentWaitingMessage,
});
setChat(chat);
setSearchParams((prev) => {
prev.set('resumeSessionId', chat.sessionId);
return prev;
});
} catch (retryError) {
handleInitializationError(retryError);
}
} else {
handleInitializationError(error);
}
} finally { } finally {
setLoadingChat(false); setLoadingChat(false);
} }
}; };
const handleInitializationError = (error: unknown) => {
let errorMessage = 'Unknown error occurred';
if (error) {
if (error instanceof Error) {
errorMessage = error.message;
} else if (typeof error === 'object' && error !== null) {
// Handle case where error is an object with properties
try {
errorMessage = JSON.stringify(error);
} catch {
errorMessage = Object.prototype.toString.call(error);
}
} else {
errorMessage = String(error);
}
}
setFatalError(`Agent init failure: ${errorMessage}`);
};
initializeFromState(); initializeFromState();
}, [ }, [
agentState, agentState,
+93 -27
View File
@@ -47,6 +47,7 @@ export function useAgent(): UseAgentReturn {
const [agentState, setAgentState] = useState<AgentState>(AgentState.UNINITIALIZED); const [agentState, setAgentState] = useState<AgentState>(AgentState.UNINITIALIZED);
const [sessionId, setSessionId] = useState<string | null>(null); const [sessionId, setSessionId] = useState<string | null>(null);
const initPromiseRef = useRef<Promise<ChatType> | null>(null); const initPromiseRef = useRef<Promise<ChatType> | null>(null);
const deletedSessionsRef = useRef<Set<string>>(new Set());
const recipeIdFromConfig = useRef<string | null>( const recipeIdFromConfig = useRef<string | null>(
(window.appConfig.get('recipeId') as string | null | undefined) ?? null (window.appConfig.get('recipeId') as string | null | undefined) ?? null
); );
@@ -64,30 +65,65 @@ export function useAgent(): UseAgentReturn {
recipeIdFromConfig.current = null; recipeIdFromConfig.current = null;
recipeDeeplinkFromConfig.current = null; recipeDeeplinkFromConfig.current = null;
scheduledJobIdFromConfig.current = null; scheduledJobIdFromConfig.current = null;
deletedSessionsRef.current.clear();
}, []); }, []);
const agentIsInitialized = agentState === AgentState.INITIALIZED; const agentIsInitialized = agentState === AgentState.INITIALIZED;
const currentChat = useCallback( const currentChat = useCallback(
async (initContext: InitializationContext): Promise<ChatType> => { async (initContext: InitializationContext): Promise<ChatType> => {
if (agentIsInitialized && sessionId) { // Skip deleted sessions
const agentResponse = await resumeAgent({ if (
body: { initContext.resumeSessionId &&
session_id: sessionId, deletedSessionsRef.current.has(initContext.resumeSessionId)
load_model_and_extensions: false, ) {
}, initContext.resumeSessionId = undefined;
throwOnError: true,
});
const agentSession = agentResponse.data; // Clear from URL
const messages = agentSession.conversation || []; const url = new URL(window.location.href);
return { url.searchParams.delete('resumeSessionId');
sessionId: agentSession.id, window.history.replaceState({}, '', url.toString());
name: agentSession.recipe?.title || agentSession.name, }
messageHistoryIndex: 0,
messages, if (sessionId && deletedSessionsRef.current.has(sessionId)) {
recipe: agentSession.recipe, setSessionId(null);
recipeParameterValues: agentSession.user_recipe_values || null, }
};
if (agentIsInitialized && sessionId && !deletedSessionsRef.current.has(sessionId)) {
let agentResponse;
try {
agentResponse = await resumeAgent({
body: {
session_id: sessionId,
load_model_and_extensions: false,
},
throwOnError: true,
});
} catch {
// Mark session as deleted and clear state
deletedSessionsRef.current.add(sessionId);
setSessionId(null);
// Clear from URL
const url = new URL(window.location.href);
if (url.searchParams.get('resumeSessionId')) {
url.searchParams.delete('resumeSessionId');
window.history.replaceState({}, '', url.toString());
}
}
// Fall through to create new session
if (agentResponse?.data) {
const agentSession = agentResponse.data;
const messages = agentSession.conversation || [];
return {
sessionId: agentSession.id,
name: agentSession.recipe?.title || agentSession.name,
messageHistoryIndex: 0,
messages,
recipe: agentSession.recipe,
recipeParameterValues: agentSession.user_recipe_values || null,
};
}
} }
if (initPromiseRef.current) { if (initPromiseRef.current) {
@@ -109,15 +145,38 @@ export function useAgent(): UseAgentReturn {
throw new NoProviderOrModelError(); throw new NoProviderOrModelError();
} }
const agentResponse = initContext.resumeSessionId let agentResponse;
? await resumeAgent({ try {
body: { agentResponse = initContext.resumeSessionId
session_id: initContext.resumeSessionId, ? await resumeAgent({
load_model_and_extensions: false, body: {
}, session_id: initContext.resumeSessionId,
throwOnError: true, load_model_and_extensions: false,
}) },
: await startAgent({ throwOnError: true,
})
: await startAgent({
body: {
working_dir: window.appConfig.get('GOOSE_WORKING_DIR') as string,
...buildRecipeInput(
initContext.recipe,
recipeIdFromConfig.current,
recipeDeeplinkFromConfig.current
),
},
throwOnError: true,
});
} catch (error) {
// If resuming fails, mark session as deleted and create new agent
if (initContext.resumeSessionId) {
deletedSessionsRef.current.add(initContext.resumeSessionId);
// Clear from URL
const url = new URL(window.location.href);
url.searchParams.delete('resumeSessionId');
window.history.replaceState({}, '', url.toString());
agentResponse = await startAgent({
body: { body: {
working_dir: window.appConfig.get('GOOSE_WORKING_DIR') as string, working_dir: window.appConfig.get('GOOSE_WORKING_DIR') as string,
...buildRecipeInput( ...buildRecipeInput(
@@ -129,6 +188,13 @@ export function useAgent(): UseAgentReturn {
throwOnError: true, throwOnError: true,
}); });
// Clear resume flag
initContext.resumeSessionId = undefined;
} else {
throw error;
}
}
const agentSession = agentResponse.data; const agentSession = agentResponse.data;
if (!agentSession) { if (!agentSession) {
throw Error('Failed to get session info'); throw Error('Failed to get session info');