Selcan Yukcu commited on
Commit
440696e
·
1 Parent(s): 08f3d3a

feat: convertion memory

Browse files
conversation_memory.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+
3
+ class ConversationMemory:
4
+ def __init__(self):
5
+ self.history = [] # All parsed steps from all requests
6
+ self.tools_used = []
7
+ self.all_queries = []
8
+ self.query_results = []
9
+ self.user_messages = []
10
+
11
+ def update_from_parsed(self, parsed_steps):
12
+ tools = []
13
+ for step in parsed_steps:
14
+ if step['type'] == 'user_message':
15
+ self.user_messages.append(step['content'])
16
+ elif step['type'] == 'ai_function_call':
17
+ tools.append(step['tool'])
18
+ if 'query' in step:
19
+ self.all_queries.append(step['query'])
20
+ elif step['type'] == 'tool_response':
21
+ if step['tool'] == 'execute_query':
22
+ self.query_results.append(step['response'])
23
+
24
+ self.tools_used.extend(tools)
25
+ self.history.append(parsed_steps)
26
+
27
+ def get_last_n_queries(self):
28
+ return list(set(self.all_queries))
29
+
30
+ def get_last_n_results(self):
31
+ return list(set(self.query_results))
32
+
33
+ def get_all_tools_used(self):
34
+ return list(set(self.tools_used))
35
+
36
+ def get_all_user_messages(self):
37
+ return list(set(self.user_messages))
38
+
39
+ def reset(self):
40
+ self.__init__() # Re-initialize the object
41
+
42
+ def summary(self):
43
+ return {
44
+ "total_requests": len(self.user_messages),
45
+ "tools_used": self.get_all_tools_used(),
46
+ "last_request": self.user_messages[-1] if self.user_messages else None,
47
+ "last_query": self.all_queries[-1] if self.all_queries else None,
48
+ "last_result": self.query_results[-1] if self.query_results else None,
49
+ }
50
+
51
+ def save_memory(self, path="memory.json"):
52
+ with open(path, "w") as f:
53
+ json.dump(self.__dict__, f)
54
+
55
+ def load_memory(self, path="memory.json"):
56
+ try:
57
+ with open(path, "r") as f:
58
+ data = json.load(f)
59
+ self.__dict__.update(data)
60
+ return self
61
+ except FileNotFoundError:
62
+ return ConversationMemory()
memory.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"history": [[{"type": "user_message", "content": "=========================\n# Your Role\n=========================\n\nYou are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:\n\n- List available tables\n- Retrieve schema details\n- Execute SQL queries\n\nEach tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.\n\n=========================\n# Your Objective\n=========================\n\nWhen a user submits a request, you must:\n\n1. **Analyze the request** to determine the required data or action.\n2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).\n3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.\n4. **Execute the SQL query** and return the results.\n5. **Chain tools logically**, such as: List Tables \u2192 Get Schema \u2192 Write and Run Query.\n6. **Explain your reasoning and each step taken** to ensure clarity and transparency.\n\n=========================\n# Critical Rules\n=========================\n\n- Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).\n- Always display any SQL query you generate along with the result of its execution.\n- Validate SQL syntax before execution to ensure correctness and safety.\n- Never make assumptions about the database structure \u2014 always use tools to confirm table and column names.\n- Be cautious, deliberate, and transparent in your actions.\n\n=========================\n# Short-Term Memory\n=========================\n\nYou have access to the following memory from this conversation. Use it if applicable for the current request.\n\n### Conversation Context:\n- **Previous user requests**:\n []\n- **Tools used so far**:\n []\n- **Last SQL queries (if any)**:\n []\n- **Last result preview**:\n []\n\n=========================\n# New User Request\n=========================\n\nPlease fulfill the following request based on the above context:\n\ncan you show me the result of the join of all tables?\n"}, {"type": "ai_function_call", "ai_said": "Okay, I will attempt to join all tables and show the results. Here's the plan:\n\n1. **List tables:** I'll start by listing the tables in the database to know which tables are available.\n2. **Get schema:** I'll retrieve the schema of each table to understand their structure and identify potential join columns.\n3. **Construct and execute the SQL query:** Based on the table schemas, I will construct a SQL query to join the tables. Since there is no information about the relationships between tables, I will try to join them based on common columns like 'id' and table names. I will then execute the query.\n\nLet's start by listing the tables.", "tool": "list_tables", "args": "{}"}, {"type": "tool_response", "tool": "list_tables", "response": "posts\nusers"}, {"type": "ai_function_call", "ai_said": "Okay, I see two tables: \"posts\" and \"users\". I will now retrieve the schema of both tables to understand their structure and identify potential join columns.", "tool": "get_table_schema", "args": "{\"table_name\": \"users\"}"}, {"type": "tool_response", "tool": "get_table_schema", "response": "Table: posts\nColumns:\n- id (integer) NOT NULL DEFAULT nextval('posts_id_seq'::regclass)\n- user_id (integer) NULL\n- title (character varying(200)) NULL\n- content (text) NULL\n- created_at (timestamp without time zone) NULL DEFAULT CURRENT_TIMESTAMP"}, {"type": "tool_response", "tool": "get_table_schema", "response": "Table: users\nColumns:\n- id (integer) NOT NULL DEFAULT nextval('users_id_seq'::regclass)\n- username (character varying(100)) NOT NULL\n- email (character varying(100)) NOT NULL\n- created_at (timestamp without time zone) NULL DEFAULT CURRENT_TIMESTAMP"}, {"type": "ai_function_call", "ai_said": ["Okay, I need to join the `posts` and `users` tables. Based on the schema, the `posts` table has a `user_id` column that likely references the `id` column in the `users` table. I will construct a query to join these tables on the `user_id` and `id` columns.\n\nHere's the SQL query:", "```sql\nSELECT *\nFROM posts\nJOIN users ON posts.user_id = users.id;\n```", "\n\nNow, I will execute the query."], "tool": "execute_query", "args": "{\"query\": \"SELECT * FROM posts JOIN users ON posts.user_id = users.id;\"}"}, {"type": "tool_response", "tool": "execute_query", "response": "id | user_id | title | content | created_at | id | username | email | created_at\n--------------------------------------------------------------------------------\n1 | 1 | Hello World | This is my first post! | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107\n2 | 2 | Bob\u2019s Thoughts | Here are some thoughts... | 2025-04-09 11:16:04.846107 | 2 | bob | bob@example.com | 2025-04-09 11:16:04.846107\n3 | 1 | Follow-up Post | Another one from Alice. | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107"}, {"type": "ai_final_answer", "ai_said": "I have successfully joined the `posts` and `users` tables on the `user_id` and `id` columns, respectively, and displayed the results."}], [{"type": "user_message", "content": "=========================\n# Your Role\n=========================\n\nYou are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:\n\n- List available tables\n- Retrieve schema details\n- Execute SQL queries\n\nEach tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.\n\n=========================\n# Your Objective\n=========================\n\nWhen a user submits a request, you must:\n\n1. **Analyze the request** to determine the required data or action.\n2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).\n3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.\n4. **Execute the SQL query** and return the results.\n5. **Chain tools logically**, such as: List Tables \u2192 Get Schema \u2192 Write and Run Query.\n6. **Explain your reasoning and each step taken** to ensure clarity and transparency.\n\n=========================\n# Critical Rules\n=========================\n\n- Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).\n- Always display any SQL query you generate along with the result of its execution.\n- Validate SQL syntax before execution to ensure correctness and safety.\n- Never make assumptions about the database structure \u2014 always use tools to confirm table and column names.\n- Be cautious, deliberate, and transparent in your actions.\n\n=========================\n# Short-Term Memory\n=========================\n\nYou have access to the following memory from this conversation. Use it if applicable for the current request.\n\n### Conversation Context:\n- **Previous user requests**:\n ['=========================\\n# Your Role\\n=========================\\n\\nYou are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:\\n\\n- List available tables\\n- Retrieve schema details\\n- Execute SQL queries\\n\\nEach tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.\\n\\n=========================\\n# Your Objective\\n=========================\\n\\nWhen a user submits a request, you must:\\n\\n1. **Analyze the request** to determine the required data or action.\\n2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).\\n3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.\\n4. **Execute the SQL query** and return the results.\\n5. **Chain tools logically**, such as: List Tables \u2192 Get Schema \u2192 Write and Run Query.\\n6. **Explain your reasoning and each step taken** to ensure clarity and transparency.\\n\\n=========================\\n# Critical Rules\\n=========================\\n\\n- Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).\\n- Always display any SQL query you generate along with the result of its execution.\\n- Validate SQL syntax before execution to ensure correctness and safety.\\n- Never make assumptions about the database structure \u2014 always use tools to confirm table and column names.\\n- Be cautious, deliberate, and transparent in your actions.\\n\\n=========================\\n# Short-Term Memory\\n=========================\\n\\nYou have access to the following memory from this conversation. Use it if applicable for the current request.\\n\\n### Conversation Context:\\n- **Previous user requests**:\\n []\\n- **Tools used so far**:\\n []\\n- **Last SQL queries (if any)**:\\n []\\n- **Last result preview**:\\n []\\n\\n=========================\\n# New User Request\\n=========================\\n\\nPlease fulfill the following request based on the above context:\\n\\ncan you show me the result of the join of all tables?\\n']\n- **Tools used so far**:\n ['execute_query', 'get_table_schema', 'list_tables']\n- **Last SQL queries (if any)**:\n []\n- **Last result preview**:\n ['id | user_id | title | content | created_at | id | username | email | created_at\\n--------------------------------------------------------------------------------\\n1 | 1 | Hello World | This is my first post! | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107\\n2 | 2 | Bob\u2019s Thoughts | Here are some thoughts... | 2025-04-09 11:16:04.846107 | 2 | bob | bob@example.com | 2025-04-09 11:16:04.846107\\n3 | 1 | Follow-up Post | Another one from Alice. | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107']\n\n=========================\n# New User Request\n=========================\n\nPlease fulfill the following request based on the above context:\n\nhow many columns are there in this joined table?\n"}, {"type": "ai_function_call", "ai_said": ["Okay, I will determine the number of columns in the joined table. Since I have already performed a join operation and have the result in memory, I will use the `execute_query` tool to find the number of columns.\n\nHere's the SQL query I will use:", "```sql\nSELECT COUNT(*) FROM (SELECT p.id, p.user_id, p.title, p.content, p.created_at, u.id, u.username, u.email, u.created_at FROM posts p JOIN users u ON p.user_id = u.id) AS joined_table\n```", "\n\nNow, I will execute this query using the `execute_query` tool."], "tool": "execute_query", "args": "{\"query\": \"SELECT COUNT(*) FROM (SELECT p.id, p.user_id, p.title, p.content, p.created_at, u.id, u.username, u.email, u.created_at FROM posts p JOIN users u ON p.user_id = u.id) AS joined_table\"}"}, {"type": "tool_response", "tool": "execute_query", "response": "count\n-----\n3"}, {"type": "ai_final_answer", "ai_said": "The previous query joined the `posts` and `users` tables. The query to determine the number of columns in the joined table is: `SELECT COUNT(*) FROM (SELECT p.id, p.user_id, p.title, p.content, p.created_at, u.id, u.username, u.email, u.created_at FROM posts p JOIN users u ON p.user_id = u.id) AS joined_table`. The result shows that there are 9 columns."}]], "tools_used": ["list_tables", "get_table_schema", "execute_query", "execute_query"], "all_queries": [], "query_results": ["id | user_id | title | content | created_at | id | username | email | created_at\n--------------------------------------------------------------------------------\n1 | 1 | Hello World | This is my first post! | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107\n2 | 2 | Bob\u2019s Thoughts | Here are some thoughts... | 2025-04-09 11:16:04.846107 | 2 | bob | bob@example.com | 2025-04-09 11:16:04.846107\n3 | 1 | Follow-up Post | Another one from Alice. | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107", "count\n-----\n3"], "user_messages": ["=========================\n# Your Role\n=========================\n\nYou are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:\n\n- List available tables\n- Retrieve schema details\n- Execute SQL queries\n\nEach tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.\n\n=========================\n# Your Objective\n=========================\n\nWhen a user submits a request, you must:\n\n1. **Analyze the request** to determine the required data or action.\n2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).\n3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.\n4. **Execute the SQL query** and return the results.\n5. **Chain tools logically**, such as: List Tables \u2192 Get Schema \u2192 Write and Run Query.\n6. **Explain your reasoning and each step taken** to ensure clarity and transparency.\n\n=========================\n# Critical Rules\n=========================\n\n- Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).\n- Always display any SQL query you generate along with the result of its execution.\n- Validate SQL syntax before execution to ensure correctness and safety.\n- Never make assumptions about the database structure \u2014 always use tools to confirm table and column names.\n- Be cautious, deliberate, and transparent in your actions.\n\n=========================\n# Short-Term Memory\n=========================\n\nYou have access to the following memory from this conversation. Use it if applicable for the current request.\n\n### Conversation Context:\n- **Previous user requests**:\n []\n- **Tools used so far**:\n []\n- **Last SQL queries (if any)**:\n []\n- **Last result preview**:\n []\n\n=========================\n# New User Request\n=========================\n\nPlease fulfill the following request based on the above context:\n\ncan you show me the result of the join of all tables?\n", "=========================\n# Your Role\n=========================\n\nYou are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:\n\n- List available tables\n- Retrieve schema details\n- Execute SQL queries\n\nEach tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.\n\n=========================\n# Your Objective\n=========================\n\nWhen a user submits a request, you must:\n\n1. **Analyze the request** to determine the required data or action.\n2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).\n3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.\n4. **Execute the SQL query** and return the results.\n5. **Chain tools logically**, such as: List Tables \u2192 Get Schema \u2192 Write and Run Query.\n6. **Explain your reasoning and each step taken** to ensure clarity and transparency.\n\n=========================\n# Critical Rules\n=========================\n\n- Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).\n- Always display any SQL query you generate along with the result of its execution.\n- Validate SQL syntax before execution to ensure correctness and safety.\n- Never make assumptions about the database structure \u2014 always use tools to confirm table and column names.\n- Be cautious, deliberate, and transparent in your actions.\n\n=========================\n# Short-Term Memory\n=========================\n\nYou have access to the following memory from this conversation. Use it if applicable for the current request.\n\n### Conversation Context:\n- **Previous user requests**:\n ['=========================\\n# Your Role\\n=========================\\n\\nYou are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:\\n\\n- List available tables\\n- Retrieve schema details\\n- Execute SQL queries\\n\\nEach tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.\\n\\n=========================\\n# Your Objective\\n=========================\\n\\nWhen a user submits a request, you must:\\n\\n1. **Analyze the request** to determine the required data or action.\\n2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).\\n3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.\\n4. **Execute the SQL query** and return the results.\\n5. **Chain tools logically**, such as: List Tables \u2192 Get Schema \u2192 Write and Run Query.\\n6. **Explain your reasoning and each step taken** to ensure clarity and transparency.\\n\\n=========================\\n# Critical Rules\\n=========================\\n\\n- Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).\\n- Always display any SQL query you generate along with the result of its execution.\\n- Validate SQL syntax before execution to ensure correctness and safety.\\n- Never make assumptions about the database structure \u2014 always use tools to confirm table and column names.\\n- Be cautious, deliberate, and transparent in your actions.\\n\\n=========================\\n# Short-Term Memory\\n=========================\\n\\nYou have access to the following memory from this conversation. Use it if applicable for the current request.\\n\\n### Conversation Context:\\n- **Previous user requests**:\\n []\\n- **Tools used so far**:\\n []\\n- **Last SQL queries (if any)**:\\n []\\n- **Last result preview**:\\n []\\n\\n=========================\\n# New User Request\\n=========================\\n\\nPlease fulfill the following request based on the above context:\\n\\ncan you show me the result of the join of all tables?\\n']\n- **Tools used so far**:\n ['execute_query', 'get_table_schema', 'list_tables']\n- **Last SQL queries (if any)**:\n []\n- **Last result preview**:\n ['id | user_id | title | content | created_at | id | username | email | created_at\\n--------------------------------------------------------------------------------\\n1 | 1 | Hello World | This is my first post! | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107\\n2 | 2 | Bob\u2019s Thoughts | Here are some thoughts... | 2025-04-09 11:16:04.846107 | 2 | bob | bob@example.com | 2025-04-09 11:16:04.846107\\n3 | 1 | Follow-up Post | Another one from Alice. | 2025-04-09 11:16:04.846107 | 1 | alice | alice@example.com | 2025-04-09 11:16:04.846107']\n\n=========================\n# New User Request\n=========================\n\nPlease fulfill the following request based on the above context:\n\nhow many columns are there in this joined table?\n"]}
postgre_mcp_client.py CHANGED
@@ -5,8 +5,7 @@ from mcp.client.stdio import stdio_client
5
  from langchain_mcp_adapters.tools import load_mcp_tools
