Spaces:
Build error
Build error
File size: 6,070 Bytes
1d89d60 | 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 | import os
import logging
from typing import Literal, Union
from langchain_core.tools import tool
from langchain_community.tools.tavily_search import TavilySearchResults
from langchain_community.document_loaders import WikipediaLoader
from langchain_community.document_loaders import ArxivLoader
from googleapiclient.discovery import build
# Configure basic logging for tools
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# --- Arithmetic Tool ---
@tool
def perform_calculation(
a: Union[int, float],
b: Union[int, float],
operation: Literal["add", "subtract", "multiply", "divide", "modulus"],
) -> Union[int, float, str]:
"""Performs a specified arithmetic operation on two numbers.
Args:
a: The first number (integer or float).
b: The second number (integer or float).
operation: The arithmetic operation to perform.
Must be one of "add", "subtract", "multiply", "divide", or "modulus".
"""
logging.info(f"Tool Call: perform_calculation(a={a}, b={b}, operation='{operation}')")
try:
if operation == "add":
result = a + b
elif operation == "subtract":
result = a - b
elif operation == "multiply":
result = a * b
elif operation == "divide":
if b == 0:
logging.warning("perform_calculation: Division by zero attempted.")
return "Error: Cannot divide by zero."
result = a / b
elif operation == "modulus":
if b == 0:
logging.warning("perform_calculation: Modulus with zero divisor attempted.")
return "Error: Cannot perform modulus with zero divisor."
# Optional: enforce integer for modulus for clarity/LLM expectation
if not isinstance(a, int) or not isinstance(b, int):
logging.warning("perform_calculation: Modulus with non-integer operands. Results might be float.")
# You might return a specific error or proceed depending on desired behavior
result = a % b
else:
logging.error(f"perform_calculation: Invalid operation '{operation}' specified.")
return "Error: Invalid operation specified."
logging.info(f"perform_calculation: Result of {operation} on {a}, {b} is {result}")
return result
except Exception as e:
logging.error(f"perform_calculation: An unexpected error occurred: {e}", exc_info=True)
return f"Error during calculation: {e}"
# --- Search & Document Loader Tools ---
@tool
def search_from_wiki(query: str) -> str:
"""Search Wikipedia for a query and return maximum 2 relevant sections.
Args:
query: The search query for Wikipedia."""
logging.info(f"Tool Call: search_from_wiki(query='{query}')")
try:
search_docs = WikipediaLoader(query=query, load_max_docs=2).load()
if not search_docs:
logging.info(f"search_from_wiki: No results found for '{query}'.")
return {"wiki_results": f"No Wikipedia results found for '{query}'."}
formatted_search_docs = "\n\n---\n\n".join(
[
f'<Document source="{doc.metadata.get("source", "Wikipedia")}" '
f'page="{doc.metadata.get("page", "")}" '
f'title="{doc.metadata.get("title", "No Title")}">\n'
f'{doc.page_content}\n</Document>'
for doc in search_docs
]
)
logging.info(f"search_from_wiki: Successfully fetched {len(search_docs)} results for '{query}'.")
return {"wiki_results": formatted_search_docs}
except Exception as e:
logging.error(f"search_from_wiki: An error occurred for query '{query}': {e}", exc_info=True)
return {"wiki_results": f"An error occurred during Wikipedia search for '{query}': {e}. Please try a different query or source."}
@tool
def search_from_arxiv(query: str) -> str:
"""Search Arxiv for a query and return maximum 3 relevant paper abstracts/summaries.
Args:
query: The search query for Arxiv."""
logging.info(f"Tool Call: search_from_arxiv(query='{query}')")
try:
search_docs = ArxivLoader(query=query, load_max_docs=3).load()
if not search_docs:
logging.info(f"search_from_arxiv: No results found for '{query}'.")
return {"arvix_results": f"No Arxiv results found for '{query}'."}
formatted_search_docs = "\n\n---\n\n".join(
[
f'<Document source="{doc.metadata.get("source", "Arxiv")}" '
f'published="{doc.metadata.get("Published", "Unknown")}" '
f'title="{doc.metadata.get("Title", "No Title")}" '
f'authors="{", ".join(doc.metadata.get("Authors", ["Unknown"]))}" '
f'id="{doc.metadata.get("Id", "No ID")}">\n'
f'{doc.page_content[:1500]}...\n</Document>'
for doc in search_docs
]
)
logging.info(f"search_from_arxiv: Successfully fetched {len(search_docs)} results for '{query}'.")
return {"arvix_results": formatted_search_docs}
except Exception as e:
logging.error(f"search_from_arxiv: An error occurred for query '{query}': {e}", exc_info=True)
return {"arvix_results": f"An error occurred during Arxiv search for '{query}': {e}. Please try a different query or source."}
@tool
def search_from_web(query: str) -> str:
"""Search Google and return top results."""
api_key = os.getenv("GOOGLE_API_KEY")
cse_id = os.getenv("GOOGLE_CSE_ID")
service = build("customsearch", "v1", developerKey=api_key)
res = service.cse().list(q=query, cx=cse_id, num=3).execute()
results = res.get("items", [])
return "\n\n---\n\n".join(f"{item['title']}\n{item['link']}\n{item['snippet']}" for item in results)
# List all tools available to the agent
tools = [perform_calculation, search_from_arxiv, search_from_wiki,search_from_web] |