Merge pull request #1826 from xKevIsDev/error-fix

fix: enhanced error handling for llm api, general cleanup
This commit is contained in:
KevIsDev
2025-07-08 02:11:37 +01:00
committed by GitHub
31 changed files with 633 additions and 6405 deletions

View File

@@ -4,8 +4,6 @@ export * from './useShortcuts';
export * from './StickToBottom';
export * from './useEditChatDescription';
export { default } from './useViewport';
export { useUpdateCheck } from './useUpdateCheck';
export { useFeatures } from './useFeatures';
export { useNotifications } from './useNotifications';
export { useConnectionStatus } from './useConnectionStatus';
export { useDebugStatus } from './useDebugStatus';

View File

@@ -1,89 +0,0 @@
import { useState, useEffect } from 'react';
import { getDebugStatus, acknowledgeWarning, acknowledgeError, type DebugIssue } from '~/lib/api/debug';
const ACKNOWLEDGED_DEBUG_ISSUES_KEY = 'bolt_acknowledged_debug_issues';
const getAcknowledgedIssues = (): string[] => {
try {
const stored = localStorage.getItem(ACKNOWLEDGED_DEBUG_ISSUES_KEY);
return stored ? JSON.parse(stored) : [];
} catch {
return [];
}
};
const setAcknowledgedIssues = (issueIds: string[]) => {
try {
localStorage.setItem(ACKNOWLEDGED_DEBUG_ISSUES_KEY, JSON.stringify(issueIds));
} catch (error) {
console.error('Failed to persist acknowledged debug issues:', error);
}
};
export const useDebugStatus = () => {
const [hasActiveWarnings, setHasActiveWarnings] = useState(false);
const [activeIssues, setActiveIssues] = useState<DebugIssue[]>([]);
const [acknowledgedIssueIds, setAcknowledgedIssueIds] = useState<string[]>(() => getAcknowledgedIssues());
const checkDebugStatus = async () => {
try {
const status = await getDebugStatus();
const issues: DebugIssue[] = [
...status.warnings.map((w) => ({ ...w, type: 'warning' as const })),
...status.errors.map((e) => ({ ...e, type: 'error' as const })),
].filter((issue) => !acknowledgedIssueIds.includes(issue.id));
setActiveIssues(issues);
setHasActiveWarnings(issues.length > 0);
} catch (error) {
console.error('Failed to check debug status:', error);
}
};
useEffect(() => {
// Check immediately and then every 5 seconds
checkDebugStatus();
const interval = setInterval(checkDebugStatus, 5 * 1000);
return () => clearInterval(interval);
}, [acknowledgedIssueIds]);
const acknowledgeIssue = async (issue: DebugIssue) => {
try {
if (issue.type === 'warning') {
await acknowledgeWarning(issue.id);
} else {
await acknowledgeError(issue.id);
}
const newAcknowledgedIds = [...acknowledgedIssueIds, issue.id];
setAcknowledgedIssueIds(newAcknowledgedIds);
setAcknowledgedIssues(newAcknowledgedIds);
setActiveIssues((prev) => prev.filter((i) => i.id !== issue.id));
setHasActiveWarnings(activeIssues.length > 1);
} catch (error) {
console.error('Failed to acknowledge issue:', error);
}
};
const acknowledgeAllIssues = async () => {
try {
await Promise.all(
activeIssues.map((issue) =>
issue.type === 'warning' ? acknowledgeWarning(issue.id) : acknowledgeError(issue.id),
),
);
const newAcknowledgedIds = [...acknowledgedIssueIds, ...activeIssues.map((i) => i.id)];
setAcknowledgedIssueIds(newAcknowledgedIds);
setAcknowledgedIssues(newAcknowledgedIds);
setActiveIssues([]);
setHasActiveWarnings(false);
} catch (error) {
console.error('Failed to acknowledge all issues:', error);
}
};
return { hasActiveWarnings, activeIssues, acknowledgeIssue, acknowledgeAllIssues };
};

View File

