|
from typing import Dict, Any, List |
|
from langgraph.graph import Graph, StateGraph |
|
from langgraph.prebuilt import ToolNode |
|
from pydantic import BaseModel, Field |
|
from duckduckgo_search import DDGS |
|
|
|
class CalculatorInput(BaseModel): |
|
operation: str = Field(..., description="The operation to perform (add, subtract, multiply, divide)") |
|
numbers: List[float] = Field(..., description="List of numbers to perform the operation on") |
|
|
|
class CalculatorOutput(BaseModel): |
|
result: float = Field(..., description="The result of the calculation") |
|
operation: str = Field(..., description="The operation that was performed") |
|
|
|
class CalculatorState(BaseModel): |
|
input: CalculatorInput |
|
output: CalculatorOutput = None |
|
|
|
class SearchInput(BaseModel): |
|
query: str = Field(..., description="The search query to look up") |
|
max_results: int = Field(default=3, description="Maximum number of results to return") |
|
|
|
class SearchResult(BaseModel): |
|
title: str = Field(..., description="Title of the search result") |
|
link: str = Field(..., description="URL of the search result") |
|
snippet: str = Field(..., description="Brief description of the search result") |
|
|
|
class SearchOutput(BaseModel): |
|
results: List[SearchResult] = Field(..., description="List of search results") |
|
query: str = Field(..., description="The original search query") |
|
|
|
class SearchState(BaseModel): |
|
input: SearchInput |
|
output: SearchOutput = None |
|
|
|
def create_calculator_tool() -> Graph: |
|
"""Creates a calculator tool using LangGraph that can perform basic arithmetic operations.""" |
|
print("Creating calculator tool") |
|
def calculator_function(state: CalculatorState) -> CalculatorState: |
|
if len(state.input.numbers) < 2: |
|
raise ValueError("At least two numbers are required for calculation") |
|
|
|
result = state.input.numbers[0] |
|
|
|
for num in state.input.numbers[1:]: |
|
if state.input.operation == "add": |
|
result += num |
|
elif state.input.operation == "subtract": |
|
result -= num |
|
elif state.input.operation == "multiply": |
|
result *= num |
|
elif state.input.operation == "divide": |
|
if num == 0: |
|
raise ValueError("Cannot divide by zero") |
|
result /= num |
|
else: |
|
raise ValueError(f"Unsupported operation: {state.input.operation}") |
|
|
|
state.output = CalculatorOutput( |
|
result=result, |
|
operation=state.input.operation |
|
) |
|
|
|
return state |
|
|
|
|
|
workflow = StateGraph(state_schema=CalculatorState) |
|
|
|
|
|
workflow.add_node("calculator", ToolNode(calculator_function)) |
|
|
|
|
|
workflow.set_entry_point("calculator") |
|
workflow.set_finish_point("calculator") |
|
|
|
return workflow.compile() |
|
|
|
def create_search_tool() -> Graph: |
|
"""Creates a search tool using DuckDuckGo that can search for information online.""" |
|
|
|
def search_function(state: SearchState) -> SearchState: |
|
|
|
with DDGS() as ddgs: |
|
|
|
search_results = list(ddgs.text( |
|
state.input.query, |
|
max_results=state.input.max_results |
|
)) |
|
|
|
|
|
results = [ |
|
SearchResult( |
|
title=result["title"], |
|
link=result["link"], |
|
snippet=result["body"] |
|
) |
|
for result in search_results |
|
] |
|
|
|
state.output = SearchOutput( |
|
results=results, |
|
query=state.input.query |
|
) |
|
|
|
return state |
|
|
|
|
|
workflow = StateGraph(state_schema=SearchState) |
|
|
|
|
|
workflow.add_node("search", ToolNode(search_function)) |
|
|
|
|
|
workflow.set_entry_point("search") |
|
workflow.set_finish_point("search") |
|
|
|
return workflow.compile() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|