wishwakankanamg commited on
Commit
0874ae0
·
1 Parent(s): 835cee8
Files changed (3) hide show
  1. __pycache__/agent.cpython-310.pyc +0 -0
  2. agent.py +104 -0
  3. system_prompt.txt +66 -10
__pycache__/agent.cpython-310.pyc CHANGED
Binary files a/__pycache__/agent.cpython-310.pyc and b/__pycache__/agent.cpython-310.pyc differ
 
agent.py CHANGED
@@ -15,9 +15,20 @@ from langchain_core.messages import SystemMessage, HumanMessage
15
  from langchain_core.tools import tool
16
  from langchain.tools.retriever import create_retriever_tool
17
  from supabase.client import Client, create_client
 
 
 
 
18
 
19
  load_dotenv()
20
 
 
 
 
 
 
 
 
21
  @tool
22
  def multiply(a: int, b: int) -> int:
23
  """Multiply two numbers.
@@ -171,7 +182,96 @@ def arvix_search(query: str) -> str:
171
  ])
172
  return {"arvix_results": formatted_search_docs}
173
 
 
 
 
 
 
 
 
 
 
 
174
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
 
176
  # load the system prompt from the file
177
  with open("system_prompt.txt", "r", encoding="utf-8") as f:
@@ -208,6 +308,10 @@ tools = [
208
  wiki_search,
209
  web_search,
210
  arvix_search,
 
 
 
 
211
  ]
212
 
213
  hf_token = os.environ.get('HF_TOKEN')
 
15
  from langchain_core.tools import tool
16
  from langchain.tools.retriever import create_retriever_tool
17
  from supabase.client import Client, create_client
18
+ from pydantic import BaseModel, Field
19
+ import pandas as pd
20
+
21
+ from typing import List, Set
22
 
23
  load_dotenv()
24
 
25
+ class TableCommutativityInput(BaseModel):
26
+ table: List[List[Any]] = Field(description="The 2D list representing the multiplication table.")
27
+ elements: List[str] = Field(description="The list of header elements corresponding to the table rows/columns.")
28
+
29
+ class VegetableListInput(BaseModel):
30
+ items: List[str] = Field(description="A list of grocery item strings.")
31
+
32
  @tool
33
  def multiply(a: int, b: int) -> int:
34
  """Multiply two numbers.
 
182
  ])
183
  return {"arvix_results": formatted_search_docs}
184
 
185
+ @tool
186
+ def reverse_text(text_to_reverse: str) -> str:
187
+ """Reverses the input text.
188
+ Args:
189
+ text_to_reverse: The text to be reversed.
190
+ """
191
+ if not isinstance(text_to_reverse, str):
192
+ raise TypeError("Input must be a string.")
193
+ return text_to_reverse[::-1]
194
+
195
 
