feat(conversation): improve OpenWebUI error handling and parsing

This commit is contained in:
cogwheel0
2025-12-15 20:42:09 +05:30
parent 008c77612a
commit 45532bf78f
5 changed files with 211 additions and 20 deletions

View File

@@ -191,6 +191,57 @@ List<Map<String, dynamic>>? _extractToolCalls(
return null;
}
/// Extract error data from OpenWebUI message format.
/// OpenWebUI stores errors in a separate 'error' field with 'content' inside.
/// Returns a map suitable for ChatMessageError.fromJson().
Map<String, dynamic>? _extractErrorData(
Map<String, dynamic> msgData,
Map<String, dynamic>? historyMsg,
) {
// Check msgData first, then historyMsg
final errorRaw = msgData['error'] ?? historyMsg?['error'];
if (errorRaw == null) return null;
// Handle different error formats from OpenWebUI
if (errorRaw is Map) {
// Most common: { error: { content: "error message" } }
final content = errorRaw['content'];
if (content is String && content.isNotEmpty) {
return {'content': content};
}
// Alternative: { error: { message: "error message" } }
final message = errorRaw['message'];
if (message is String && message.isNotEmpty) {
return {'content': message};
}
// Nested error: { error: { error: { message: "..." } } }
final nestedError = errorRaw['error'];
if (nestedError is Map) {
final nestedMessage = nestedError['message'];
if (nestedMessage is String && nestedMessage.isNotEmpty) {
return {'content': nestedMessage};
}
}
// FastAPI detail format: { detail: "..." }
final detail = errorRaw['detail'];
if (detail is String && detail.isNotEmpty) {
return {'content': detail};
}
// If it's a map but we couldn't extract content, still return an error
// to indicate there was an error (matches legacy error === true behavior)
return const {'content': null};
} else if (errorRaw is String && errorRaw.isNotEmpty) {
// Simple string error
return {'content': errorRaw};
} else if (errorRaw == true) {
// Legacy format: error === true means content IS the error message
// Return a marker so the UI knows this is an error message
return const {'content': null};
}
return null;
}
Map<String, dynamic> _parseOpenWebUIMessageToJson(
Map<String, dynamic> msgData, {
Map<String, dynamic>? historyMsg,
@@ -253,6 +304,9 @@ Map<String, dynamic> _parseOpenWebUIMessageToJson(
}
}
// Extract error field from OpenWebUI - preserve it separately for round-trip
final errorData = _extractErrorData(msgData, historyMsg);
final role = _resolveRole(msgData);
final effectiveFiles = msgData['files'] ?? historyMsg?['files'];
@@ -325,6 +379,7 @@ Map<String, dynamic> _parseOpenWebUIMessageToJson(
'sources': _parseSourcesField(sourcesRaw),
'usage': usage,
'versions': const <Map<String, dynamic>>[],
if (errorData != null) 'error': errorData,
};
}