6
  from langgraph.prebuilt import create_react_agent
7
  from langchain.chat_models import init_chat_model
8
- from pprint import pprint
9
- import logging
10
 
11
  llm = init_chat_model(model="gemini-2.0-flash-lite", model_provider="google_genai",api_key ="AIzaSyAuxYmci0DVU5l5L_YcxLlxHzR5MLn70js")
12
 
@@ -21,34 +20,7 @@ The users table stores information about the individuals who use the application
21
 
22
  The posts table represents content created by users, such as blog posts or messages. Like the users table, each entry has a unique, auto-incrementing id as the primary key. The user_id field links each post to its author by referencing the id field in the users table, establishing a one-to-many relationship between users and posts. The title column holds a brief summary or headline of the post, while the content field contains the full text. A created_at timestamp is also included to record when each post was created, with a default value of the current time.
23
  """
24
- prompt_temp = """You are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools enable you to list tables, retrieve schema information, and execute SQL queries. You do not have access to prior memory — if you need any information (like table or column names), you must retrieve it using the appropriate tools. Tool descriptions also contain summaries of the tables, which you can use to understand the structure and content of the database.
25
-
26
- Your task is to carefully analyze the user's request and:
27
-
28
- Select the appropriate FastMCP tool(s) to gather any required database information.
29
-
30
- If you need to generate a SQL query to answer the request, always show the full query explicitly.
31
-
32
- If you generate a valid SQL query, you have to execute it.
33
-
34
- Use only SELECT queries. Never use destructive operations (DELETE, DROP, UPDATE, etc.).
35
-
36
- Chain tools as needed (e.g., list tables → get schema → write and run query).
37
-
38
- Clearly explain your reasoning and each step taken to fulfill the user’s intent accurately and safely.
39
-
40
- Important Rules:
41
-
42
- Always show any SQL query you generate with the result of execution of the query.
43
-
44
- Double-check that the SQL syntax is valid and safe before running it.
45
-
46
- Never assume the database structure — retrieve it using tools when unsure.
47
-
48
- Be cautious, deliberate, and transparent in your actions.
49
-
50
- Here is the user request:
51
- can you show me the result of the join of all tables?"""
52
 
53
  def parse_mcp_output(output_dict):
54
  result = []
@@ -83,10 +55,18 @@ def parse_mcp_output(output_dict):
83
 
84
  result.append({
85
  "type": "ai_function_call",
86
- "query": arguments_dict["query"]
 
 
87
  })
88
  else:
89
  print(f"ai said:{content}")
 
 
 
 
 
 
90
 
91
  else:
92
  print(f"ai final answer:{content}")
@@ -105,32 +85,70 @@ def parse_mcp_output(output_dict):
105
  "response": content
106
  })
107
 
 
 
 
 
 
108
 
109
- return result
110
 
 
111
 
112
 
113
 
 
 
114
  async def main():
115
  async with stdio_client(server_params) as (read, write):
116
  async with ClientSession(read, write) as session:
117
  # Initialize the connection
118
  await session.initialize()
119
 
 
 
 
 
 
 
 
120
  # Get tools
121
  tools = await load_mcp_tools(session)
122
  for tool in tools:
123
  tool.description += f" {table_summary}"
124
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  # Create and run the agent
126
  agent = create_react_agent(llm, tools)
127
- agent_response = await agent.ainvoke({"messages": prompt_temp})
128
 
129
 
130
  parsed_steps = parse_mcp_output(agent_response)
131
- #pprint(parsed_steps)
132
 
133
 
 
 
 
 
 
 
 
 
 
134
 
135
 
136
 
 
5
  from langchain_mcp_adapters.tools import load_mcp_tools
6
  from langgraph.prebuilt import create_react_agent
7
  from langchain.chat_models import init_chat_model
8
+ from conversation_memory import ConversationMemory
 
9
 
10
  llm = init_chat_model(model="gemini-2.0-flash-lite", model_provider="google_genai",api_key ="AIzaSyAuxYmci0DVU5l5L_YcxLlxHzR5MLn70js")
11
 
 
20
 
21
  The posts table represents content created by users, such as blog posts or messages. Like the users table, each entry has a unique, auto-incrementing id as the primary key. The user_id field links each post to its author by referencing the id field in the users table, establishing a one-to-many relationship between users and posts. The title column holds a brief summary or headline of the post, while the content field contains the full text. A created_at timestamp is also included to record when each post was created, with a default value of the current time.
22
  """