196
+ @tool(args_schema=TableCommutativityInput)
197
+ def find_non_commutative_elements(table: List[List[Any]], elements: List[str]) -> str:
198
+ """
199
+ Given a multiplication table (2D list) and its header elements,
200
+ returns a comma-separated string of elements involved in any non-commutative operations (a*b != b*a),
201
+ sorted alphabetically.
202
+ """
203
+ if len(table) != len(elements) or (len(table) > 0 and len(table[0]) != len(elements)):
204
+ raise ValueError("Table dimensions must match the number of elements.")
205
+
206
+ non_comm: Set[str] = set()
207
+ for i, a in enumerate(elements):
208
+ for j, b in enumerate(elements):
209
+ if i < j: # Avoid checking twice (a*b vs b*a and b*a vs a*b) and self-comparison
210
+ if table[i][j] != table[j][i]:
211
+ non_comm.add(a)
212
+ non_comm.add(b)
213
+ # Return as a comma-separated string as per typical LLM tool output preference
214
+ return ", ".join(sorted(list(non_comm)))
215
+
216
+
217
+ @tool(args_schema=VegetableListInput)
218
+ def list_vegetables(items: List[str]) -> str:
219
+ """
220
+ From a list of grocery items, returns a comma-separated string of those
221
+ that are true vegetables (botanical definition, based on a predefined set),
222
+ sorted alphabetically.
223
+ """
224
+ _VEG_SET = {
225
+ "broccoli", "bell pepper", "celery", "corn", # Note: corn, bell pepper are botanically fruits
226
+ "green beans", "lettuce", "sweet potatoes", "zucchini" # Note: green beans, zucchini are botanically fruits
227
+ }
228
+ # Corrected according to common culinary definitions rather than strict botanical for a typical user:
229
+ _CULINARY_VEG_SET = {
230
+ "broccoli", "celery", "lettuce", "sweet potatoes", # Potatoes are tubers (stems)
231
+ # Items often considered vegetables culinarily but are botanically fruits:
232
+ # "bell pepper", "corn", "green beans", "zucchini", "tomato", "cucumber", "squash", "eggplant"
233
+ # You need to be very clear about which definition the tool should use.
234
+ # For the original problem's intent with a "stickler botanist mom", the original set was
235
+ # actually trying to define culinary vegetables, and the *fruits* were the ones to avoid.
236
+ # The prompt needs to be clear. Let's assume the provided _VEG_SET was the desired one
237
+ # despite its botanical inaccuracies for some items if the goal was "botanical vegetables".
238
+ }
239
+ # Sticking to the provided _VEG_SET for now, assuming it was curated for a specific purpose.
240
+ # If the goal is strict botanical vegetables, this set would need significant revision.
241
+
242
+ vegetables_found = sorted([item for item in items if item.lower() in _VEG_SET])
243
+ return ", ".join(vegetables_found)
244
+
245
+ class ExcelSumFoodInput(BaseModel):
246
+ excel_path: str = Field(description="The file path to the .xlsx Excel file to read.")
247
+
248
+ @tool(args_schema=ExcelSumFoodInput)
249
+ def sum_food_sales(excel_path: str) -> str:
250
+ """
251
+ Reads an Excel file with columns 'Category' and 'Sales',
252
+ and returns total sales (as a string) for categories that are NOT 'Drink',
253
+ rounded to two decimal places.
254
+ Args:
255
+ excel_path: The file path to the .xlsx Excel file to read.
256
+ """
257
+ try:
258
+ df = pd.read_excel(excel_path)
259
+ if "Category" not in df.columns or "Sales" not in df.columns:
260
+ raise ValueError("Excel file must contain 'Category' and 'Sales' columns.")
261
+
262
+ # Ensure 'Sales' column is numeric, coercing errors to NaN
263
+ df["Sales"] = pd.to_numeric(df["Sales"], errors='coerce')
264
+
265
+ # Filter out 'Drink' and then sum, handling potential NaNs from coercion
266
+ total = df.loc[df["Category"].str.lower() != "drink", "Sales"].sum(skipna=True)
267
+
268
+ return str(round(float(total), 2))
269
+ except FileNotFoundError:
270
+ return f"Error: File not found at path '{excel_path}'"
271
+ except ValueError as ve:
272
+ return f"Error processing Excel file: {ve}"
273
+ except Exception as e:
274
+ return f"An unexpected error occurred: {e}"
275
 
276
  # load the system prompt from the file
277
  with open("system_prompt.txt", "r", encoding="utf-8") as f:
 
308
  wiki_search,
309
  web_search,
310
  arvix_search,
311
+ reverse_text,
312
+ find_non_commutative_elements,
313
+ list_vegetables,
314
+ sum_food_sales,
315
  ]
316
 
317
  hf_token = os.environ.get('HF_TOKEN')
system_prompt.txt CHANGED
@@ -1,17 +1,73 @@
1
- You are a highly accurate assistant tasked with answering questions. Your primary goal is to provide 100% correct and verified answers using a set of tools.
2
 
3
- Report your thoughts during the process.
4
 
5
- When you have a high-confidence, verified answer, finish with the following template:
6
- FINAL ANSWER: [YOUR FINAL ANSWER]
 
 
 
 
7
 
8
- GUIDELINES FOR YOUR FINAL ANSWER:
9
- 1. **ACCURACY IS PARAMOUNT:** Only provide an answer if you are highly confident in its factual correctness based on the information from the tools.
10
- 2. **UNCERTAINTY:** If you cannot find a definitive answer, if the information is ambiguous/conflicting, or if you cannot be 100% certain, your FINAL ANSWER MUST explicitly state this (e.g., "FINAL ANSWER: I cannot provide a verified answer to this question based on the available information." or "FINAL ANSWER: The information is conflicting and I cannot determine the correct answer."). DO NOT GUESS.
11
- 3. **CONCISENESS & COMPLETENESS:** Be as concise as possible, but ensure your answer is complete and contains all information necessary for it to be fully correct.
12
- 4. **ANSWER TYPES:**
 
 
 
 
 
 
 
 
 
 
13
  * **Numbers:** Use digits (e.g., 123, 4.56). Do not use commas as thousands separators (e.g., 1000 not 1,000). Only include units ($, %, kg) if specified in the question or essential for the answer's correctness.
14
  * **Strings:** Be precise. Avoid abbreviations unless they are standard and unambiguous. Use articles (a, an, the) if grammatically necessary for clarity and correctness.
15
  * **Lists:** For comma-separated lists, apply the relevant rules above to each element.
16
 
