Skip to content

feat: Persistent AlgoBot chat history with localStorage + clear button (closes #14)#63

Open
arcgod-design wants to merge 2 commits into
rishabhx29:mainfrom
arcgod-design:feat/issue-14-chat-history
Open

feat: Persistent AlgoBot chat history with localStorage + clear button (closes #14)#63
arcgod-design wants to merge 2 commits into
rishabhx29:mainfrom
arcgod-design:feat/issue-14-chat-history

Conversation

@arcgod-design

@arcgod-design arcgod-design commented Jun 30, 2026

Copy link
Copy Markdown

Related Issue

Closes #14

Description

AlgoBot's chat history now persists across page navigation and browser refresh using localStorage. Messages are capped at 20 to prevent unbounded storage growth. A "Clear Chat" button in the header lets users reset the conversation. localStorage access is wrapped in try/catch for private browsing compatibility.

Type of Change

  • New feature
  • Bug fix
  • UI/styling change
  • Documentation update
  • Other (describe):

Screenshots

No visual changes — the Clear Chat button (trash icon) appears in the AlgoBot header only when a conversation has started.

Checklist

  • I have created/linked an issue before opening this PR
  • My code follows the existing code style of the project
  • I have tested my changes locally
  • No new dependencies were added (or I have explained why)
  • I have read the CONTRIBUTING.md

Summary by CodeRabbit

  • New Features
    • Chat conversations now persist between visits, allowing you to pick up where you left off after reloading.
    • Added a Clear Chat button to quickly reset the conversation and start fresh.
  • Bug Fixes
    • Prevents the welcome message from being stored as part of the ongoing chat history.
    • Limits how much stored conversation is retained to keep history consistent and manageable.

@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the rishabhjtripathi2903-3434's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d17223ea-31f1-4ee3-abfb-f9f8975067bb

📥 Commits

Reviewing files that changed from the base of the PR and between 3d901b1 and 678ac64.

📒 Files selected for processing (1)
  • app/src/components/custom/AlgoBot.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/components/custom/AlgoBot.tsx

📝 Walkthrough

Walkthrough

AlgoBot.tsx gains localStorage-backed chat persistence. New constants and helpers manage serialization and a 20-message cap. Chat state now restores from stored history, saves on each update, supports clearing storage and in-memory state, and shows a conditional header button to reset the conversation.

Changes

AlgoBot localStorage Chat Persistence

Layer / File(s) Summary
Persistence helpers and state init
app/src/components/custom/AlgoBot.tsx
Adds STORAGE_KEY, MAX_MESSAGES, WELCOME_MESSAGE, loadHistory, and saveHistory, then initializes messages from stored history when available.
Save effect and clear handler
app/src/components/custom/AlgoBot.tsx
Persists messages to localStorage on changes and adds handleClearChat to remove stored history and reset chat state.
Clear Chat UI button
app/src/components/custom/AlgoBot.tsx
Adds a conditional Trash2-icon "Clear Chat" button in the header that calls handleClearChat.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive Most requirements appear implemented, but the summary doesn't confirm guarded localStorage access or the expected storage scoping. Confirm localStorage is wrapped in try/catch and that the history key is scoped as required; the summary doesn't verify those details.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: persistent AlgoBot chat history with a clear button.
Out of Scope Changes check ✅ Passed The diff appears focused on AlgoBot persistence and chat clearing, with no unrelated changes shown.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/src/components/custom/AlgoBot.tsx`:
- Around line 30-34: The saveHistory() flow in AlgoBot is re-persisting an empty
array after “Clear Chat” because it always writes to localStorage even when
there are no conversation messages to save. Update saveHistory(messages) so it
skips setItem when the sliced toStore list is empty (and ideally removes the
STORAGE_KEY instead), keeping the clear action truly empty. Use the existing
saveHistory, STORAGE_KEY, and localStorage call site to make the fix without
affecting normal message persistence.
- Around line 18-23: The restored chat history in loadHistory() is currently
accepted as any non-empty array, which can let malformed items through and cause
renderContent(msg.content) or /api/chat usage to fail. Update loadHistory() in
AlgoBot.tsx to validate each item against the runtime ChatMessage shape before
returning it, drop invalid entries, and cap the recovered list with
slice(-MAX_MESSAGES) so stale oversized history is trimmed on load.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0644368f-4ecb-4cc8-ad77-c4e1c8aee800

📥 Commits

Reviewing files that changed from the base of the PR and between 8e41fd8 and 3d901b1.

📒 Files selected for processing (1)
  • app/src/components/custom/AlgoBot.tsx

Comment on lines +18 to +23
function loadHistory(): ChatMessage[] | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw);
if (Array.isArray(parsed) && parsed.length > 0) return parsed;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Validate and cap restored history before using it.

On Lines 22-23, any non-empty array from localStorage is accepted as ChatMessage[]. A stale/corrupt entry like { content: null } will make renderContent(msg.content) throw on first render, and malformed items also get forwarded to /api/chat. Filter by the runtime ChatMessage shape here and apply slice(-MAX_MESSAGES) on load too.

Suggested fix
 function loadHistory(): ChatMessage[] | null {
     try {
         const raw = localStorage.getItem(STORAGE_KEY);
         if (!raw) return null;
         const parsed = JSON.parse(raw);
-        if (Array.isArray(parsed) && parsed.length > 0) return parsed;
-        return null;
+        if (!Array.isArray(parsed)) return null;
+
+        const history = parsed
+            .filter(
+                (msg): msg is ChatMessage =>
+                    !!msg &&
+                    (msg.role === 'user' || msg.role === 'assistant') &&
+                    typeof msg.content === 'string'
+            )
+            .slice(-MAX_MESSAGES);
+
+        return history.length > 0 ? history : null;
     } catch {
         return null;
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function loadHistory(): ChatMessage[] | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw);
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
function loadHistory(): ChatMessage[] | null {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return null;
const parsed = JSON.parse(raw);
if (!Array.isArray(parsed)) return null;
const history = parsed
.filter(
(msg): msg is ChatMessage =>
!!msg &&
(msg.role === 'user' || msg.role === 'assistant') &&
typeof msg.content === 'string'
)
.slice(-MAX_MESSAGES);
return history.length > 0 ? history : null;
} catch {
return null;
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/custom/AlgoBot.tsx` around lines 18 - 23, The restored
chat history in loadHistory() is currently accepted as any non-empty array,
which can let malformed items through and cause renderContent(msg.content) or
/api/chat usage to fail. Update loadHistory() in AlgoBot.tsx to validate each
item against the runtime ChatMessage shape before returning it, drop invalid
entries, and cap the recovered list with slice(-MAX_MESSAGES) so stale oversized
history is trimmed on load.

Comment on lines +30 to +34
function saveHistory(messages: ChatMessage[]) {
try {
// Skip the welcome message (index 0) — only persist conversation
const toStore = messages.slice(1).slice(-MAX_MESSAGES);
localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Empty history gets written back right after “Clear Chat”.

Because saveHistory() always calls setItem, clearing the chat removes the key and then immediately recreates it as [] when the effect reruns. The UI resets correctly, but the persisted history is not actually cleared.

Suggested fix
 function saveHistory(messages: ChatMessage[]) {
     try {
         // Skip the welcome message (index 0) — only persist conversation
         const toStore = messages.slice(1).slice(-MAX_MESSAGES);
-        localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore));
+        if (toStore.length === 0) {
+            localStorage.removeItem(STORAGE_KEY);
+            return;
+        }
+        localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore));
     } catch {
         // Private browsing or quota exceeded — silently ignore
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function saveHistory(messages: ChatMessage[]) {
try {
// Skip the welcome message (index 0) — only persist conversation
const toStore = messages.slice(1).slice(-MAX_MESSAGES);
localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore));
function saveHistory(messages: ChatMessage[]) {
try {
// Skip the welcome message (index 0) — only persist conversation
const toStore = messages.slice(1).slice(-MAX_MESSAGES);
if (toStore.length === 0) {
localStorage.removeItem(STORAGE_KEY);
return;
}
localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore));
} catch {
// Private browsing or quota exceeded — silently ignore
}
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/components/custom/AlgoBot.tsx` around lines 30 - 34, The
saveHistory() flow in AlgoBot is re-persisting an empty array after “Clear Chat”
because it always writes to localStorage even when there are no conversation
messages to save. Update saveHistory(messages) so it skips setItem when the
sliced toStore list is empty (and ideally removes the STORAGE_KEY instead),
keeping the clear action truly empty. Use the existing saveHistory, STORAGE_KEY,
and localStorage call site to make the fix without affecting normal message
persistence.

@vercel

vercel Bot commented Jul 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
algo-forge-2-0 Ready Ready Preview, Comment Jul 4, 2026 9:12am

@arcgod-design

Copy link
Copy Markdown
Author

Hey @Rishabhworkspace, this PR has been ready for review for a while -- offering this friendly bump. The implementation matches the issue's specified behavior and CI is passing.

PR: #63
Title: feat: Persistent AlgoBot chat history with localStorage
Issue: #14

When you have a moment, a review would be much appreciated. I am happy to iterate on any feedback. If the timing is not right, no worries at all -- just a gentle nudge from a contributor who has been waiting patiently. �

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AlgoBot Has No Persistent Chat History Across Navigation

2 participants