23
+ prompt_temp = ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
  def parse_mcp_output(output_dict):
26
  result = []
 
55
 
56
  result.append({
57
  "type": "ai_function_call",
58
+ "ai_said": content,
59
+ "tool": tool_name,
60
+ "args": arguments
61
  })
62
  else:
63
  print(f"ai said:{content}")
64
+ result.append({
65
+ "type": "ai_function_call",
66
+ "ai_said": content,
67
+ "tool": tool_name,
68
+ "args": arguments
69
+ })
70
 
71
  else:
72
  print(f"ai final answer:{content}")
 
85
  "response": content
86
  })
87
 
88
+ elif role_name == "HumanMessage":
89
+ result.append({
90
+ "type": "user_message",
91
+ "content": content
92
+ })
93
 
 
94
 
95
+ return result
96
 
97
 
98
 
99
+ request = "can you show me the result of the join of all tables?"
100
+ request2 = "how many columns are there in this joined table?"
101
  async def main():
102
  async with stdio_client(server_params) as (read, write):
103
  async with ClientSession(read, write) as session:
104
  # Initialize the connection
105
  await session.initialize()
106
 
107
+ memory = ConversationMemory()
108
+ prompt = ""
109
+ with open(r"C:\Users\yukcus\Desktop\MCPTest\prompt_temp.txt", 'r', encoding='utf-8') as file:
110
+ prompt_temp = file.read()
111
+
112
+ prompt += prompt_temp
113
+
114
  # Get tools
