Update tools/tools_on_modal_labs.py
Browse files- tools/tools_on_modal_labs.py +14 -35
tools/tools_on_modal_labs.py
CHANGED
|
@@ -17,8 +17,7 @@ image = modal.Image.debian_slim().pip_install(
|
|
| 17 |
"groundx",
|
| 18 |
"llama-index",
|
| 19 |
"llama-index-llms-nebius",
|
| 20 |
-
"
|
| 21 |
-
"langchain-community")
|
| 22 |
|
| 23 |
app = modal.App(name="hackathon-mcp-tools", image=image)
|
| 24 |
|
|
@@ -45,7 +44,7 @@ def search_rag_context(queryInput: QueryInput) -> str:
|
|
| 45 |
print(f"RAG Search Result: {result}")
|
| 46 |
print("=============================\n")
|
| 47 |
|
| 48 |
-
return
|
| 49 |
|
| 50 |
def search_groundx_for_rag_context(query) -> str:
|
| 51 |
from groundx import GroundX
|
|
@@ -71,7 +70,7 @@ from llama_index.core.agent.workflow import (
|
|
| 71 |
ToolCallResult,
|
| 72 |
)
|
| 73 |
|
| 74 |
-
from
|
| 75 |
|
| 76 |
@app.function(secrets=[
|
| 77 |
modal.Secret.from_name("hackathon-secret", required_keys=["NEBIUS_API_KEY", "AGENT_MODEL"])
|
|
@@ -92,33 +91,13 @@ llm = NebiusLLM(
|
|
| 92 |
is_function_calling_model=True
|
| 93 |
)
|
| 94 |
|
| 95 |
-
|
| 96 |
-
duckduckgo = DuckDuckGoSearchAPIWrapper()
|
| 97 |
-
|
| 98 |
-
MAX_SEARCH_CALLS = 2 # Limit the number of searches to 2
|
| 99 |
-
search_call_count = 0
|
| 100 |
-
past_queries = set()
|
| 101 |
-
|
| 102 |
-
async def duckduckgo_search(query: str) -> str:
|
| 103 |
-
"""
|
| 104 |
-
A DuckDuckGo-based search limiting number of searches and avoiding duplicates.
|
| 105 |
-
"""
|
| 106 |
-
global search_call_count, past_queries
|
| 107 |
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
if search_call_count >= MAX_SEARCH_CALLS:
|
| 114 |
-
return "Search limit reached."
|
| 115 |
-
|
| 116 |
-
# Otherwise, perform the search
|
| 117 |
-
search_call_count += 1
|
| 118 |
-
past_queries.add(query)
|
| 119 |
-
|
| 120 |
-
result = duckduckgo.run(query)
|
| 121 |
-
return str(result)
|
| 122 |
|
| 123 |
# Research tools
|
| 124 |
async def save_research(ctx: Context, notes: str, notes_title: str) -> str:
|
|
@@ -166,8 +145,8 @@ async def review_report(ctx: Context, review: str) -> str:
|
|
| 166 |
research_agent = FunctionAgent(
|
| 167 |
name="ResearchAgent",
|
| 168 |
description=(
|
| 169 |
-
"A research agent that searches the web using
|
| 170 |
-
"It must not exceed
|
| 171 |
"Once sufficient information is collected, it should hand off to the WriteAgent."
|
| 172 |
),
|
| 173 |
system_prompt=(
|
|
@@ -178,10 +157,10 @@ research_agent = FunctionAgent(
|
|
| 178 |
),
|
| 179 |
llm=llm,
|
| 180 |
tools=[
|
| 181 |
-
|
| 182 |
save_research
|
| 183 |
],
|
| 184 |
-
max_iterations=
|
| 185 |
cooldown=5, # Cooldown to prevent rapid re-querying
|
| 186 |
can_handoff_to=["WriteAgent"]
|
| 187 |
)
|
|
@@ -230,7 +209,7 @@ agent_workflow = AgentWorkflow(
|
|
| 230 |
root_agent=research_agent.name, # Start with the ResearchAgent
|
| 231 |
initial_state={
|
| 232 |
"research_notes": {},
|
| 233 |
-
"report_content": "
|
| 234 |
"review": "Review required.",
|
| 235 |
},
|
| 236 |
)
|
|
|
|
| 17 |
"groundx",
|
| 18 |
"llama-index",
|
| 19 |
"llama-index-llms-nebius",
|
| 20 |
+
"tavily-python")
|
|
|
|
| 21 |
|
| 22 |
app = modal.App(name="hackathon-mcp-tools", image=image)
|
| 23 |
|
|
|
|
| 44 |
print(f"RAG Search Result: {result}")
|
| 45 |
print("=============================\n")
|
| 46 |
|
| 47 |
+
return result
|
| 48 |
|
| 49 |
def search_groundx_for_rag_context(query) -> str:
|
| 50 |
from groundx import GroundX
|
|
|
|
| 70 |
ToolCallResult,
|
| 71 |
)
|
| 72 |
|
| 73 |
+
from tavily import AsyncTavilyClient
|
| 74 |
|
| 75 |
@app.function(secrets=[
|
| 76 |
modal.Secret.from_name("hackathon-secret", required_keys=["NEBIUS_API_KEY", "AGENT_MODEL"])
|
|
|
|
| 91 |
is_function_calling_model=True
|
| 92 |
)
|
| 93 |
|
| 94 |
+
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 95 |
|
| 96 |
+
# Search tools using Tavily
|
| 97 |
+
async def search_web(query: str) -> str:
|
| 98 |
+
"""Useful for using the web to answer questions."""
|
| 99 |
+
client = AsyncTavilyClient(api_key=TAVILY_API_KEY)
|
| 100 |
+
return str(await client.search(query))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
|
| 102 |
# Research tools
|
| 103 |
async def save_research(ctx: Context, notes: str, notes_title: str) -> str:
|
|
|
|
| 145 |
research_agent = FunctionAgent(
|
| 146 |
name="ResearchAgent",
|
| 147 |
description=(
|
| 148 |
+
"A research agent that searches the web using TavilyClient Search."
|
| 149 |
+
"It must not exceed 3 searches total, and must avoid repeating the same query. "
|
| 150 |
"Once sufficient information is collected, it should hand off to the WriteAgent."
|
| 151 |
),
|
| 152 |
system_prompt=(
|
|
|
|
| 157 |
),
|
| 158 |
llm=llm,
|
| 159 |
tools=[
|
| 160 |
+
search_web,
|
| 161 |
save_research
|
| 162 |
],
|
| 163 |
+
max_iterations=3, # Limit to 2 iterations to prevent infinite loops
|
| 164 |
cooldown=5, # Cooldown to prevent rapid re-querying
|
| 165 |
can_handoff_to=["WriteAgent"]
|
| 166 |
)
|
|
|
|
| 209 |
root_agent=research_agent.name, # Start with the ResearchAgent
|
| 210 |
initial_state={
|
| 211 |
"research_notes": {},
|
| 212 |
+
"report_content": "No report has been generated after the search.",
|
| 213 |
"review": "Review required.",
|
| 214 |
},
|
| 215 |
)
|