feat(cache): Add lightweight in-memory cache with TTL and LRU eviction

This commit is contained in:
cogwheel0
2025-11-22 21:53:14 +05:30
parent 8ed75f8f14
commit c4a36bb51c
14 changed files with 1298 additions and 242 deletions

View File

@@ -35,16 +35,27 @@ class BackendConfig {
}
Map<String, dynamic> toJson() {
return <String, dynamic>{'enable_websocket': enableWebsocket};
return <String, dynamic>{
'enable_websocket': enableWebsocket,
};
}
static BackendConfig fromJson(Map<String, dynamic> json) {
bool? enableWebsocket;
final features = json['features'];
if (features is Map<String, dynamic>) {
final value = features['enable_websocket'];
if (value is bool) {
enableWebsocket = value;
// Try canonical format first
final value = json['enable_websocket'];
if (value is bool) {
enableWebsocket = value;
}
// Fallback to nested format for backwards compatibility
if (enableWebsocket == null) {
final features = json['features'];
if (features is Map<String, dynamic>) {
final nestedValue = features['enable_websocket'];
if (nestedValue is bool) {
enableWebsocket = nestedValue;
}
}
}

View File

@@ -20,6 +20,18 @@ sealed class Model with _$Model {
}) = _Model;
factory Model.fromJson(Map<String, dynamic> json) {
final cachedIsMultimodal = switch (json['isMultimodal']) {
final bool value => value,
_ => json['is_multimodal'] is bool ? json['is_multimodal'] as bool : null,
};
final cachedSupportsStreaming = switch (json['supportsStreaming']) {
final bool value => value,
_ =>
json['supports_streaming'] is bool
? json['supports_streaming'] as bool
: null,
};
// Handle different response formats from OpenWebUI
// Extract architecture info for capabilities
@@ -29,8 +41,9 @@ sealed class Model with _$Model {
// Determine if multimodal based on architecture
final isMultimodal =
modality?.contains('image') == true ||
inputModalities?.contains('image') == true;
cachedIsMultimodal ??
(modality?.contains('image') == true ||
inputModalities?.contains('image') == true);
// Extract supported parameters robustly (top-level or nested under provider keys)
List? supportedParams =
@@ -63,7 +76,8 @@ sealed class Model with _$Model {
}
// Determine streaming support from supported parameters if known
final supportsStreaming = supportedParams?.contains('stream') ?? true;
final supportsStreaming =
cachedSupportsStreaming ?? supportedParams?.contains('stream') ?? true;
// Convert supported parameters to List<String> if present
final supportedParamsList = supportedParams
@@ -154,4 +168,22 @@ sealed class Model with _$Model {
toolIds: toolIds,
);
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{
'id': id,
'name': name,
'description': description,
'isMultimodal': isMultimodal,
'supportsStreaming': supportsStreaming,
'supportsRAG': supportsRAG,
'supported_parameters': supportedParameters,
'capabilities': capabilities,
'metadata': metadata,
'architecture': capabilities?['architecture'],
'toolIds': toolIds,
};
data.removeWhere((_, value) => value == null);
return data;
}
}

View File

@@ -0,0 +1,23 @@
class SocketTransportAvailability {
const SocketTransportAvailability({
required this.allowPolling,
required this.allowWebsocketOnly,
});
final bool allowPolling;
final bool allowWebsocketOnly;
Map<String, dynamic> toJson() {
return {
'allowPolling': allowPolling,
'allowWebsocketOnly': allowWebsocketOnly,
};
}
factory SocketTransportAvailability.fromJson(Map<String, dynamic> json) {
return SocketTransportAvailability(
allowPolling: json['allowPolling'] == true,
allowWebsocketOnly: json['allowWebsocketOnly'] == true,
);
}
}

View File

@@ -23,4 +23,14 @@ sealed class Tool with _$Tool {
meta: json['meta'] as Map<String, dynamic>?,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'description': description,
'user_id': userId,
'meta': meta,
};
}
}

View File

@@ -30,4 +30,16 @@ sealed class User with _$User {
isActive: json['is_active'] as bool? ?? json['isActive'] as bool? ?? true,
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'username': username,
'email': email,
'name': name,
'profile_image_url': profileImage,
'role': role,
'is_active': isActive,
};
}
}