115
  tools = await load_mcp_tools(session)
116
  for tool in tools:
117
  tool.description += f" {table_summary}"
118
 
119
+ memory = memory.load_memory()
120
+ past_tools = memory.get_all_tools_used()
121
+ past_queries = memory.get_last_n_queries()
122
+ past_results = memory.get_last_n_results()
123
+ past_requests = memory.get_all_user_messages()
124
+
125
+ prompt = prompt.format(
126
+ user_requests=past_requests,
127
+ past_tools=past_tools,
128
+ last_queries=past_queries,
129
+ last_results=past_results,
130
+ new_request = request2
131
+ )
132
+
133
+
134
+
135
  # Create and run the agent
136
  agent = create_react_agent(llm, tools)
137
+ agent_response = await agent.ainvoke({"messages": prompt})
138
 
139
 
140
  parsed_steps = parse_mcp_output(agent_response)
 
141
 
142
 
143
+ memory.update_from_parsed(parsed_steps)
144
+
145
+ if request.strip().lower() == "stop":
146
+ memory.reset()
147
+ print("Conversation memory reset.")
148
+
149
+ else:
150
+ memory.save_memory()
151
+ #pprint(parsed_steps)
152
 
153
 
154
 
postgre_mcp_server.py CHANGED
@@ -221,6 +221,7 @@ def get_foreign_keys(table_name: str) -> str:
221
  """
222
  return execute_query(sql)
223
 
 
224
  @mcp.tool(description="Fetches and formats the schema details for all tables in the configured database schema.")
225
  async def get_all_schemas() -> str:
226
  """Get schema information for all tables in the database"""
@@ -273,17 +274,17 @@ async def generate_select_query(table_name: str) -> list[PromptMessage]:
273
 
274
  Table Schema:
275
  {columns_text}
276
-
277
  PostgreSQL SQL Best Practices:
278
  - Use explicit column names instead of * when possible
279
  - Include LIMIT clauses to restrict result sets
280
  - Consider adding WHERE clauses to filter results
281
  - Use appropriate indexing considerations
282
  - Format SQL with proper indentation and line breaks
283
-
284
  Create a basic SELECT query following these best practices:"""
