Spaces:
Sleeping
Sleeping
File size: 7,358 Bytes
dd8ccca 18cb4ee 1d4c10f dd8ccca 0b1169d dd8ccca 18cb4ee dd8ccca 18cb4ee dd8ccca d1e5bf8 d912fe7 5ce8e58 18cb4ee d912fe7 d1e5bf8 18cb4ee d912fe7 d1e5bf8 18cb4ee d912fe7 d1e5bf8 dd8ccca d1e5bf8 d912fe7 5ce8e58 18cb4ee d912fe7 d1e5bf8 5942702 18cb4ee d912fe7 d1e5bf8 18cb4ee d912fe7 d1e5bf8 d912fe7 18cb4ee d912fe7 0b1169d d912fe7 18cb4ee dd8ccca d912fe7 18cb4ee 0b1169d d912fe7 18cb4ee d912fe7 18cb4ee d912fe7 ae86d09 d912fe7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
import os
from dotenv import load_dotenv
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_community.document_loaders import WikipediaLoader
from langchain_core.tools import tool # Consolidated import for @tool decorator
from datetime import datetime
from langchain_experimental.utilities import PythonREPL
# Load environment variables
load_dotenv()
# === MATH TOOL ===
# Consolidated calculator tool
@tool
def calculator(a: float, b: float, operation: str) -> float:
"""
Performs a mathematical operation (addition, subtraction, multiplication, division) on two numbers.
Input should be a dictionary with 'a' (float, first number), 'b' (float, second number),
and 'operation' (string, e.g., 'add', 'subtract', 'multiply', 'divide') keys.
Example: {"a": 5.5, "b": 10.0, "operation": "add"}
"""
if operation == "add":
return a + b
elif operation == "subtract":
return a - b
elif operation == "multiply":
return a * b
elif operation == "divide":
if b == 0:
raise ValueError("Cannot divide by zero.")
return a / b
else:
raise ValueError("Invalid operation. Choose from 'add', 'subtract', 'multiply', 'divide'.")
# === SEARCH TOOLS ===
@tool
def wiki_search(query: str) -> dict:
"""
Search Wikipedia for a given query and return up to 2 relevant document results.
Useful for factual questions about people, places, events, etc.
Input should be a string representing the search query.
Example: {"query": "Barack Obama"}
The output is a dictionary with a 'wiki_results' key containing the formatted search results.
"""
try:
if not query.strip():
return {"wiki_results": "Error: Empty query provided."}
# LangChain's WikipediaLoader returns Document objects
search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
if not search_docs:
return {"wiki_results": "No results found on Wikipedia."}
# Format results for the LLM
formatted = "\n\n---\n\n".join(
f'<Document source="{doc.metadata.get("source", "unknown")}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
for doc in search_docs
)
return {"wiki_results": formatted}
except Exception as e:
return {"wiki_results": f"Error during Wikipedia search: {str(e)}"}
@tool
def web_search(query: str) -> dict:
"""
Search the web using Tavily for a given query and return up to 3 relevant snippets.
Useful for up-to-date information, current events, or general web searches.
Input should be a string representing the search query. Requires TAVILY_API_KEY environment variable.
Example: {"query": "latest news on AI"}
The output is a dictionary with a 'web_results' key containing the formatted search results.
"""
try:
if not query.strip():
return {"web_results": "Error: Empty query provided."}
if not os.getenv("TAVILY_API_KEY"):
return {"web_results": "Error: Tavily API key is not configured."}
# TavilySearchResults.invoke expects 'query' as a keyword argument
search_docs = TavilySearchResults(max_results=3).invoke(query=query)
if not search_docs:
return {"web_results": "No results found on the web."}
# Format results for the LLM
formatted = "\n\n---\n\n".join(
f'<Document source="{doc.metadata.get("source", "unknown")}" page="{doc.metadata.get("page", "")}"/>\n{doc.page_content}\n</Document>'
for doc in search_docs
)
return {"web_results": formatted}
except Exception as e:
return {"web_results": f"Error during web search: {str(e)}"}
# === UTILITY TOOLS ===
@tool
def get_current_datetime(format_string: str = "%Y-%m-%d %H:%M:%S") -> str:
"""
Returns the current date and time in a specified format.
Useful for questions related to the current date, time, or for calculating durations.
Input is an optional format_string (string, default: "%Y-%m-%d %H:%M:%S").
Example: {"format_string": "%A, %B %d, %Y"} will return "Wednesday, July 16, 2025".
"""
try:
# Using current time as per system prompt guidance
current_time = datetime(2025, 7, 16, 12, 43, 1) # Specific time provided in context
return current_time.strftime(format_string)
except Exception as e:
return f"Error getting current datetime: {str(e)}"
# === CODE EXECUTION TOOL ===
# Initialize PythonREPL
python_repl = PythonREPL()
# Create a LangChain Tool from the PythonREPL
@tool
def python_repl_tool(code: str) -> str:
"""
Executes Python code and returns the output.
Useful for mathematical calculations, string manipulations, list operations,
logic problems, and any task that can be solved with Python code.
Input should be a string containing valid Python code to execute.
Example: {"code": "print(2 + 2)"}
"""
try:
# LangChain's PythonREPL.run expects a string input
return python_repl.run(code)
except Exception as e:
return f"Error executing Python code: {str(e)}"
# === TOOLSET EXPORT ===
# List of all available tools to be imported by agent.py
tools_for_llm = [
calculator, # Replaced individual math tools
wiki_search,
web_search,
get_current_datetime,
python_repl_tool,
]
# For local testing of tools (optional)
if __name__ == "__main__":
print("Testing tools.py functionalities...")
# Set dummy API key for testing if not already set in .env
# os.environ["TAVILY_API_KEY"] = "YOUR_TAVILY_API_KEY" # Replace with a real key for actual testing
# Test Math Tool
print("\n--- Calculator Tool Test ---")
print(f"Calculator(5, 3, 'multiply'): {calculator.invoke({'a': 5, 'b': 3, 'operation': 'multiply'})}")
print(f"Calculator(10.5, 2.3, 'add'): {calculator.invoke({'a': 10.5, 'b': 2.3, 'operation': 'add'})}")
try:
print(f"Calculator(7, 0, 'divide') (should error): {calculator.invoke({'a': 7, 'b': 0, 'operation': 'divide'})}")
except ValueError as e:
print(f" Error caught as expected: {e}")
# Test Search Tools
print("\n--- Search Tools Test ---")
wiki_res = wiki_search.invoke({'query': 'Artificial Intelligence'})
print(f"Wiki Search 'Artificial Intelligence': {wiki_res['wiki_results'][:200]}...") # Limit output for brevity
web_res = web_search.invoke({'query': 'Hugging Face new features'})
print(f"Web Search 'Hugging Face new features': {web_res['web_results'][:200]}...") # Limit output for brevity
# Test Utility Tool
print("\n--- Utility Tools Test ---")
print(f"Current Datetime (default): {get_current_datetime.invoke({})}")
print(f"Current Datetime (custom format): {get_current_datetime.invoke({'format_string': '%A, %d %B %Y'})}")
# Test Python REPL Tool
print("\n--- Python REPL Tool Test ---")
print(f"Python REPL '2 + 2': {python_repl_tool.invoke({'code': '2 + 2'})}")
test_code_len = 'len("hello")'
print(f"Python REPL '{test_code_len}': {python_repl_tool.invoke({'code': test_code_len})}")
print(f"Python REPL error: {python_repl_tool.invoke({'code': '10 / 0'})}") |