@@ -8,7 +8,6 @@ import {
autoSelectStarterTemplate,
enableContextOptimizationStore,
tabConfigurationStore,
updateTabConfiguration as updateTabConfig,
resetTabConfiguration as resetTabConfig,
updateProviderSettings as updateProviderSettingsStore,
updateLatestBranch,
@@ -20,7 +19,7 @@ import {
import { useCallback, useEffect, useState } from 'react';
import Cookies from 'js-cookie';
import type { IProviderSetting, ProviderInfo, IProviderConfig } from '~/types/model';
import type { TabWindowConfig, TabVisibilityConfig } from '~/components/@settings/core/types';
import type { TabWindowConfig } from '~/components/@settings/core/types';
import { logStore } from '~/lib/stores/logs';
import { getLocalStorage, setLocalStorage } from '~/lib/persistence';
@@ -62,7 +61,6 @@ export interface UseSettingsReturn {
// Tab configuration
tabConfiguration: TabWindowConfig;
updateTabConfiguration: (config: TabVisibilityConfig) => void;
resetTabConfiguration: () => void;
}
@@ -205,7 +203,6 @@ export function useSettings(): UseSettingsReturn {
setTimezone,
settings,
tabConfiguration,
updateTabConfiguration: updateTabConfig,
resetTabConfiguration: resetTabConfig,
};
}

View File

@@ -1,58 +0,0 @@
import { useState, useEffect } from 'react';
import { checkForUpdates, acknowledgeUpdate } from '~/lib/api/updates';
const LAST_ACKNOWLEDGED_VERSION_KEY = 'bolt_last_acknowledged_version';
export const useUpdateCheck = () => {
const [hasUpdate, setHasUpdate] = useState(false);
const [currentVersion, setCurrentVersion] = useState<string>('');
const [lastAcknowledgedVersion, setLastAcknowledgedVersion] = useState<string | null>(() => {
try {
return localStorage.getItem(LAST_ACKNOWLEDGED_VERSION_KEY);
} catch {
return null;
}
});
useEffect(() => {
const checkUpdate = async () => {
try {
const { available, version } = await checkForUpdates();
setCurrentVersion(version);
// Only show update if it's a new version and hasn't been acknowledged
setHasUpdate(available && version !== lastAcknowledgedVersion);
} catch (error) {
console.error('Failed to check for updates:', error);
}
};
// Check immediately and then every 30 minutes
checkUpdate();
const interval = setInterval(checkUpdate, 30 * 60 * 1000);
return () => clearInterval(interval);
}, [lastAcknowledgedVersion]);
const handleAcknowledgeUpdate = async () => {
try {
const { version } = await checkForUpdates();
await acknowledgeUpdate(version);
// Store in localStorage
try {
localStorage.setItem(LAST_ACKNOWLEDGED_VERSION_KEY, version);
} catch (error) {
console.error('Failed to persist acknowledged version:', error);
}
setLastAcknowledgedVersion(version);
setHasUpdate(false);
} catch (error) {
console.error('Failed to acknowledge update:', error);
}
};
return { hasUpdate, currentVersion, acknowledgeUpdate: handleAcknowledgeUpdate };
};

View File

@@ -1,14 +1,8 @@
import { atom, map } from 'nanostores';
import { PROVIDER_LIST } from '~/utils/constants';
import type { IProviderConfig } from '~/types/model';
import type {
TabVisibilityConfig,
TabWindowConfig,
UserTabConfig,
DevTabConfig,
} from '~/components/@settings/core/types';
import type { TabVisibilityConfig, TabWindowConfig, UserTabConfig } from '~/components/@settings/core/types';
import { DEFAULT_TAB_CONFIG } from '~/components/@settings/core/constants';
import Cookies from 'js-cookie';
import { toggleTheme } from './theme';
import { create } from 'zustand';
@@ -202,7 +196,6 @@ export const updatePromptId = (id: string) => {
const getInitialTabConfiguration = (): TabWindowConfig => {
const defaultConfig: TabWindowConfig = {
userTabs: DEFAULT_TAB_CONFIG.filter((tab): tab is UserTabConfig => tab.window === 'user'),
developerTabs: DEFAULT_TAB_CONFIG.filter((tab): tab is DevTabConfig => tab.window === 'developer'),
};
if (!isBrowser) {
@@ -218,16 +211,13 @@ const getInitialTabConfiguration = (): TabWindowConfig => {
const parsed = JSON.parse(saved);
if (!parsed?.userTabs || !parsed?.developerTabs) {
if (!parsed?.userTabs) {
return defaultConfig;
}
// Ensure proper typing of loaded configuration
return {
userTabs: parsed.userTabs.filter((tab: TabVisibilityConfig): tab is UserTabConfig => tab.window === 'user'),
developerTabs: parsed.developerTabs.filter(
(tab: TabVisibilityConfig): tab is DevTabConfig => tab.window === 'developer',
),
};
} catch (error) {
console.warn('Failed to parse tab configuration:', error);
@@ -239,60 +229,16 @@ const getInitialTabConfiguration = (): TabWindowConfig => {
export const tabConfigurationStore = map<TabWindowConfig>(getInitialTabConfiguration());
// Helper function to update tab configuration
export const updateTabConfiguration = (config: TabVisibilityConfig) => {
const currentConfig = tabConfigurationStore.get();
console.log('Current tab configuration before update:', currentConfig);
const isUserTab = config.window === 'user';
const targetArray = isUserTab ? 'userTabs' : 'developerTabs';
// Only update the tab in its respective window
const updatedTabs = currentConfig[targetArray].map((tab) => (tab.id === config.id ? { ...config } : tab));
// If tab doesn't exist in this window yet, add it
if (!updatedTabs.find((tab) => tab.id === config.id)) {
updatedTabs.push(config);
}
// Create new config, only updating the target window's tabs
const newConfig: TabWindowConfig = {
...currentConfig,
[targetArray]: updatedTabs,
};
console.log('New tab configuration after update:', newConfig);
tabConfigurationStore.set(newConfig);
Cookies.set('tabConfiguration', JSON.stringify(newConfig), {
expires: 365, // Set cookie to expire in 1 year
path: '/',
sameSite: 'strict',
});
};
// Helper function to reset tab configuration
export const resetTabConfiguration = () => {
const defaultConfig: TabWindowConfig = {
userTabs: DEFAULT_TAB_CONFIG.filter((tab): tab is UserTabConfig => tab.window === 'user'),
developerTabs: DEFAULT_TAB_CONFIG.filter((tab): tab is DevTabConfig => tab.window === 'developer'),
};
tabConfigurationStore.set(defaultConfig);
localStorage.setItem('bolt_tab_configuration', JSON.stringify(defaultConfig));
};
// Developer mode store with persistence
export const developerModeStore = atom<boolean>(initialSettings.developerMode);
export const setDeveloperMode = (value: boolean) => {
developerModeStore.set(value);
if (isBrowser) {
localStorage.setItem(SETTINGS_KEYS.DEVELOPER_MODE, JSON.stringify(value));
}
};
// First, let's define the SettingsStore interface
interface SettingsStore {
isOpen: boolean;

View File

@@ -10,22 +10,19 @@ export interface TabConfig {
interface TabConfigurationStore {
userTabs: TabConfig[];
developerTabs: TabConfig[];
get: () => { userTabs: TabConfig[]; developerTabs: TabConfig[] };
set: (config: { userTabs: TabConfig[]; developerTabs: TabConfig[] }) => void;
get: () => { userTabs: TabConfig[] };
set: (config: { userTabs: TabConfig[] }) => void;
reset: () => void;
}
const DEFAULT_CONFIG = {
userTabs: [],
developerTabs: [],
};
export const tabConfigurationStore = create<TabConfigurationStore>((set, get) => ({
...DEFAULT_CONFIG,
get: () => ({
userTabs: get().userTabs,
developerTabs: get().developerTabs,
}),
set: (config) => set(config),
reset: () => set(DEFAULT_CONFIG),