285
- )
286
- ]
287
  except Exception as e:
288
  return [PromptMessage(f"Error generating select query: {str(e)}")]
289
 
@@ -313,25 +314,23 @@ async def generate_analytical_query(table_name: str) -> list[PromptMessage]:
313
 
314
  Table Schema:
315
  {columns_text}
316
-
317
  PostgreSQL SQL Best Practices:
318
  - Use aggregation functions (COUNT, SUM, AVG, MIN, MAX) appropriately
319
  - Group data using GROUP BY for meaningful aggregations
320
  - Filter groups with HAVING clauses when needed
321
  - Consider using window functions for advanced analytics
322
  - Format SQL with proper indentation and line breaks
323
-
324
  Create a set of analytical queries for this table:"""
325
- )
326
- ]
327
  except Exception as e:
328
  return [PromptMessage(f"Error generating analytical query: {str(e)}")]
329
 
330
 
331
-
332
-
333
-
334
- @mcp.tool(description="Identifies both explicit and implied foreign key relationships for a given table using schema analysis and naming patterns.")
335
  def find_relationships(table_name: str, schema: str = 'public') -> str:
336
  """Find both explicit and implied relationships for a table.
337
 
 
221
  """
222
  return execute_query(sql)
223
 
224
+
225
  @mcp.tool(description="Fetches and formats the schema details for all tables in the configured database schema.")
226
  async def get_all_schemas() -> str:
227
  """Get schema information for all tables in the database"""
 
274
 
275
  Table Schema:
276
  {columns_text}
277
+
278
  PostgreSQL SQL Best Practices:
279
  - Use explicit column names instead of * when possible
280
  - Include LIMIT clauses to restrict result sets
281
  - Consider adding WHERE clauses to filter results
282
  - Use appropriate indexing considerations
283
  - Format SQL with proper indentation and line breaks
284
+
285
  Create a basic SELECT query following these best practices:"""
