| 
							 | 
						import React, { useCallback, useEffect, useState } from 'react'; | 
					
					
						
						| 
							 | 
						import { useSettings } from '~/lib/hooks/useSettings'; | 
					
					
						
						| 
							 | 
						import { toast } from 'react-toastify'; | 
					
					
						
						| 
							 | 
						import { providerBaseUrlEnvKeys } from '~/utils/constants'; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						interface ProviderStatus { | 
					
					
						
						| 
							 | 
						  name: string; | 
					
					
						
						| 
							 | 
						  enabled: boolean; | 
					
					
						
						| 
							 | 
						  isLocal: boolean; | 
					
					
						
						| 
							 | 
						  isRunning: boolean | null; | 
					
					
						
						| 
							 | 
						  error?: string; | 
					
					
						
						| 
							 | 
						  lastChecked: Date; | 
					
					
						
						| 
							 | 
						  responseTime?: number; | 
					
					
						
						| 
							 | 
						  url: string | null; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						interface SystemInfo { | 
					
					
						
						| 
							 | 
						  os: string; | 
					
					
						
						| 
							 | 
						  browser: string; | 
					
					
						
						| 
							 | 
						  screen: string; | 
					
					
						
						| 
							 | 
						  language: string; | 
					
					
						
						| 
							 | 
						  timezone: string; | 
					
					
						
						| 
							 | 
						  memory: string; | 
					
					
						
						| 
							 | 
						  cores: number; | 
					
					
						
						| 
							 | 
						  deviceType: string; | 
					
					
						
						| 
							 | 
						  colorDepth: string; | 
					
					
						
						| 
							 | 
						  pixelRatio: number; | 
					
					
						
						| 
							 | 
						  online: boolean; | 
					
					
						
						| 
							 | 
						  cookiesEnabled: boolean; | 
					
					
						
						| 
							 | 
						  doNotTrack: boolean; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						interface IProviderConfig { | 
					
					
						
						| 
							 | 
						  name: string; | 
					
					
						
						| 
							 | 
						  settings: { | 
					
					
						
						| 
							 | 
						    enabled: boolean; | 
					
					
						
						| 
							 | 
						    baseUrl?: string; | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						interface CommitData { | 
					
					
						
						| 
							 | 
						  commit: string; | 
					
					
						
						| 
							 | 
						  version?: string; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						const connitJson: CommitData = { | 
					
					
						
						| 
							 | 
						  commit: __COMMIT_HASH, | 
					
					
						
						| 
							 | 
						  version: __APP_VERSION, | 
					
					
						
						| 
							 | 
						}; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						const LOCAL_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike']; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						const versionHash = connitJson.commit; | 
					
					
						
						| 
							 | 
						const versionTag = connitJson.version; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						const GITHUB_URLS = { | 
					
					
						
						| 
							 | 
						  original: 'https://api.github.com/repos/stackblitz-labs/bolt.diy/commits/main', | 
					
					
						
						| 
							 | 
						  fork: 'https://api.github.com/repos/Stijnus/bolt.new-any-llm/commits/main', | 
					
					
						
						| 
							 | 
						  commitJson: async (branch: string) => { | 
					
					
						
						| 
							 | 
						    try { | 
					
					
						
						| 
							 | 
						      const response = await fetch(`https://api.github.com/repos/stackblitz-labs/bolt.diy/commits/${branch}`); | 
					
					
						
						| 
							 | 
						      const data: { sha: string } = await response.json(); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      const packageJsonResp = await fetch( | 
					
					
						
						| 
							 | 
						        `https://raw.githubusercontent.com/stackblitz-labs/bolt.diy/${branch}/package.json`, | 
					
					
						
						| 
							 | 
						      ); | 
					
					
						
						| 
							 | 
						      const packageJson: { version: string } = await packageJsonResp.json(); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      return { | 
					
					
						
						| 
							 | 
						        commit: data.sha.slice(0, 7), | 
					
					
						
						| 
							 | 
						        version: packageJson.version, | 
					
					
						
						| 
							 | 
						      }; | 
					
					
						
						| 
							 | 
						    } catch (error) { | 
					
					
						
						| 
							 | 
						      console.log('Failed to fetch local commit info:', error); | 
					
					
						
						| 
							 | 
						      throw new Error('Failed to fetch local commit info'); | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						  }, | 
					
					
						
						| 
							 | 
						}; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						function getSystemInfo(): SystemInfo { | 
					
					
						
						| 
							 | 
						  const formatBytes = (bytes: number): string => { | 
					
					
						
						| 
							 | 
						    if (bytes === 0) { | 
					
					
						
						| 
							 | 
						      return '0 Bytes'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    const k = 1024; | 
					
					
						
						| 
							 | 
						    const sizes = ['Bytes', 'KB', 'MB', 'GB']; | 
					
					
						
						| 
							 | 
						    const i = Math.floor(Math.log(bytes) / Math.log(k)); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const getBrowserInfo = (): string => { | 
					
					
						
						| 
							 | 
						    const ua = navigator.userAgent; | 
					
					
						
						| 
							 | 
						    let browser = 'Unknown'; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Firefox/')) { | 
					
					
						
						| 
							 | 
						      browser = 'Firefox'; | 
					
					
						
						| 
							 | 
						    } else if (ua.includes('Chrome/')) { | 
					
					
						
						| 
							 | 
						      if (ua.includes('Edg/')) { | 
					
					
						
						| 
							 | 
						        browser = 'Edge'; | 
					
					
						
						| 
							 | 
						      } else if (ua.includes('OPR/')) { | 
					
					
						
						| 
							 | 
						        browser = 'Opera'; | 
					
					
						
						| 
							 | 
						      } else { | 
					
					
						
						| 
							 | 
						        browser = 'Chrome'; | 
					
					
						
						| 
							 | 
						      } | 
					
					
						
						| 
							 | 
						    } else if (ua.includes('Safari/')) { | 
					
					
						
						| 
							 | 
						      if (!ua.includes('Chrome')) { | 
					
					
						
						| 
							 | 
						        browser = 'Safari'; | 
					
					
						
						| 
							 | 
						      } | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						    const match = ua.match(new RegExp(`${browser}\\/([\\d.]+)`)); | 
					
					
						
						| 
							 | 
						    const version = match ? ` ${match[1]}` : ''; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return `${browser}${version}`; | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const getOperatingSystem = (): string => { | 
					
					
						
						| 
							 | 
						    const ua = navigator.userAgent; | 
					
					
						
						| 
							 | 
						    const platform = navigator.platform; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Win')) { | 
					
					
						
						| 
							 | 
						      return 'Windows'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Mac')) { | 
					
					
						
						| 
							 | 
						      if (ua.includes('iPhone') || ua.includes('iPad')) { | 
					
					
						
						| 
							 | 
						        return 'iOS'; | 
					
					
						
						| 
							 | 
						      } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      return 'macOS'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Linux')) { | 
					
					
						
						| 
							 | 
						      return 'Linux'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Android')) { | 
					
					
						
						| 
							 | 
						      return 'Android'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return platform || 'Unknown'; | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const getDeviceType = (): string => { | 
					
					
						
						| 
							 | 
						    const ua = navigator.userAgent; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Mobile')) { | 
					
					
						
						| 
							 | 
						      return 'Mobile'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    if (ua.includes('Tablet')) { | 
					
					
						
						| 
							 | 
						      return 'Tablet'; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return 'Desktop'; | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						   | 
					
					
						
						| 
							 | 
						  const getMemoryInfo = (): string => { | 
					
					
						
						| 
							 | 
						    if ('memory' in performance) { | 
					
					
						
						| 
							 | 
						      const memory = (performance as any).memory; | 
					
					
						
						| 
							 | 
						      return `${formatBytes(memory.jsHeapSizeLimit)} (Used: ${formatBytes(memory.usedJSHeapSize)})`; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return 'Not available'; | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  return { | 
					
					
						
						| 
							 | 
						    os: getOperatingSystem(), | 
					
					
						
						| 
							 | 
						    browser: getBrowserInfo(), | 
					
					
						
						| 
							 | 
						    screen: `${window.screen.width}x${window.screen.height}`, | 
					
					
						
						| 
							 | 
						    language: navigator.language, | 
					
					
						
						| 
							 | 
						    timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, | 
					
					
						
						| 
							 | 
						    memory: getMemoryInfo(), | 
					
					
						
						| 
							 | 
						    cores: navigator.hardwareConcurrency || 0, | 
					
					
						
						| 
							 | 
						    deviceType: getDeviceType(), | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						    colorDepth: `${window.screen.colorDepth}-bit`, | 
					
					
						
						| 
							 | 
						    pixelRatio: window.devicePixelRatio, | 
					
					
						
						| 
							 | 
						    online: navigator.onLine, | 
					
					
						
						| 
							 | 
						    cookiesEnabled: navigator.cookieEnabled, | 
					
					
						
						| 
							 | 
						    doNotTrack: navigator.doNotTrack === '1', | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						const checkProviderStatus = async (url: string | null, providerName: string): Promise<ProviderStatus> => { | 
					
					
						
						| 
							 | 
						  if (!url) { | 
					
					
						
						| 
							 | 
						    console.log(`[Debug] No URL provided for ${providerName}`); | 
					
					
						
						| 
							 | 
						    return { | 
					
					
						
						| 
							 | 
						      name: providerName, | 
					
					
						
						| 
							 | 
						      enabled: false, | 
					
					
						
						| 
							 | 
						      isLocal: true, | 
					
					
						
						| 
							 | 
						      isRunning: false, | 
					
					
						
						| 
							 | 
						      error: 'No URL configured', | 
					
					
						
						| 
							 | 
						      lastChecked: new Date(), | 
					
					
						
						| 
							 | 
						      url: null, | 
					
					
						
						| 
							 | 
						    }; | 
					
					
						
						| 
							 | 
						  } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  console.log(`[Debug] Checking status for ${providerName} at ${url}`); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const startTime = performance.now(); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  try { | 
					
					
						
						| 
							 | 
						    if (providerName.toLowerCase() === 'ollama') { | 
					
					
						
						| 
							 | 
						       | 
					
					
						
						| 
							 | 
						      try { | 
					
					
						
						| 
							 | 
						        console.log(`[Debug] Checking Ollama root endpoint: ${url}`); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        const controller = new AbortController(); | 
					
					
						
						| 
							 | 
						        const timeoutId = setTimeout(() => controller.abort(), 5000);  | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        const response = await fetch(url, { | 
					
					
						
						| 
							 | 
						          signal: controller.signal, | 
					
					
						
						| 
							 | 
						          headers: { | 
					
					
						
						| 
							 | 
						            Accept: 'text/plain,application/json', | 
					
					
						
						| 
							 | 
						          }, | 
					
					
						
						| 
							 | 
						        }); | 
					
					
						
						| 
							 | 
						        clearTimeout(timeoutId); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        const text = await response.text(); | 
					
					
						
						| 
							 | 
						        console.log(`[Debug] Ollama root response:`, text); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        if (text.includes('Ollama is running')) { | 
					
					
						
						| 
							 | 
						          console.log(`[Debug] Ollama running confirmed via root endpoint`); | 
					
					
						
						| 
							 | 
						          return { | 
					
					
						
						| 
							 | 
						            name: providerName, | 
					
					
						
						| 
							 | 
						            enabled: false, | 
					
					
						
						| 
							 | 
						            isLocal: true, | 
					
					
						
						| 
							 | 
						            isRunning: true, | 
					
					
						
						| 
							 | 
						            lastChecked: new Date(), | 
					
					
						
						| 
							 | 
						            responseTime: performance.now() - startTime, | 
					
					
						
						| 
							 | 
						            url, | 
					
					
						
						| 
							 | 
						          }; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						      } catch (error) { | 
					
					
						
						| 
							 | 
						        console.log(`[Debug] Ollama root check failed:`, error); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        const errorMessage = error instanceof Error ? error.message : 'Unknown error'; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						        if (errorMessage.includes('aborted')) { | 
					
					
						
						| 
							 | 
						          return { | 
					
					
						
						| 
							 | 
						            name: providerName, | 
					
					
						
						| 
							 | 
						            enabled: false, | 
					
					
						
						| 
							 | 
						            isLocal: true, | 
					
					
						
						| 
							 | 
						            isRunning: false, | 
					
					
						
						| 
							 | 
						            error: 'Connection timeout', | 
					
					
						
						| 
							 | 
						            lastChecked: new Date(), | 
					
					
						
						| 
							 | 
						            responseTime: performance.now() - startTime, | 
					
					
						
						| 
							 | 
						            url, | 
					
					
						
						| 
							 | 
						          }; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						      } | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						     | 
					
					
						
						| 
							 | 
						    const checkUrls = [`${url}/api/health`, url.endsWith('v1') ? `${url}/models` : `${url}/v1/models`]; | 
					
					
						
						| 
							 | 
						    console.log(`[Debug] Checking additional endpoints:`, checkUrls); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    const results = await Promise.all( | 
					
					
						
						| 
							 | 
						      checkUrls.map(async (checkUrl) => { | 
					
					
						
						| 
							 | 
						        try { | 
					
					
						
						| 
							 | 
						          console.log(`[Debug] Trying endpoint: ${checkUrl}`); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						          const controller = new AbortController(); | 
					
					
						
						| 
							 | 
						          const timeoutId = setTimeout(() => controller.abort(), 5000); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						          const response = await fetch(checkUrl, { | 
					
					
						
						| 
							 | 
						            signal: controller.signal, | 
					
					
						
						| 
							 | 
						            headers: { | 
					
					
						
						| 
							 | 
						              Accept: 'application/json', | 
					
					
						
						| 
							 | 
						            }, | 
					
					
						
						| 
							 | 
						          }); | 
					
					
						
						| 
							 | 
						          clearTimeout(timeoutId); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						          const ok = response.ok; | 
					
					
						
						| 
							 | 
						          console.log(`[Debug] Endpoint ${checkUrl} response:`, ok); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						          if (ok) { | 
					
					
						
						| 
							 | 
						            try { | 
					
					
						
						| 
							 | 
						              const data = await response.json(); | 
					
					
						
						| 
							 | 
						              console.log(`[Debug] Endpoint ${checkUrl} data:`, data); | 
					
					
						
						| 
							 | 
						            } catch { | 
					
					
						
						| 
							 | 
						              console.log(`[Debug] Could not parse JSON from ${checkUrl}`); | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						          } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						          return ok; | 
					
					
						
						| 
							 | 
						        } catch (error) { | 
					
					
						
						| 
							 | 
						          console.log(`[Debug] Endpoint ${checkUrl} failed:`, error); | 
					
					
						
						| 
							 | 
						          return false; | 
					
					
						
						| 
							 | 
						        } | 
					
					
						
						| 
							 | 
						      }), | 
					
					
						
						| 
							 | 
						    ); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    const isRunning = results.some((result) => result); | 
					
					
						
						| 
							 | 
						    console.log(`[Debug] Final status for ${providerName}:`, isRunning); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return { | 
					
					
						
						| 
							 | 
						      name: providerName, | 
					
					
						
						| 
							 | 
						      enabled: false, | 
					
					
						
						| 
							 | 
						      isLocal: true, | 
					
					
						
						| 
							 | 
						      isRunning, | 
					
					
						
						| 
							 | 
						      lastChecked: new Date(), | 
					
					
						
						| 
							 | 
						      responseTime: performance.now() - startTime, | 
					
					
						
						| 
							 | 
						      url, | 
					
					
						
						| 
							 | 
						    }; | 
					
					
						
						| 
							 | 
						  } catch (error) { | 
					
					
						
						| 
							 | 
						    console.log(`[Debug] Provider check failed for ${providerName}:`, error); | 
					
					
						
						| 
							 | 
						    return { | 
					
					
						
						| 
							 | 
						      name: providerName, | 
					
					
						
						| 
							 | 
						      enabled: false, | 
					
					
						
						| 
							 | 
						      isLocal: true, | 
					
					
						
						| 
							 | 
						      isRunning: false, | 
					
					
						
						| 
							 | 
						      error: error instanceof Error ? error.message : 'Unknown error', | 
					
					
						
						| 
							 | 
						      lastChecked: new Date(), | 
					
					
						
						| 
							 | 
						      responseTime: performance.now() - startTime, | 
					
					
						
						| 
							 | 
						      url, | 
					
					
						
						| 
							 | 
						    }; | 
					
					
						
						| 
							 | 
						  } | 
					
					
						
						| 
							 | 
						}; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						export default function DebugTab() { | 
					
					
						
						| 
							 | 
						  const { providers, isLatestBranch } = useSettings(); | 
					
					
						
						| 
							 | 
						  const [activeProviders, setActiveProviders] = useState<ProviderStatus[]>([]); | 
					
					
						
						| 
							 | 
						  const [updateMessage, setUpdateMessage] = useState<string>(''); | 
					
					
						
						| 
							 | 
						  const [systemInfo] = useState<SystemInfo>(getSystemInfo()); | 
					
					
						
						| 
							 | 
						  const [isCheckingUpdate, setIsCheckingUpdate] = useState(false); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const updateProviderStatuses = async () => { | 
					
					
						
						| 
							 | 
						    if (!providers) { | 
					
					
						
						| 
							 | 
						      return; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    try { | 
					
					
						
						| 
							 | 
						      const entries = Object.entries(providers) as [string, IProviderConfig][]; | 
					
					
						
						| 
							 | 
						      const statuses = await Promise.all( | 
					
					
						
						| 
							 | 
						        entries | 
					
					
						
						| 
							 | 
						          .filter(([, provider]) => LOCAL_PROVIDERS.includes(provider.name)) | 
					
					
						
						| 
							 | 
						          .map(async ([, provider]) => { | 
					
					
						
						| 
							 | 
						            const envVarName = | 
					
					
						
						| 
							 | 
						              providerBaseUrlEnvKeys[provider.name].baseUrlKey || `REACT_APP_${provider.name.toUpperCase()}_URL`; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						             | 
					
					
						
						| 
							 | 
						            let settingsUrl = provider.settings.baseUrl; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						            if (settingsUrl && settingsUrl.trim().length === 0) { | 
					
					
						
						| 
							 | 
						              settingsUrl = undefined; | 
					
					
						
						| 
							 | 
						            } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						            const url = settingsUrl || import.meta.env[envVarName] || null;  | 
					
					
						
						| 
							 | 
						            console.log(`[Debug] Using URL for ${provider.name}:`, url, `(from ${envVarName})`); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						            const status = await checkProviderStatus(url, provider.name); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						            return { | 
					
					
						
						| 
							 | 
						              ...status, | 
					
					
						
						| 
							 | 
						              enabled: provider.settings.enabled ?? false, | 
					
					
						
						| 
							 | 
						            }; | 
					
					
						
						| 
							 | 
						          }), | 
					
					
						
						| 
							 | 
						      ); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      setActiveProviders(statuses); | 
					
					
						
						| 
							 | 
						    } catch (error) { | 
					
					
						
						| 
							 | 
						      console.error('[Debug] Failed to update provider statuses:', error); | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						  }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  useEffect(() => { | 
					
					
						
						| 
							 | 
						    updateProviderStatuses(); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    const interval = setInterval(updateProviderStatuses, 30000); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    return () => clearInterval(interval); | 
					
					
						
						| 
							 | 
						  }, [providers]); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const handleCheckForUpdate = useCallback(async () => { | 
					
					
						
						| 
							 | 
						    if (isCheckingUpdate) { | 
					
					
						
						| 
							 | 
						      return; | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    try { | 
					
					
						
						| 
							 | 
						      setIsCheckingUpdate(true); | 
					
					
						
						| 
							 | 
						      setUpdateMessage('Checking for updates...'); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      const branchToCheck = isLatestBranch ? 'main' : 'stable'; | 
					
					
						
						| 
							 | 
						      console.log(`[Debug] Checking for updates against ${branchToCheck} branch`); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      const latestCommitResp = await GITHUB_URLS.commitJson(branchToCheck); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      const remoteCommitHash = latestCommitResp.commit; | 
					
					
						
						| 
							 | 
						      const currentCommitHash = versionHash; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						      if (remoteCommitHash !== currentCommitHash) { | 
					
					
						
						| 
							 | 
						        setUpdateMessage( | 
					
					
						
						| 
							 | 
						          `Update available from ${branchToCheck} branch!\n` + | 
					
					
						
						| 
							 | 
						            `Current: ${currentCommitHash.slice(0, 7)}\n` + | 
					
					
						
						| 
							 | 
						            `Latest: ${remoteCommitHash.slice(0, 7)}`, | 
					
					
						
						| 
							 | 
						        ); | 
					
					
						
						| 
							 | 
						      } else { | 
					
					
						
						| 
							 | 
						        setUpdateMessage(`You are on the latest version from the ${branchToCheck} branch`); | 
					
					
						
						| 
							 | 
						      } | 
					
					
						
						| 
							 | 
						    } catch (error) { | 
					
					
						
						| 
							 | 
						      setUpdateMessage('Failed to check for updates'); | 
					
					
						
						| 
							 | 
						      console.error('[Debug] Failed to check for updates:', error); | 
					
					
						
						| 
							 | 
						    } finally { | 
					
					
						
						| 
							 | 
						      setIsCheckingUpdate(false); | 
					
					
						
						| 
							 | 
						    } | 
					
					
						
						| 
							 | 
						  }, [isCheckingUpdate, isLatestBranch]); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  const handleCopyToClipboard = useCallback(() => { | 
					
					
						
						| 
							 | 
						    const debugInfo = { | 
					
					
						
						| 
							 | 
						      System: systemInfo, | 
					
					
						
						| 
							 | 
						      Providers: activeProviders.map((provider) => ({ | 
					
					
						
						| 
							 | 
						        name: provider.name, | 
					
					
						
						| 
							 | 
						        enabled: provider.enabled, | 
					
					
						
						| 
							 | 
						        isLocal: provider.isLocal, | 
					
					
						
						| 
							 | 
						        running: provider.isRunning, | 
					
					
						
						| 
							 | 
						        error: provider.error, | 
					
					
						
						| 
							 | 
						        lastChecked: provider.lastChecked, | 
					
					
						
						| 
							 | 
						        responseTime: provider.responseTime, | 
					
					
						
						| 
							 | 
						        url: provider.url, | 
					
					
						
						| 
							 | 
						      })), | 
					
					
						
						| 
							 | 
						      Version: { | 
					
					
						
						| 
							 | 
						        hash: versionHash.slice(0, 7), | 
					
					
						
						| 
							 | 
						        branch: isLatestBranch ? 'main' : 'stable', | 
					
					
						
						| 
							 | 
						      }, | 
					
					
						
						| 
							 | 
						      Timestamp: new Date().toISOString(), | 
					
					
						
						| 
							 | 
						    }; | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						    navigator.clipboard.writeText(JSON.stringify(debugInfo, null, 2)).then(() => { | 
					
					
						
						| 
							 | 
						      toast.success('Debug information copied to clipboard!'); | 
					
					
						
						| 
							 | 
						    }); | 
					
					
						
						| 
							 | 
						  }, [activeProviders, systemInfo, isLatestBranch]); | 
					
					
						
						| 
							 | 
						
 | 
					
					
						
						| 
							 | 
						  return ( | 
					
					
						
						| 
							 | 
						    <div className="p-4 space-y-6"> | 
					
					
						
						| 
							 | 
						      <div className="flex items-center justify-between"> | 
					
					
						
						| 
							 | 
						        <h3 className="text-lg font-medium text-bolt-elements-textPrimary">Debug Information</h3> | 
					
					
						
						| 
							 | 
						        <div className="flex gap-2"> | 
					
					
						
						| 
							 | 
						          <button | 
					
					
						
						| 
							 | 
						            onClick={handleCopyToClipboard} | 
					
					
						
						| 
							 | 
						            className="bg-bolt-elements-button-primary-background rounded-lg px-4 py-2 transition-colors duration-200 hover:bg-bolt-elements-button-primary-backgroundHover text-bolt-elements-button-primary-text" | 
					
					
						
						| 
							 | 
						          > | 
					
					
						
						| 
							 | 
						            Copy Debug Info | 
					
					
						
						| 
							 | 
						          </button> | 
					
					
						
						| 
							 | 
						          <button | 
					
					
						
						| 
							 | 
						            onClick={handleCheckForUpdate} | 
					
					
						
						| 
							 | 
						            disabled={isCheckingUpdate} | 
					
					
						
						| 
							 | 
						            className={`bg-bolt-elements-button-primary-background rounded-lg px-4 py-2 transition-colors duration-200 | 
					
					
						
						| 
							 | 
						              ${!isCheckingUpdate ? 'hover:bg-bolt-elements-button-primary-backgroundHover' : 'opacity-75 cursor-not-allowed'} | 
					
					
						
						| 
							 | 
						              text-bolt-elements-button-primary-text`} | 
					
					
						
						| 
							 | 
						          > | 
					
					
						
						| 
							 | 
						            {isCheckingUpdate ? 'Checking...' : 'Check for Updates'} | 
					
					
						
						| 
							 | 
						          </button> | 
					
					
						
						| 
							 | 
						        </div> | 
					
					
						
						| 
							 | 
						      </div> | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						      {updateMessage && ( | 
					
					
						
						| 
							 | 
						        <div | 
					
					
						
						| 
							 | 
						          className={`bg-bolt-elements-surface rounded-lg p-3 ${ | 
					
					
						
						| 
							 | 
						            updateMessage.includes('Update available') ? 'border-l-4 border-yellow-400' : '' | 
					
					
						
						| 
							 | 
						          }`} | 
					
					
						
						| 
							 | 
						        > | 
					
					
						
						| 
							 | 
						          <p className="text-bolt-elements-textSecondary whitespace-pre-line">{updateMessage}</p> | 
					
					
						
						| 
							 | 
						          {updateMessage.includes('Update available') && ( | 
					
					
						
						| 
							 | 
						            <div className="mt-3 text-sm"> | 
					
					
						
						| 
							 | 
						              <p className="font-medium text-bolt-elements-textPrimary">To update:</p> | 
					
					
						
						| 
							 | 
						              <ol className="list-decimal ml-4 mt-1 text-bolt-elements-textSecondary"> | 
					
					
						
						| 
							 | 
						                <li> | 
					
					
						
						| 
							 | 
						                  Pull the latest changes:{' '} | 
					
					
						
						| 
							 | 
						                  <code className="bg-bolt-elements-surface-hover px-1 rounded">git pull upstream main</code> | 
					
					
						
						| 
							 | 
						                </li> | 
					
					
						
						| 
							 | 
						                <li> | 
					
					
						
						| 
							 | 
						                  Install any new dependencies:{' '} | 
					
					
						
						| 
							 | 
						                  <code className="bg-bolt-elements-surface-hover px-1 rounded">pnpm install</code> | 
					
					
						
						| 
							 | 
						                </li> | 
					
					
						
						| 
							 | 
						                <li>Restart the application</li> | 
					
					
						
						| 
							 | 
						              </ol> | 
					
					
						
						| 
							 | 
						            </div> | 
					
					
						
						| 
							 | 
						          )} | 
					
					
						
						| 
							 | 
						        </div> | 
					
					
						
						| 
							 | 
						      )} | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						      <section className="space-y-4"> | 
					
					
						
						| 
							 | 
						        <div> | 
					
					
						
						| 
							 | 
						          <h4 className="text-md font-medium text-bolt-elements-textPrimary mb-2">System Information</h4> | 
					
					
						
						| 
							 | 
						          <div className="bg-bolt-elements-surface rounded-lg p-4"> | 
					
					
						
						| 
							 | 
						            <div className="grid grid-cols-2 md:grid-cols-3 gap-4"> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Operating System</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.os}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Device Type</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.deviceType}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Browser</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.browser}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Display</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary"> | 
					
					
						
						| 
							 | 
						                  {systemInfo.screen} ({systemInfo.colorDepth}) @{systemInfo.pixelRatio}x | 
					
					
						
						| 
							 | 
						                </p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Connection</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium flex items-center gap-2"> | 
					
					
						
						| 
							 | 
						                  <span | 
					
					
						
						| 
							 | 
						                    className={`inline-block w-2 h-2 rounded-full ${systemInfo.online ? 'bg-green-500' : 'bg-red-500'}`} | 
					
					
						
						| 
							 | 
						                  /> | 
					
					
						
						| 
							 | 
						                  <span className={`${systemInfo.online ? 'text-green-600' : 'text-red-600'}`}> | 
					
					
						
						| 
							 | 
						                    {systemInfo.online ? 'Online' : 'Offline'} | 
					
					
						
						| 
							 | 
						                  </span> | 
					
					
						
						| 
							 | 
						                </p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Screen Resolution</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.screen}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Language</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.language}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">Timezone</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.timezone}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						              <div> | 
					
					
						
						| 
							 | 
						                <p className="text-xs text-bolt-elements-textSecondary">CPU Cores</p> | 
					
					
						
						| 
							 | 
						                <p className="text-sm font-medium text-bolt-elements-textPrimary">{systemInfo.cores}</p> | 
					
					
						
						| 
							 | 
						              </div> | 
					
					
						
						| 
							 | 
						            </div> | 
					
					
						
						| 
							 | 
						            <div className="mt-3 pt-3 border-t border-bolt-elements-surface-hover"> | 
					
					
						
						| 
							 | 
						              <p className="text-xs text-bolt-elements-textSecondary">Version</p> | 
					
					
						
						| 
							 | 
						              <p className="text-sm font-medium text-bolt-elements-textPrimary font-mono"> | 
					
					
						
						| 
							 | 
						                {connitJson.commit.slice(0, 7)} | 
					
					
						
						| 
							 | 
						                <span className="ml-2 text-xs text-bolt-elements-textSecondary"> | 
					
					
						
						| 
							 | 
						                  (v{versionTag || '0.0.1'}) - {isLatestBranch ? 'nightly' : 'stable'} | 
					
					
						
						| 
							 | 
						                </span> | 
					
					
						
						| 
							 | 
						              </p> | 
					
					
						
						| 
							 | 
						            </div> | 
					
					
						
						| 
							 | 
						          </div> | 
					
					
						
						| 
							 | 
						        </div> | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						        <div> | 
					
					
						
						| 
							 | 
						          <h4 className="text-md font-medium text-bolt-elements-textPrimary mb-2">Local LLM Status</h4> | 
					
					
						
						| 
							 | 
						          <div className="bg-bolt-elements-surface rounded-lg"> | 
					
					
						
						| 
							 | 
						            <div className="grid grid-cols-1 divide-y"> | 
					
					
						
						| 
							 | 
						              {activeProviders.map((provider) => ( | 
					
					
						
						| 
							 | 
						                <div key={provider.name} className="p-3 flex flex-col space-y-2"> | 
					
					
						
						| 
							 | 
						                  <div className="flex items-center justify-between"> | 
					
					
						
						| 
							 | 
						                    <div className="flex items-center gap-3"> | 
					
					
						
						| 
							 | 
						                      <div className="flex-shrink-0"> | 
					
					
						
						| 
							 | 
						                        <div | 
					
					
						
						| 
							 | 
						                          className={`w-2 h-2 rounded-full ${ | 
					
					
						
						| 
							 | 
						                            !provider.enabled ? 'bg-gray-300' : provider.isRunning ? 'bg-green-400' : 'bg-red-400' | 
					
					
						
						| 
							 | 
						                          }`} | 
					
					
						
						| 
							 | 
						                        /> | 
					
					
						
						| 
							 | 
						                      </div> | 
					
					
						
						| 
							 | 
						                      <div> | 
					
					
						
						| 
							 | 
						                        <p className="text-sm font-medium text-bolt-elements-textPrimary">{provider.name}</p> | 
					
					
						
						| 
							 | 
						                        {provider.url && ( | 
					
					
						
						| 
							 | 
						                          <p className="text-xs text-bolt-elements-textSecondary truncate max-w-[300px]"> | 
					
					
						
						| 
							 | 
						                            {provider.url} | 
					
					
						
						| 
							 | 
						                          </p> | 
					
					
						
						| 
							 | 
						                        )} | 
					
					
						
						| 
							 | 
						                      </div> | 
					
					
						
						| 
							 | 
						                    </div> | 
					
					
						
						| 
							 | 
						                    <div className="flex items-center gap-2"> | 
					
					
						
						| 
							 | 
						                      <span | 
					
					
						
						| 
							 | 
						                        className={`px-2 py-0.5 text-xs rounded-full ${ | 
					
					
						
						| 
							 | 
						                          provider.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' | 
					
					
						
						| 
							 | 
						                        }`} | 
					
					
						
						| 
							 | 
						                      > | 
					
					
						
						| 
							 | 
						                        {provider.enabled ? 'Enabled' : 'Disabled'} | 
					
					
						
						| 
							 | 
						                      </span> | 
					
					
						
						| 
							 | 
						                      {provider.enabled && ( | 
					
					
						
						| 
							 | 
						                        <span | 
					
					
						
						| 
							 | 
						                          className={`px-2 py-0.5 text-xs rounded-full ${ | 
					
					
						
						| 
							 | 
						                            provider.isRunning ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800' | 
					
					
						
						| 
							 | 
						                          }`} | 
					
					
						
						| 
							 | 
						                        > | 
					
					
						
						| 
							 | 
						                          {provider.isRunning ? 'Running' : 'Not Running'} | 
					
					
						
						| 
							 | 
						                        </span> | 
					
					
						
						| 
							 | 
						                      )} | 
					
					
						
						| 
							 | 
						                    </div> | 
					
					
						
						| 
							 | 
						                  </div> | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						                  <div className="pl-5 flex flex-col space-y-1 text-xs"> | 
					
					
						
						| 
							 | 
						                    {/* Status Details */} | 
					
					
						
						| 
							 | 
						                    <div className="flex flex-wrap gap-2"> | 
					
					
						
						| 
							 | 
						                      <span className="text-bolt-elements-textSecondary"> | 
					
					
						
						| 
							 | 
						                        Last checked: {new Date(provider.lastChecked).toLocaleTimeString()} | 
					
					
						
						| 
							 | 
						                      </span> | 
					
					
						
						| 
							 | 
						                      {provider.responseTime && ( | 
					
					
						
						| 
							 | 
						                        <span className="text-bolt-elements-textSecondary"> | 
					
					
						
						| 
							 | 
						                          Response time: {Math.round(provider.responseTime)}ms | 
					
					
						
						| 
							 | 
						                        </span> | 
					
					
						
						| 
							 | 
						                      )} | 
					
					
						
						| 
							 | 
						                    </div> | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						                    {/* Error Message */} | 
					
					
						
						| 
							 | 
						                    {provider.error && ( | 
					
					
						
						| 
							 | 
						                      <div className="mt-1 text-red-600 bg-red-50 rounded-md p-2"> | 
					
					
						
						| 
							 | 
						                        <span className="font-medium">Error:</span> {provider.error} | 
					
					
						
						| 
							 | 
						                      </div> | 
					
					
						
						| 
							 | 
						                    )} | 
					
					
						
						| 
							 | 
						 | 
					
					
						
						| 
							 | 
						                    {/* Connection Info */} | 
					
					
						
						| 
							 | 
						                    {provider.url && ( | 
					
					
						
						| 
							 | 
						                      <div className="text-bolt-elements-textSecondary"> | 
					
					
						
						| 
							 | 
						                        <span className="font-medium">Endpoints checked:</span> | 
					
					
						
						| 
							 | 
						                        <ul className="list-disc list-inside pl-2 mt-1"> | 
					
					
						
						| 
							 | 
						                          <li>{provider.url} (root)</li> | 
					
					
						
						| 
							 | 
						                          <li>{provider.url}/api/health</li> | 
					
					
						
						| 
							 | 
						                          <li>{provider.url}/v1/models</li> | 
					
					
						
						| 
							 | 
						                        </ul> | 
					
					
						
						| 
							 | 
						                      </div> | 
					
					
						
						| 
							 | 
						                    )} | 
					
					
						
						| 
							 | 
						                  </div> | 
					
					
						
						| 
							 | 
						                </div> | 
					
					
						
						| 
							 | 
						              ))} | 
					
					
						
						| 
							 | 
						              {activeProviders.length === 0 && ( | 
					
					
						
						| 
							 | 
						                <div className="p-4 text-center text-bolt-elements-textSecondary">No local LLMs configured</div> | 
					
					
						
						| 
							 | 
						              )} | 
					
					
						
						| 
							 | 
						            </div> | 
					
					
						
						| 
							 | 
						          </div> | 
					
					
						
						| 
							 | 
						        </div> | 
					
					
						
						| 
							 | 
						      </section> | 
					
					
						
						| 
							 | 
						    </div> | 
					
					
						
						| 
							 | 
						  ); | 
					
					
						
						| 
							 | 
						} | 
					
					
						
						| 
							 | 
						
 |