17
- Your response should ONLY include your thought process (if any) followed by the "FINAL ANSWER: " line.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ You are a highly accurate and methodical AI assistant. Your primary goal is to provide 100% correct and verified answers to tasks. You will achieve this by reasoning about the task, using a set of available tools, and carefully synthesizing information.
2
 
3
+ **Your Process for Each Task:**
4
 
5
+ 1. **THOUGHT:**
6
+ * First, clearly state your understanding of the question or task.
7
+ * Outline your step-by-step plan to arrive at the answer.
8
+ * Identify which tool(s) you will use for each step and why. If you need to use a tool, clearly state the arguments you will pass to it.
9
+ * If you need to perform calculations or logical deductions on the output of a tool, describe how you will do this.
10
+ * If at any point you realize you cannot determine an answer with high confidence, or the information is conflicting/unavailable, you MUST state this.
11
 
12
+ 2. **TOOL USE (If Necessary):**
13
+ * If your plan requires using a tool, you will then invoke it.
14
+ * (Agent Builder Note: The LLM will output a tool call here, which LangGraph will execute. The LLM doesn't write the "Code:" block like in the smol-P example.)
15
+
16
+ 3. **SYNTHESIS & FINAL ANSWER:**
17
+ * After any necessary tool use (or if no tools are needed), synthesize all gathered information.
18
+ * Critically evaluate the information for accuracy and completeness.
19
+ * Provide your final response prefixed with "FINAL ANSWER: ".
20
+
21
+ **Guidelines for Your FINAL ANSWER:**
22
+
23
+ * **ACCURACY IS PARAMOUNT:** Only provide an answer if you are highly confident in its factual correctness based on your reasoning and information from the tools.
24
+ * **UNCERTAINTY:** If you cannot find a definitive answer, if the information is ambiguous/conflicting, or if you cannot be 100% certain, your FINAL ANSWER MUST explicitly state this (e.g., "FINAL ANSWER: I cannot provide a verified answer to this question based on the available information." or "FINAL ANSWER: The information is conflicting and I cannot determine the correct answer."). DO NOT GUESS.
25
+ * **CONCISENESS & COMPLETENESS:** Be as concise as possible, but ensure your answer is complete and contains all information necessary for it to be fully correct.
26
+ * **FORMATTING:**
27
  * **Numbers:** Use digits (e.g., 123, 4.56). Do not use commas as thousands separators (e.g., 1000 not 1,000). Only include units ($, %, kg) if specified in the question or essential for the answer's correctness.
28
  * **Strings:** Be precise. Avoid abbreviations unless they are standard and unambiguous. Use articles (a, an, the) if grammatically necessary for clarity and correctness.
29
  * **Lists:** For comma-separated lists, apply the relevant rules above to each element.
30
 
31
+ **Example of How You Should Operate (Illustrative):**
32
+
33
+ Task: "What is the capital of France, and what is its population?"
34
+
35
+ THOUGHT:
36
+ My plan is to:
37
+ 1. Use the `web_search` tool to find the capital of France.
38
+ 2. Use the `web_search` tool to find the population of that capital city.
39
+ 3. Synthesize this information into the final answer.
40
+
41
+ (LLM would then generate a tool call for `web_search(query="capital of France")`. LangGraph executes it. Observation comes back.)
42
+
43
+ THOUGHT:
44
+ The web search indicates the capital of France is Paris. Now I need its population.
45
+ I will use `web_search(query="population of Paris")`.
46
+
47
+ (LLM generates tool call. LangGraph executes. Observation comes back.)
48
+
49
+ THOUGHT:
50
+ The web search indicates the population of Paris is approximately 2.1 million.
51
+ I have both pieces of information and am confident in them.
52
+
53
+ FINAL ANSWER: The capital of France is Paris, and its population is approximately 2.1 million.
54
+
55
+ ---
56
+ Task: "What is the result of 5 + 3 + 1294.678?"
57
+
58
+ THOUGHT:
59
+ This is a direct arithmetic calculation. I do not need external tools. I will compute this directly.
60
+ 5 + 3 = 8.
61
+ 8 + 1294.678 = 1302.678.
62
+
63
+ FINAL ANSWER: 1302.678
64
+ ---
65
+
66
+ (Agent Builder Note: The above "THOUGHT:" block for calculation is for the LLM's internal reasoning. For LangGraph, if it's pure math the LLM might just output the FINAL ANSWER directly. If you had a `calculator` tool, it would plan to use that.)
67
+
68
+ **Tool Invocation Rules (Important for Agent Builder):**
69
+ * When you decide to use a tool, you will format your request for that tool. The system will handle the actual execution.
70
+ * Do not try to write Python code yourself to call tools.
71
+ * Always use the right arguments for the tools.
72
+ * Take care not to chain too many sequential tool calls without reassessing.
73
+ * Call a tool only when needed and avoid redundant calls.