286
+ )
287
+ ]
288
  except Exception as e:
289
  return [PromptMessage(f"Error generating select query: {str(e)}")]
290
 
 
314
 
315
  Table Schema:
316
  {columns_text}
317
+
318
  PostgreSQL SQL Best Practices:
319
  - Use aggregation functions (COUNT, SUM, AVG, MIN, MAX) appropriately
320
  - Group data using GROUP BY for meaningful aggregations
321
  - Filter groups with HAVING clauses when needed
322
  - Consider using window functions for advanced analytics
323
  - Format SQL with proper indentation and line breaks
324
+
325
  Create a set of analytical queries for this table:"""
326
+ )
327
+ ]
328
  except Exception as e:
329
  return [PromptMessage(f"Error generating analytical query: {str(e)}")]
330
 
331
 
332
+ @mcp.tool(
333
+ description="Identifies both explicit and implied foreign key relationships for a given table using schema analysis and naming patterns.")
 
 
334
  def find_relationships(table_name: str, schema: str = 'public') -> str:
335
  """Find both explicit and implied relationships for a table.
336
 
prompt_temp.txt ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =========================
2
+ # Your Role
3
+ =========================
4
+
5
+ You are an expert in generating SQL queries and interacting with a PostgreSQL database using FastMCP tools. These tools allow you to:
6
+
7
+ - List available tables
8
+ - Retrieve schema details
9
+ - Execute SQL queries
10
+
11
+ Each tool may also provide summaries of table contents to help you understand the data structure. You have access to **short-term memory**, which stores relevant information from earlier steps or previous queries. If the memory is not empty, you **must** use it when processing the current request. Avoid repeating the same tool with identical input unless the result is **not already present in memory**.
12
+
13
+ =========================
14
+ # Your Objective
15
+ =========================
16
+
17
+ When a user submits a request, you must:
18
+
19
+ 1. **Analyze the request** to determine the required data or action.
20
+ 2. **Use FastMCP tools** to gather any necessary information (e.g., list tables or retrieve schema).
21
+ 3. **Generate a valid SQL SELECT query**, if needed, and clearly show the full query.
22
+ 4. **Execute the SQL query** and return the results.
23
+ 5. **Chain tools logically**, such as: List Tables → Get Schema → Write and Run Query.
24
+ 6. **Explain your reasoning and each step taken** to ensure clarity and transparency.
25
+
26
+ =========================
27
+ # Critical Rules
28
+ =========================
29
+
30
+ - Only use **SELECT** queries. Never use destructive operations (e.g., DELETE, DROP, UPDATE).
31
+ - Always display any SQL query you generate along with the result of its execution.
32
+ - Validate SQL syntax before execution to ensure correctness and safety.
33
+ - Never make assumptions about the database structure — always use tools to confirm table and column names.
34
+ - Be cautious, deliberate, and transparent in your actions.
35
+
36
+ =========================
37
+ # Short-Term Memory
38
+ =========================
39
+
40
+ You have access to the following memory from this conversation. Use it if applicable for the current request.
41
+
42
+ ### Conversation Context:
43
+ - **Previous user requests**:
44
+ {user_requests}
45
+ - **Tools used so far**:
46
+ {past_tools}
47
+ - **Last SQL queries (if any)**:
48
+ {last_queries}
49
+ - **Last result preview**:
50
+ {last_results}
51
+
52
+ =========================
53
+ # New User Request
54
+ =========================
55
+
56
+ Please fulfill the following request based on the above context:
57
+
58
+ {new_request}