Skip to content

TigerGraph as LLM memory stage-1#41

Open
Bharath-Tigergraph wants to merge 1 commit into
mainfrom
GML-2070-tg-memory-stage1
Open

TigerGraph as LLM memory stage-1#41
Bharath-Tigergraph wants to merge 1 commit into
mainfrom
GML-2070-tg-memory-stage1

Conversation

@Bharath-Tigergraph
Copy link
Copy Markdown
Contributor

@Bharath-Tigergraph Bharath-Tigergraph commented May 21, 2026

User description

User description

Stage 1: TigerGraph as LLM Chat Memory

Replaces the SQLite-based chat-history Docker service with native TigerGraph storage for all chat conversation data. Each user's conversations and messages are stored as graph vertices (conversation, message) with a has_message edge, enabling per-user isolation, ownership security, and history-aware LLM responses.

PR Type

Enhancement, Security

Description

Add TigerGraph memory schema (conversation, message vertices + has_message edge)
Add tg_memory.py module for all conversation/message CRUD and ownership verification
Auto-install memory schema and GSQL queries on graphrag startup
Remove chat-history SQLite container; update docker-compose.yml to use TigerGraph directly
Add REST endpoints for listing, creating, and deleting conversations and messages
Enforce per-user conversation ownership to isolate users working on the same graph
Fix agent routing to prioritize last 4 chat history messages before falling back to knowledge base
Create conversation on first user message (not on "New Chat" button click)
Add delete button per conversation in sidebar and per message turn in chat window
Immediate UI feedback on delete — no page refresh required

flowchart LR
UI["Chat UI"] -- "send query" --> API["ui.py chat/query endpoints"]
API -- "verify owner + load history" --> MEM["TigerGraph Memory"]
API -- "run agent" --> AGENT["Agent Routing and Execution"]
AGENT -- "history question" --> HIST["History Lookup"]
HIST -- "last 4 exchanges" --> API
API -- "write exchange" --> MEM
UI -- "delete message or conversation" --> API


PR Type

Enhancement, Bug fix


Description

  • Replace chat-history with TigerGraph memory

  • Add memory schema startup installation

  • Secure conversation ownership and deletion

  • Improve history routing and UI updates


Diagram Walkthrough

flowchart LR
  CFG["Config defaults"] -- "enable startup install" --> START["Startup schema installer"]
  START -- "installs schema and queries" --> TG["TigerGraph memory"]
  API["UI router endpoints"] -- "read write verify delete" --> TG
  AGENT["Agent routing"] -- "prefer conversation history" --> TG
  UI["Chat UI"] -- "delete conversation or message" --> API
Loading

File Walkthrough

Relevant files
Configuration changes
2 files
config.py
Add default startup memory schema flag                                     
+2/-0     
docker-compose.yml
Remove chat-history and add TigerGraph service                     
+14/-28 
Enhancement
14 files
base_llm.py
Strengthen prompt guidance for history routing                     
+9/-0     
tg_memory.py
Implement TigerGraph chat memory CRUD layer                           
+920/-0 
main.py
Install memory schema during app startup                                 
+28/-4   
ui.py
Migrate UI chat APIs to TigerGraph                                             
+191/-149
supportai.py
Initialize memory schema with SupportAI setup                       
+7/-0     
ActionProvider.tsx
Remove deleted messages from local chat state                       
+27/-0   
CustomChatMessage.tsx
Add per-message delete confirmation workflow                         
+82/-8   
Interact.tsx
Add delete action to message controls                                       
+13/-0   
SideMenu.tsx
Add conversation delete controls in sidebar                           
+65/-1   
GetLastNMemoryExchanges.gsql
Add query for recent memory exchanges                                       
+20/-0   
ListConversationsForUser.gsql
Add query to list user conversations                                         
+11/-0   
ListMessagesForConversation.gsql
Add query to load conversation messages                                   
+11/-0   
ListMessagesForMemory.gsql
Add query for memory message retrieval                                     
+15/-0   
Memory_Schema.gsql
Define conversation message memory graph schema                   
+31/-0   
Miscellaneous
1 files
__init__.py
Add memory package initializer                                                     
+4/-0     
Bug fix
1 files
agent_graph.py
Fast-path history questions before LLM routing                     
+35/-0   

