Conversation
- 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.
There was a problem hiding this comment.
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_historyin use case / test case / combined generation. - Fix similarity threshold defaulting when
threshold=0.0and 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.
| history_section = "" | ||
| if chat_history: | ||
| history_section = CHAT_HISTORY_TEMPLATE.format(chat_history=chat_history) + "\n\n" | ||
|
|
There was a problem hiding this comment.
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.
| 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: |
There was a problem hiding this comment.
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.
| def _get_session_file(self, session_id: str) -> Path: | ||
| return settings.session_path / f"{session_id}.json" |
There was a problem hiding this comment.
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.
| 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) |
There was a problem hiding this comment.
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.
| 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) |
There was a problem hiding this comment.
_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.
| session_file = self._get_session_file(session_id) | ||
| if session_file.exists(): | ||
| session_file.unlink() |
There was a problem hiding this comment.
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.
| from typing import Dict, List, Optional | ||
| import time | ||
| from collections import deque |
There was a problem hiding this comment.
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).
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).