IDAgentsFreshTest / SESSION_ISOLATION_GUIDE.md
IDAgents Developer
Implement per-user session isolation system - Each authenticated user now has isolated workspace with separate chat histories and agent data
d952de8
|
raw
history blame
5.46 kB

Per-User Session Isolation Implementation Guide

Overview

This guide explains how to implement per-user session isolation in the ID Agents app so that each authenticated user has their own isolated workspace (chat histories, agents, patient data, etc.).

Problem

Currently, all users share the same gr.State() objects, meaning:

  • User A sees User B's chat messages
  • User A's agents appear in User B's dropdown
  • Everyone works in the same shared container

Solution

Use Gradio's gr.Request object to identify users and store their data separately in a UserSessionManager.

Files Created

  1. user_session_manager.py - Core session storage with thread-safe operations
  2. session_helpers.py - Helper functions for getting/setting user data

Implementation Steps

Step 1: Update Function Signatures

All functions that currently accept gr.State parameters need to accept request: gr.Request instead:

Before:

def simple_chat_response(user_message, history):
    # Uses history parameter
    ...

After:

def simple_chat_response(user_message, request: gr.Request):
    # Gets history from session manager
    history = get_user_simple_chat_history(request)
    ...
    # Saves history back to session manager
    set_user_simple_chat_history(request, updated_history)

Step 2: Update Gradio Event Bindings

When binding functions to Gradio components, remove gr.State from inputs/outputs and add request:

Before:

simple_input.submit(
    simple_chat_response,
    inputs=[simple_input, simple_chat_history],
    outputs=[simple_chatbot, simple_input]
)

After:

simple_input.submit(
    simple_chat_response,
    inputs=[simple_input],  # request is added automatically by Gradio
    outputs=[simple_chatbot, simple_input]
)

Step 3: Remove gr.State() Declarations

In build_ui(), remove these lines:

simple_chat_history = gr.State([])
builder_chat_histories = gr.State({})
deployed_chat_histories = gr.State({})

These are now managed by the session manager per-user.

Functions That Need Updates

Critical Functions (High Priority)

  1. simple_chat_response - Already updated
  2. chatpanel_handle - Already updated
  3. load_history - Needs update
  4. reset_chat - May need update if it affects per-user state
  5. save_deployed_agent - If it stores to chat histories
  6. populate_from_preset - If it affects builder state

UI Event Bindings That Need Updates

All .click(), .submit(), .change() handlers that currently use:

  • simple_chat_history
  • builder_chat_histories
  • deployed_chat_histories
  • Any other gr.State() objects

Testing Checklist

After implementation, test with 2 different user accounts simultaneously:

  • User1 and User2 have separate simple chat histories
  • User1's agents don't appear in User2's dropdown
  • User1 and User2 can build different agents without interference
  • Patient data is separate between users
  • Reset/clear functions only affect the current user
  • Logout/re-login maintains session (or clears if desired)

Key Benefits

  1. True Multi-Tenancy: Each user gets isolated workspace
  2. No Data Leakage: User A cannot see User B's data
  3. Thread-Safe: Concurrent users don't interfere with each other
  4. Scalable: Can handle multiple simultaneous users
  5. Auditable: Can log per-user actions for debugging

Important Notes

  • gr.Request only works when authentication is enabled
  • Username comes from request.username (set by Gradio's auth system)
  • Session data is stored in memory (lost on restart - could be persisted to database if needed)
  • The session manager is thread-safe for concurrent access

Migration Strategy

Phase 1: Core Chat Functions (DONE)

  • ✅ simple_chat_response
  • ✅ chatpanel_handle

Phase 2: Agent Management

  • load_history
  • save_deployed_agent
  • remove_selected_agent

Phase 3: UI Bindings

  • Update all .click() and .submit() bindings
  • Remove gr.State declarations

Phase 4: Testing & Verification

  • Multi-user testing
  • Session isolation verification
  • Performance testing

Quick Reference

# Import at top of app.py (DONE)
from user_session_manager import session_manager, get_username_from_request, SessionKeys
from session_helpers import (
    get_user_simple_chat_history, set_user_simple_chat_history,
    get_user_builder_chat_histories, set_user_builder_chat_histories,
    get_user_deployed_chat_histories, set_user_deployed_chat_histories,
    get_current_username, log_user_access
)

# In any function:
def my_function(user_input, request: gr.Request):
    username = get_current_username(request)
    log_user_access(request, "my_function")
    
    # Get user-specific data
    data = session_manager.get_user_data(username, "my_key", default=[])
    
    # Process...
    
    # Save user-specific data
    session_manager.set_user_data(username, "my_key", new_data)

Next Steps

To complete the implementation:

  1. Search for all gr.State( declarations and remove them
  2. Search for all functions that have histories or history parameters
  3. Update each function to use session helpers
  4. Update all Gradio event bindings
  5. Test with multiple users
  6. Deploy and verify

For assistance, see:

  • user_session_manager.py - Core session storage
  • session_helpers.py - Helper functions and examples