Replace SQLite chat-history service with direct TigerGraph storage.

- Add TigerGraph memory schema: conversation and message vertices with has_message edge
- Add tg_memory.py module for all conversation/message CRUD operations
- Auto-install memory schema and GSQL queries on graphrag startup
- Add REST endpoints for conversation/message list, create, and delete
- Enforce conversation ownership security to isolate users on same graph
- Fix agent routing to prioritize last 4 chat history messages for history queries
- Add delete button per conversation in sidebar and per message in chat window
- Immediate UI feedback on delete without requiring page refresh
- Conversation created on first user message (not on New Chat click)

Co-authored-by: Cursor <cursoragent@cursor.com>
@tg-pr-agent
Copy link
Copy Markdown

tg-pr-agent Bot commented May 21, 2026

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
🧪 No relevant tests
🔒 Security concerns

Authorization bypass:
The new DELETE /ui/message/{message_id} path deletes messages by primary ID only and does not verify the authenticated user owns the parent conversation or message. If message IDs are exposed in the UI or logs, this could allow one user to delete another user's data across the same graph.

⚡ Recommended focus areas for review

Missing Ownership

Message deletion appears to delete any message vertex by ID without verifying that the message belongs to a conversation owned by the authenticated user. This should be validated carefully because a user who can guess or obtain another message ID may be able to delete someone else's chat history.

_, conn = ws_basic_auth(auth, graphname)
deleted = await asyncio.to_thread(
    tg_memory.delete_message_vertices,
    conn,
    graphname,
    [message_id],
)
if deleted == 0:
    raise HTTPException(status_code=404, detail="Message not found.")
Stale History

The WebSocket chat flow loads conversation history once before entering the receive loop, but does not refresh or append to that in-memory history after each exchange is written. Follow-up turns in the same session may therefore be routed and answered without seeing the most recent messages.

# Load conversation history if not a new conversation
conversation_history = (
    await load_conversation_history(conn, graphname, conversation_id)
    if not started_new_conversation
    else []
)
Startup Overhead

Several hot-path operations call schema/query initialization before each read or write. Since these functions are invoked on every chat request and message operation, this may introduce significant latency and extra GSQL load under normal traffic.

try:
    init_memory_schema(conn, graphname)

Comment on lines +835 to +849
def delete_message_vertices(
conn: TigerGraphConnection,
graphname: str,
message_ids: list[str],
) -> int:
"""Permanently delete message vertices by primary id. Returns count deleted."""
if not message_ids or not tg_memory_enabled(graphname):
return 0
init_memory_schema(conn, graphname)
ids = [str(m) for m in message_ids if m]
if not ids:
return 0
try:
conn.delVerticesById("message", ids, permanent=True)
return len(ids)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggestion: Returning len(ids) assumes every requested vertex existed and was deleted, which can turn missing IDs into false successful deletions. Query the existing vertices first and return the actual deleted count so callers can correctly emit 404 for nonexistent messages. [possible issue, importance: 7]

Suggested change
def delete_message_vertices(
conn: TigerGraphConnection,
graphname: str,
message_ids: list[str],
) -> int:
"""Permanently delete message vertices by primary id. Returns count deleted."""
if not message_ids or not tg_memory_enabled(graphname):
return 0
init_memory_schema(conn, graphname)
ids = [str(m) for m in message_ids if m]
if not ids:
return 0
try:
conn.delVerticesById("message", ids, permanent=True)
return len(ids)
def delete_message_vertices(
conn: TigerGraphConnection,
graphname: str,
message_ids: list[str],
) -> int:
"""Permanently delete message vertices by primary id. Returns count deleted."""
if not message_ids or not tg_memory_enabled(graphname):
return 0
init_memory_schema(conn, graphname)
ids = [str(m) for m in message_ids if m]
if not ids:
return 0
try:
existing = conn.getVerticesById("message", ids)
existing_ids = [str(v.get("v_id") or v.get("message_id") or v.get("primary_id")) for v in (existing or [])]
existing_ids = [mid for mid in existing_ids if mid]
if not existing_ids:
return 0
conn.delVerticesById("message", existing_ids, permanent=True)
return len(existing_ids)

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.

1 participant