Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Toggle history #369

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open

Toggle history #369

wants to merge 5 commits into from

Conversation

casistack
Copy link
Contributor

Detailed Changes

  1. Chat History Toggle Feature:

    • Implemented user-controlled chat history toggle
    • Added settings UI for enabling/disabling chat history
    • Real-time UI updates for history panel
    • Proper state management for history visibility
  2. Component Updates:

    • Enhanced HistoryList component to use client-side state management for immediate UI updates
    • Updated ClearHistory component to properly refresh the history list after clearing
    • Modified History component to handle state transitions and loading states
    • Added proper handling for history refresh operations
  3. Redis Integration:

    • Modified the Redis implemetation to support credentials
    • Implemented error handling for Redis operations
    • Added fallback behavior when Redis operations fail
  4. Storage Implementation:

    • Added flexible storage provider system
    • Implemented Redis storage adapter for server-side storage
    • Added browser-based storage (localStorage) for development/fallback
    • Created storage abstraction layer for future extensibility
  5. Environment Variables Added:

    • STORAGE_PROVIDER: Choose between 'redis' or 'local' storage
    • Enhanced Redis configuration options
    • Added fallback behavior configuration

Testing Instructions

  1. Chat History Toggle:

    • Enable/disable chat history in settings
    • Verify chat persistence matches setting
    • Test real-time updates in history panel
    • Verify clear history functionality
  2. Storage Testing:

    • Test with Redis: env STORAGE_PROVIDER=redis USE_LOCAL_REDIS=false UPSTASH_REDIS_REST_URL=[URL] UPSTASH_REDIS_REST_TOKEN=[TOKEN]
    • Test with LocalStorage: env STORAGE_PROVIDER=local
    • Test fallback behavior with invalid Redis config

Potential Impacts

  • Improved user privacy control with history toggle
  • Enhanced development experience with LocalStorage option
  • No breaking changes to existing functionality
  • Seamless fallback behavior for reliability

Additional Notes

  • Storage abstraction allows for future storage providers
  • Browser-based storage (localStorage) makes development and testing easier
  • Data in browser storage is device-specific and persists until cleared
  • All changes maintain backward compatibility
  • Added proper error handling and state management
  • UI updates happen in real-time without page refreshes

Checklist Additions

  • Implemented chat history toggle feature
  • Added storage provider abstraction
  • Implemented LocalStorage provider
  • Added proper error handling
  • Updated documentation
  • Tested all storage scenarios
  • Verified backward compatibility
  • Added some TypeScript types for changes
  • Implemented real-time UI updates

Closes #[347] Add No-History Options

Copy link

vercel bot commented Oct 23, 2024

@casistack is attempting to deploy a commit to the morphic Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

vercel bot commented Oct 24, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
morphic ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 25, 2024 10:03pm

@miurla
Copy link
Owner

miurla commented Oct 24, 2024

@casistack This is another great update! Thank you! 🥇

Please fix the compilation error that is occurring.

[09:38:56.714] Running "bun run build"
[09:38:56.719] $ next build
[09:38:57.382]   ▲ Next.js 14.2.5
[09:38:57.382] 
[09:38:57.457]    Creating an optimized production build ...
[09:39:26.506]  ✓ Compiled successfully
[09:39:26.507]    Linting and checking validity of types ...
[09:39:34.144] Failed to compile.
[09:39:34.144] 
[09:39:34.144] ./components/history-container.tsx:17:10
[09:39:34.144] Type error: Property 'chatHistoryEnabled' is missing in type '{ userId: string; }' but required in type 'HistoryListProps'.

components/history-list.tsx Outdated Show resolved Hide resolved
components/header.tsx Outdated Show resolved Hide resolved
Copy link
Owner

@miurla miurla left a comment

Choose a reason for hiding this comment

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

Test with LocalStorage: env STORAGE_PROVIDER=local

LocalStorage wasn't working. To make LocalStorageProvider work, unlike Redis, we need to add logic to save on the client side. ref: #369 (comment)

Since we don't need to go that far, how about making STORAGE_PROVIDER options either redis or none? When set to none, nothing will be saved to storage. This would satisfy the requirements of #347.

