File size: 3,600 Bytes
c620442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9776052
 
 
 
 
c620442
9776052
c620442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import os
from typing import TypedDict, Annotated, Sequence
import operator
from langgraph.graph import StateGraph, END
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_community.tools import DuckDuckGoSearchRun
from langchain_community.document_loaders import WikipediaLoader, ArxivLoader
from langchain_core.messages import BaseMessage, HumanMessage, SystemMessage
from langchain.agents import Tool
from langchain_core.tools import tool

# Load environment variables (compatible with Hugging Face Space)
google_api_key = os.getenv("GOOGLE_API_KEY") or os.environ.get("GOOGLE_API_KEY")
if not google_api_key:
    raise ValueError("Missing GOOGLE_API_KEY environment variable")

# --- System Prompt ---
with open("System_Prompt.txt", "r", encoding="utf-8") as f:
    system_prompt = f.read()
sys_msg = SystemMessage(content=system_prompt)

# --- Tool Definitions ---
@tool
def multiply(a: int, b: int) -> int:
    """Multiply two integers together."""
    return a * b

@tool
def add(a: int, b: int) -> int:
    """Add two integers together."""
    return a + b

@tool
def subtract(a: int, b: int) -> int:
    """Subtract b from a."""
    return a - b

@tool
def divide(a: int, b: int) -> float:
    """Divide a by b. Returns float. Raises error if b is zero."""
    if b == 0:
        raise ValueError("Cannot divide by zero.")
    return a / b

@tool
def wiki_search(query: str) -> str:
    """Search Wikipedia and return up to 2 relevant documents."""
    docs = WikipediaLoader(query=query, load_max_docs=2).load()
    if not docs:
        return "No Wikipedia results found."
    return "\n\n".join([d.page_content[:1000] for d in docs])

# Tool inventory with proper categorization
tools = [
    Tool(name="Math_Multiply", func=multiply, description="Multiplies two integers"),
    Tool(name="Math_Add", func=add, description="Adds two integers"),
    Tool(name="Math_Subtract", func=subtract, description="Subtracts two integers"),
    Tool(name="Math_Divide", func=divide, description="Divides two numbers"),
    Tool(name="Search_Wikipedia", func=wiki_search, description="Searches Wikipedia"),
    Tool(
        name="Search_Web", 
        func=DuckDuckGoSearchRun().run,
        description="Searches the web using DuckDuckGo"
    )
]

# --- Graph Definition ---
class AgentState(TypedDict):
    """State definition for the agent workflow"""
    messages: Annotated[Sequence[BaseMessage], operator.add]

def build_graph():
    """Constructs and compiles the LangGraph workflow"""
    
    # Initialize LLM with Gemini 2.0 Flash
    llm = ChatGoogleGenerativeAI(
        model="gemini-2.0-flash-exp",
        temperature=0.3,
        google_api_key=google_api_key
    )
    llm_with_tools = llm.bind_tools(tools)

    # Node definitions
    def agent_node(state: AgentState):
        """Main agent node that processes messages"""
        response = llm_with_tools.invoke(state["messages"])
        return {"messages": [response]}

    # Graph construction
    workflow = StateGraph(AgentState)
    
    # Add nodes to the workflow
    workflow.add_node("agent", agent_node)
    workflow.add_node("tools", ToolNode(tools))
    
    # Configure graph flow
    workflow.set_entry_point("agent")
    workflow.add_conditional_edges(
        "agent",
        tools_condition,  # LangGraph's built-in tool detection
        {"tools": "tools", "end": END}  # Fixed END reference
    )
    workflow.add_edge("tools", "agent")
    
    return workflow.compile()

# Initialize the agent graph
agent_graph = build_graph()