|
|
@@ -1,3 +1,5 @@
|
|
|
+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';
|
|
|
|
|
|
@@ -34,12 +36,51 @@ 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;
|
|
|
}
|
|
|
@@ -52,6 +93,10 @@ class ServerStore {
|
|
|
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;
|
|
|
@@ -123,30 +168,43 @@ class ServerStore {
|
|
|
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')) {
|
|
|
@@ -154,7 +212,37 @@ class ServerStore {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- 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;
|
|
|
@@ -167,8 +255,10 @@ class ServerStore {
|
|
|
clear(): void {
|
|
|
this._serverProps = null;
|
|
|
this._error = null;
|
|
|
+ this._serverWarning = null;
|
|
|
this._loading = false;
|
|
|
this._slotsEndpointAvailable = null;
|
|
|
+ this.persistServerProps(null);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -177,6 +267,7 @@ export const serverStore = new ServerStore();
|
|
|
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;
|