feat(web): Integrate M4-LLM error handling improvements
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline failed

Port high-value features from work/m4-llm branch into develop's
security-hardened codebase:

- Separate LLM vs persistence error handling in useChat (shows
  assistant response even when save fails)
- Add structured error context logging with errorType, messagePreview,
  messageCount fields for debugging
- Enforce state invariant in useChatOverlay: cannot be minimized when
  closed
- Add onStorageError callback with user-friendly messages and
  per-error-type deduplication
- Add error logging to Chat imperative handle methods
- Create Chat.test.tsx with loadConversation failure mode tests

Skipped from work/m4-llm (superseded by develop):
- AbortSignal timeout (develop has centralized client timeout)
- Custom toast system (duplicates @mosaic/ui)
- ErrorBoundary (develop has its own)
- WebSocket typed events (develop's ref-based pattern is superior)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-06 20:04:53 -06:00
parent ac796072d8
commit 893a139087
8 changed files with 598 additions and 17 deletions

View File

@@ -208,12 +208,33 @@ export function useChat(options: UseChatOptions = {}): UseChatReturn {
? generateTitle(content)
: (conversationTitle ?? "Chat Conversation");
// Save conversation
await saveConversation(finalMessages, title);
// Save conversation (separate error handling from LLM errors)
try {
await saveConversation(finalMessages, title);
} catch (saveErr) {
const saveErrorMsg =
saveErr instanceof Error ? saveErr.message : "Unknown persistence error";
setError(`Message sent but failed to save: ${saveErrorMsg}`);
console.error("Failed to save conversation", {
error: saveErr,
errorType: "PERSISTENCE_ERROR",
conversationId,
});
}
} catch (err) {
const errorMsg = err instanceof Error ? err.message : "Failed to send message";
setError(errorMsg);
onError?.(err instanceof Error ? err : new Error(errorMsg));
console.error("Failed to send chat message", {
error: err,
errorType: "LLM_ERROR",
conversationId,
messageLength: content.length,
messagePreview: content.substring(0, 50),
model,
messageCount: messagesRef.current.length,
timestamp: new Date().toISOString(),
});
// Add error message to chat
const errorMessage: Message = {