app/actions.tsx Outdated Show resolved Hide resolved
app/actions.tsx Outdated
@@ -147,8 +157,16 @@ export const AI = createAI<AIState, UIState>({
onSetAIState: async ({ state, done }) => {
'use server'

const redis = await getRedisClient()
const chatHistoryEnabled = await redis.get(
Copy link
Owner

Choose a reason for hiding this comment

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

I tested with Upstash, and even when disabled, it was always saved. The reason was that chatHistoryEnabled was returning a boolean value. Please check this.

console.log({
  value: chatHistoryEnabled,
  type: typeof chatHistoryEnabled,
  comparison: chatHistoryEnabled === 'false',
  strictEquality: Object.is(chatHistoryEnabled, 'false')
})
{
  value: false,
  type: 'boolean',
  comparison: false,
  strictEquality: false
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm thats odd i tested with local redis and was working and upstash . ok will have a look

Copy link
Owner

Choose a reason for hiding this comment

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

I performed additional testing: #369 (comment)

lib/storage/local-storage.ts Show resolved Hide resolved
Copy link
Owner

@miurla miurla left a comment

Choose a reason for hiding this comment

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

Thank you for fixing the STORAGE_PROVIDER 👍 I've made several comments.

@@ -6,6 +6,9 @@ import HistoryContainer from './history-container'
import TopRightMenu from './ui/top-right-menu'

export const Header: React.FC = async () => {
// Get storage provider setting from environment
const storageProvider = process.env.STORAGE_PROVIDER || 'redis'
Copy link
Owner

Choose a reason for hiding this comment

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

The header will only be controlled on mobile. If you return null in the history-container, you can control everything at once.

https://github.com/miurla/morphic/blob/main/components/history-container.tsx

  const storageProvider = process.env.STORAGE_PROVIDER
  const enabled = storageProvider !== 'none'

  if (!enabled) {
    return null
  }

try {
if (this.client instanceof Redis) {
const value = await this.client.get(key)
return value ? String(value) : null
Copy link
Owner

Choose a reason for hiding this comment

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

I performed verification. In the case of Upstash, the value of user:${userId}:chatHistoryEnabled was being returned as a boolean, even though it was stored as a string.
Therefore, when the value was false, it was returning either 'true' or null. So, modifying it as follows achieved the expected result.

return value === null ? null : String(value)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ah yes . makes sense should have spotted that

const chatHistoryEnabled = await redis.get(
'user:anonymous:chatHistoryEnabled'
)
const chatHistoryEnabled = await redis.get('user:anonymous:chatHistoryEnabled')
Copy link
Owner

Choose a reason for hiding this comment

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

IMO: Since chatHistoryEnabled is also being checked in saveChat, checking it in either place should be sufficient.

2804b5e#diff-819d2d9016d052cd621d2190deaf60688a87f953233d709b40fdabcf99d83f47R175-R180

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yea just put it as additional safety net but see what you mean

@@ -17,7 +17,9 @@ export async function getChats(userId?: string | null) {

try {
const redis = await getRedis()
const chatHistoryEnabled = await redis.get(`user:${userId}:chatHistoryEnabled`)
const chatHistoryEnabled = await redis.get(
Copy link
Owner

Choose a reason for hiding this comment

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

You can use getChatHistorySetting

const chatHistoryEnabled = await getChatHistorySetting(userId)

2804b5e#diff-819d2d9016d052cd621d2190deaf60688a87f953233d709b40fdabcf99d83f47R217

@@ -149,7 +148,7 @@ export function ChatPanel({ messages, query }: ChatPanelProps) {
placeholder="Ask a question..."
spellCheck={false}
value={input}
className="resize-none w-full min-h-12 rounded-fill bg-muted border border-input pl-4 pr-10 pt-3 pb-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50'"
className="resize-none w-full min-h-12 rounded-fill bg-muted border border-input pl-4 pr-10 pt-3 pb-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50'"
Copy link
Owner

Choose a reason for hiding this comment

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

The ring color has changed. I don't want to change the ring color.

image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok so no cosmetic changes . cool


const preferredStorage = process.env.STORAGE_PROVIDER?.toLowerCase() || 'redis'

if (preferredStorage === 'local') {
Copy link
Owner

Choose a reason for hiding this comment

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

I overlooked it. Let's remove the local storage-related code.

  • lib/storage/local-storage.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants