Skip to content

feat: Add persistent session memory & fix retrieval algorithms - #2

Open
isatyamks wants to merge 4 commits into
masterfrom
session
Open

feat: Add persistent session memory & fix retrieval algorithms#2
isatyamks wants to merge 4 commits into
masterfrom
session

Conversation

@isatyamks

Copy link
Copy Markdown
Owner

Persistent Session Context (LLM Memory):

Refactored src/utils/session_manager.py to persist session histories as JSON files (data/sessions/<session_id>.json) rather than volatile in-memory storage. Survives server restarts.
Updated src/config/prompts.py to natively include a <chat_history> template, allowing the LLM to understand multi-turn conversation (e.g., "generate 2 more").
Plumbed chat_history downward through all generator pipelines (Generator, UseCaseGenerator, TestCaseGenerator).

- Ensure the upload directory exists before saving files in `upload_files`.
- Add a new `requests.json` file for API documentation with endpoints for server root, health check, session management, document upload, query generation, statistics, and database index reset.
- Introduce a chat history template in prompts to improve context handling in query generation.
- Update settings to include a session directory and ensure it is created on initialization.
- Modify the generator classes to accept and utilize chat history for generating use cases and test cases.
- Enhance the vector store metadata description for clarity.
- Implement session management with JSON file storage for chat history, allowing for session persistence and retrieval.
@isatyamks
isatyamks requested a review from Copilot March 29, 2026 18:27
@isatyamks isatyamks self-assigned this Mar 29, 2026
@isatyamks isatyamks added the enhancement New feature or request label Mar 29, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces persistent, file-backed session history to survive restarts and threads chat history through the generation pipeline so multi-turn requests (e.g., “generate 2 more”) can be understood, while also fixing a retrieval threshold defaulting bug in vector similarity search.

Changes:

  • Persist session histories to disk (data/sessions/<session_id>.json) and surface formatted history to prompt construction.
  • Extend generation APIs/prompts to accept and include chat_history in use case / test case / combined generation.
  • Fix similarity threshold defaulting when threshold=0.0 and configure Chroma collection metadata for cosine space.

Reviewed changes

Copilot reviewed 34 out of 41 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/utils/session_manager.py Adds JSON-backed persistence for session histories and load/save hooks.
src/retrieval/vector_store.py Updates Chroma collection metadata and fixes threshold defaulting logic.
src/generation/use_case_generator.py Passes chat_history into prompt creation for use-case generation.
src/generation/test_case_generator.py Passes chat_history into prompt creation for test-case generation.
src/generation/generator.py Pulls session history and plumbs it through generator pipelines.
src/config/settings.py Introduces SESSION_DIR + session_path and ensures directory creation.
src/config/prompts.py Adds <chat_history> template and injects it into generation prompts.
main.py Renames API strings to “Multimodal” and ensures upload directory exists before writes.
requests.json Adds a Postman collection for exercising API endpoints.
README.md Updates systemd unit description text to “Multimodal RAG API”.
logs/devasssure.log Adds a large runtime log artifact (should not be versioned).
data/processed/metadata/Screenshot2025-12-2210.53.32AM_20251224_153015_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.53.21AM_20251224_153015_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.53.09AM_20251224_153014_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.52.24AM_20251224_153012_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.52.13AM_20251224_153012_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.51.44AM_20251224_153010_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.51.26AM_20251224_153009_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Screenshot2025-12-2210.51.10AM_20251224_153008_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Booking.comHotelSearch_20251224_153006_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Booking.comFlightSearch_20251224_153006_metadata.json Removes generated processed metadata artifact.
data/processed/metadata/Booking.comFiltersFlight_20251224_153016_metadata.json Removes generated processed metadata artifact.
data/processed/chunks/Screenshot2025-12-2210.53.32AM_20251224_153015_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.53.21AM_20251224_153015_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.53.09AM_20251224_153014_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.52.24AM_20251224_153012_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.52.13AM_20251224_153012_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.51.44AM_20251224_153010_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.51.26AM_20251224_153009_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Screenshot2025-12-2210.51.10AM_20251224_153008_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Booking.comHotelSearch_20251224_153006_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Booking.comFlightSearch_20251224_153006_chunks.json Removes generated processed chunks artifact.
data/processed/chunks/Booking.comFiltersFlight_20251224_153016_chunks.json Removes generated processed chunks artifact.
data/vector_store/.gitkeep Keeps empty vector store directory tracked.
data/uploads/.gitkeep Keeps empty uploads directory tracked.
data/processed/.gitkeep Keeps empty processed directory tracked.
data/Booking-com/Booking.com Hotel Search.docx Adds sample document fixture.
data/Booking-com/Booking.com Flight Search.docx Adds sample document fixture.
data/Booking-com/Booking.com Filters Flight.docx Adds sample document fixture.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/config/prompts.py
Comment on lines +203 to +206
history_section = ""
if chat_history:
history_section = CHAT_HISTORY_TEMPLATE.format(chat_history=chat_history) + "\n\n"

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

