Spaces:
Sleeping
Sleeping
IDAgents Developer
Implement per-user session isolation system - Each authenticated user now has isolated workspace with separate chat histories and agent data
d952de8
| # 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:** | |
| ```python | |
| def simple_chat_response(user_message, history): | |
| # Uses history parameter | |
| ... | |
| ``` | |
| **After:** | |
| ```python | |
| 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:** | |
| ```python | |
| simple_input.submit( | |
| simple_chat_response, | |
| inputs=[simple_input, simple_chat_history], | |
| outputs=[simple_chatbot, simple_input] | |
| ) | |
| ``` | |
| **After:** | |
| ```python | |
| 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: | |
| ```python | |
| 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 | |
| ```python | |
| # 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 | |