--- /dev/null
+<script lang="ts">
+ import { AlertTriangle, RefreshCw } from '@lucide/svelte';
+ import { serverLoading, serverStore } from '$lib/stores/server.svelte';
+ import { fly } from 'svelte/transition';
+
+ interface Props {
+ class?: string;
+ }
+
+ let { class: className = '' }: Props = $props();
+
+ function handleRefreshServer() {
+ serverStore.fetchServerProps();
+ }
+</script>
+
+<div class="mb-3 {className}" in:fly={{ y: 10, duration: 250 }}>
+ <div
+ class="rounded-md border border-yellow-200 bg-yellow-50 px-3 py-2 dark:border-yellow-800 dark:bg-yellow-950"
+ >
+ <div class="flex items-center justify-between">
+ <div class="flex items-center">
+ <AlertTriangle class="h-4 w-4 text-yellow-600 dark:text-yellow-400" />
+ <p class="ml-2 text-sm text-yellow-800 dark:text-yellow-200">
+ Server `/props` endpoint not available - using cached data
+ </p>
+ </div>
+ <button
+ onclick={handleRefreshServer}
+ disabled={serverLoading()}
+ class="ml-3 flex items-center gap-1.5 rounded bg-yellow-100 px-2 py-1 text-xs font-medium text-yellow-800 hover:bg-yellow-200 disabled:opacity-50 dark:bg-yellow-900 dark:text-yellow-200 dark:hover:bg-yellow-800"
+ >
+ <RefreshCw class="h-3 w-3 {serverLoading() ? 'animate-spin' : ''}" />
+ {serverLoading() ? 'Checking...' : 'Retry'}
+ </button>
+ </div>
+ </div>
+</div>
+import { browser } from '$app/environment';
+import { SERVER_PROPS_LOCALSTORAGE_KEY } from '$lib/constants/localstorage-keys';
import { ChatService } from '$lib/services/chat';
import { config } from '$lib/stores/settings.svelte';
* - Slots endpoint availability (for processing state monitoring)
* - Context window size and token limits
*/
+
class ServerStore {
+ constructor() {
+ if (!browser) return;
+
+ const cachedProps = this.readCachedServerProps();
+ if (cachedProps) {
+ this._serverProps = cachedProps;
+ }
+ }
+
private _serverProps = $state<ApiLlamaCppServerProps | null>(null);
private _loading = $state(false);
private _error = $state<string | null>(null);
+ private _serverWarning = $state<string | null>(null);
private _slotsEndpointAvailable = $state<boolean | null>(null);
+ private readCachedServerProps(): ApiLlamaCppServerProps | null {
+ if (!browser) return null;
+
+ try {
+ const raw = localStorage.getItem(SERVER_PROPS_LOCALSTORAGE_KEY);
+ if (!raw) return null;
+
+ return JSON.parse(raw) as ApiLlamaCppServerProps;
+ } catch (error) {
+ console.warn('Failed to read cached server props from localStorage:', error);
+ return null;
+ }
+ }
+
+ private persistServerProps(props: ApiLlamaCppServerProps | null): void {
+ if (!browser) return;
+
+ try {
+ if (props) {
+ localStorage.setItem(SERVER_PROPS_LOCALSTORAGE_KEY, JSON.stringify(props));
+ } else {
+ localStorage.removeItem(SERVER_PROPS_LOCALSTORAGE_KEY);
+ }
+ } catch (error) {
+ console.warn('Failed to persist server props to localStorage:', error);
+ }
+ }
+
get serverProps(): ApiLlamaCppServerProps | null {
return this._serverProps;
}
return this._error;
}
+ get serverWarning(): string | null {
+ return this._serverWarning;
+ }
+
get modelName(): string | null {
if (!this._serverProps?.model_path) return null;
return this._serverProps.model_path.split(/(\\|\/)/).pop() || null;
async fetchServerProps(): Promise<void> {
this._loading = true;
this._error = null;
+ this._serverWarning = null;
try {
console.log('Fetching server properties...');
const props = await ChatService.getServerProps();
this._serverProps = props;
+ this.persistServerProps(props);
console.log('Server properties loaded:', props);
// Check slots endpoint availability after server props are loaded
await this.checkSlotsEndpointAvailability();
} catch (error) {
+ const hadCachedProps = this._serverProps !== null;
let errorMessage = 'Failed to connect to server';
+ let isOfflineLikeError = false;
+ let isServerSideError = false;
if (error instanceof Error) {
// Handle specific error types with user-friendly messages
if (error.name === 'TypeError' && error.message.includes('fetch')) {
errorMessage = 'Server is not running or unreachable';
+ isOfflineLikeError = true;
} else if (error.message.includes('ECONNREFUSED')) {
errorMessage = 'Connection refused - server may be offline';
+ isOfflineLikeError = true;
} else if (error.message.includes('ENOTFOUND')) {
errorMessage = 'Server not found - check server address';
+ isOfflineLikeError = true;
} else if (error.message.includes('ETIMEDOUT')) {
errorMessage = 'Connection timeout - server may be overloaded';
+ isOfflineLikeError = true;
+ } else if (error.message.includes('503')) {
+ errorMessage = 'Server temporarily unavailable - try again shortly';
+ isServerSideError = true;
} else if (error.message.includes('500')) {
errorMessage = 'Server error - check server logs';
+ isServerSideError = true;
} else if (error.message.includes('404')) {
errorMessage = 'Server endpoint not found';
} else if (error.message.includes('403') || error.message.includes('401')) {
}
}
- this._error = errorMessage;
+ let cachedProps: ApiLlamaCppServerProps | null = null;
+
+ if (!hadCachedProps) {
+ cachedProps = this.readCachedServerProps();
+ if (cachedProps) {
+ this._serverProps = cachedProps;
+ this._error = null;
+
+ if (isOfflineLikeError || isServerSideError) {
+ this._serverWarning = errorMessage;
+ }
+
+ console.warn(
+ 'Failed to refresh server properties, using cached values from localStorage:',
+ errorMessage
+ );
+ } else {
+ this._error = errorMessage;
+ }
+ } else {
+ this._error = null;
+
+ if (isOfflineLikeError || isServerSideError) {
+ this._serverWarning = errorMessage;
+ }
+
+ console.warn(
+ 'Failed to refresh server properties, continuing with cached values:',
+ errorMessage
+ );
+ }
console.error('Error fetching server properties:', error);
} finally {
this._loading = false;
clear(): void {
this._serverProps = null;
this._error = null;
+ this._serverWarning = null;
this._loading = false;
this._slotsEndpointAvailable = null;
+ this.persistServerProps(null);
}
}
export const serverProps = () => serverStore.serverProps;
export const serverLoading = () => serverStore.loading;
export const serverError = () => serverStore.error;
+export const serverWarning = () => serverStore.serverWarning;
export const modelName = () => serverStore.modelName;
export const supportedModalities = () => serverStore.supportedModalities;
export const supportsVision = () => serverStore.supportsVision;