Raw chat_history is injected into the generation prompt. Since chat history contains prior user inputs, this materially increases prompt-injection risk (the existing injection guard only checks the current query). Consider sanitizing/quoting chat history, adding explicit instructions to treat it as untrusted data, and/or running the prompt-injection guard over chat_history before including it.

Copilot uses AI. Check for mistakes.
Comment thread main.py
Comment on lines 101 to 106
file_path = settings.upload_path / file.filename

# Ensure upload directory exists
settings.upload_path.mkdir(parents=True, exist_ok=True)

with open(file_path, "wb") as buffer:

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

file.filename is used directly when constructing file_path. A crafted filename containing path separators (e.g., ../) can escape settings.upload_path and overwrite arbitrary files. Sanitize filenames (e.g., take basename, reject path separators, allowlist chars) and/or generate server-side filenames before writing to disk.

Copilot uses AI. Check for mistakes.
Comment on lines +19 to +20
def _get_session_file(self, session_id: str) -> Path:
return settings.session_path / f"{session_id}.json"

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

session_id is used directly to build a filename. Because session_id is user-supplied (via the API), this allows path traversal (e.g., ../../...) and writing/reading outside settings.session_path. Validate/normalize session IDs (e.g., strict UUID / safe charset) and ensure the resolved path stays within settings.session_path before accessing the file.

Copilot uses AI. Check for mistakes.
Comment on lines +35 to +40
def _save_session(self, session_id: str) -> None:
if session_id in self.sessions:
session_file = self._get_session_file(session_id)
try:
with open(session_file, "w", encoding="utf-8") as f:
json.dump(list(self.sessions[session_id]), f, indent=2)

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

Session persistence writes JSON directly to the final file path. Concurrent requests for the same session_id (or a crash mid-write) can corrupt the JSON and break future loads. Consider adding a per-session lock and using an atomic write pattern (write to a temp file then replace) to guarantee file integrity.

Copilot uses AI. Check for mistakes.
Comment on lines +22 to +31
def _load_session(self, session_id: str) -> None:
if session_id not in self.sessions:
session_file = self._get_session_file(session_id)
if session_file.exists():
try:
with open(session_file, "r", encoding="utf-8") as f:
data = json.load(f)
self.sessions[session_id] = deque(data, maxlen=self.max_history)
except Exception:
self.sessions[session_id] = deque(maxlen=self.max_history)

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

_load_session swallows all exceptions without logging and assumes the on-disk JSON is valid for deque(data, ...). If the file is malformed or not a list of {role, content} dicts, debugging will be hard and runtime behavior may be inconsistent. Log the exception (at least debug/warn) and validate the loaded structure before accepting it.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +65
session_file = self._get_session_file(session_id)
if session_file.exists():
session_file.unlink()

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

session_file.unlink() can raise (permissions, file in use, race with another request). This can cause session clears to error even though the in-memory session was removed. Wrap the unlink in a try/except and log at debug/warn level (or ignore FileNotFoundError) to make clear_session resilient.

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 3
from typing import Dict, List, Optional
import time
from collections import deque

Copilot AI Mar 29, 2026

Copy link

Choose a reason for hiding this comment

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

Optional and time appear to be unused in this module after the refactor. Removing unused imports keeps linting clean and avoids confusion about intended behavior (e.g., expiry logic).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants