Commit ·
01faebd
1
Parent(s): c82d598
feat(agent): add file URL support to agent query handling
Browse filesAdd optional `file_url` parameter to `run()` and `BasicAgent.__call__()` methods. When a task_id is available, construct and pass the file URL to the agent alongside the question text, allowing the supervisor to access attached files during processing.
- .gitignore +2 -0
- agent/agent.py +10 -4
- agent/tools/file_downloader.py +34 -0
- app.py +6 -3
- workspace/README.md +1 -0
.gitignore
CHANGED
|
@@ -1,3 +1,5 @@
|
|
| 1 |
.env
|
| 2 |
*.pyc
|
| 3 |
__pycache__/
|
|
|
|
|
|
|
|
|
| 1 |
.env
|
| 2 |
*.pyc
|
| 3 |
__pycache__/
|
| 4 |
+
workspace/*
|
| 5 |
+
!workspace/README.md
|
agent/agent.py
CHANGED
|
@@ -4,6 +4,7 @@ from colorama import Fore, Style # type: ignore[import]
|
|
| 4 |
from langchain.agents import create_agent
|
| 5 |
from langchain_core.messages import HumanMessage
|
| 6 |
from agent.tools.math_solver import math_solver
|
|
|
|
| 7 |
|
| 8 |
from agent.agents.websearchagents import web_search_agents
|
| 9 |
|
|
@@ -18,7 +19,7 @@ def supervisor_agent():
|
|
| 18 |
return create_agent(
|
| 19 |
model="google_genai:gemini-3-flash-preview",
|
| 20 |
# tools=[math_solver, websearch_agent, web_search_agents],
|
| 21 |
-
tools=[math_solver, web_search_agents],
|
| 22 |
system_prompt=(
|
| 23 |
f"You are a supervisor agent. "
|
| 24 |
f"Current time is: {datetime.now(timezone.utc).isoformat()}. "
|
|
@@ -34,18 +35,23 @@ def supervisor_agent():
|
|
| 34 |
)
|
| 35 |
|
| 36 |
|
| 37 |
-
def run(query: str, max_retries: int = 3) -> str:
|
| 38 |
"""Entry point: let the supervisor agent finish the work."""
|
| 39 |
last_error: str | None = None
|
| 40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
for attempt in range(1, max_retries + 1):
|
| 42 |
print(
|
| 43 |
f"{Fore.CYAN}[Supervisor] Processing query (attempt {attempt}/{max_retries})...\n"
|
| 44 |
-
f"[Supervisor] Query: {
|
| 45 |
)
|
| 46 |
agent = supervisor_agent()
|
| 47 |
|
| 48 |
-
messages = [HumanMessage(content=
|
| 49 |
if last_error:
|
| 50 |
messages.append(
|
| 51 |
HumanMessage(
|
|
|
|
| 4 |
from langchain.agents import create_agent
|
| 5 |
from langchain_core.messages import HumanMessage
|
| 6 |
from agent.tools.math_solver import math_solver
|
| 7 |
+
from agent.tools.file_downloader import file_downloader
|
| 8 |
|
| 9 |
from agent.agents.websearchagents import web_search_agents
|
| 10 |
|
|
|
|
| 19 |
return create_agent(
|
| 20 |
model="google_genai:gemini-3-flash-preview",
|
| 21 |
# tools=[math_solver, websearch_agent, web_search_agents],
|
| 22 |
+
tools=[math_solver, web_search_agents, file_downloader],
|
| 23 |
system_prompt=(
|
| 24 |
f"You are a supervisor agent. "
|
| 25 |
f"Current time is: {datetime.now(timezone.utc).isoformat()}. "
|
|
|
|
| 35 |
)
|
| 36 |
|
| 37 |
|
| 38 |
+
def run(query: str, file_url: str | None = None, max_retries: int = 3) -> str:
|
| 39 |
"""Entry point: let the supervisor agent finish the work."""
|
| 40 |
last_error: str | None = None
|
| 41 |
|
| 42 |
+
# Append file URL info to the query if available
|
| 43 |
+
full_query = query
|
| 44 |
+
if file_url:
|
| 45 |
+
full_query += f"\n\nAttached file URL: {file_url}"
|
| 46 |
+
|
| 47 |
for attempt in range(1, max_retries + 1):
|
| 48 |
print(
|
| 49 |
f"{Fore.CYAN}[Supervisor] Processing query (attempt {attempt}/{max_retries})...\n"
|
| 50 |
+
f"[Supervisor] Query: {full_query}{Style.RESET_ALL}"
|
| 51 |
)
|
| 52 |
agent = supervisor_agent()
|
| 53 |
|
| 54 |
+
messages = [HumanMessage(content=full_query)]
|
| 55 |
if last_error:
|
| 56 |
messages.append(
|
| 57 |
HumanMessage(
|
agent/tools/file_downloader.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
|
| 4 |
+
import httpx
|
| 5 |
+
from colorama import Fore, Style # type: ignore[import]
|
| 6 |
+
from langchain_core.tools import tool
|
| 7 |
+
|
| 8 |
+
WORKSPACE_DIR = Path(__file__).resolve().parents[2] / "workspace"
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@tool
|
| 12 |
+
def file_downloader(url: str) -> str:
|
| 13 |
+
"""Download a file from a URL and save it to the workspace directory.
|
| 14 |
+
|
| 15 |
+
Args:
|
| 16 |
+
url: The URL of the file to download.
|
| 17 |
+
|
| 18 |
+
Returns:
|
| 19 |
+
The local file path of the downloaded file, or an error message.
|
| 20 |
+
"""
|
| 21 |
+
try:
|
| 22 |
+
filename = url.rstrip("/").split("/")[-1].split("?")[0] or "downloaded_file"
|
| 23 |
+
dest = WORKSPACE_DIR / filename
|
| 24 |
+
|
| 25 |
+
with httpx.stream("GET", url, follow_redirects=True, timeout=60) as r:
|
| 26 |
+
r.raise_for_status()
|
| 27 |
+
with open(dest, "wb") as f:
|
| 28 |
+
for chunk in r.iter_bytes():
|
| 29 |
+
f.write(chunk)
|
| 30 |
+
|
| 31 |
+
print(f"{Fore.GREEN}[FileDownloader] Saved: {dest}{Style.RESET_ALL}")
|
| 32 |
+
return str(dest)
|
| 33 |
+
except Exception as e:
|
| 34 |
+
return f"Error downloading file: {e}"
|
app.py
CHANGED
|
@@ -16,9 +16,11 @@ class BasicAgent:
|
|
| 16 |
def __init__(self):
|
| 17 |
print("BasicAgent initialized.")
|
| 18 |
|
| 19 |
-
def __call__(self, question: str) -> str:
|
| 20 |
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
| 21 |
-
|
|
|
|
|
|
|
| 22 |
print(f"Agent returning answer (first 50 chars): {answer[:50]}...")
|
| 23 |
return answer
|
| 24 |
|
|
@@ -83,8 +85,9 @@ def run_and_submit_all(profile: gr.OAuthProfile | None):
|
|
| 83 |
if not task_id or question_text is None:
|
| 84 |
print(f"Skipping item with missing task_id or question: {item}")
|
| 85 |
continue
|
|
|
|
| 86 |
try:
|
| 87 |
-
submitted_answer = agent(question_text)
|
| 88 |
answers_payload.append(
|
| 89 |
{"task_id": task_id, "submitted_answer": submitted_answer}
|
| 90 |
)
|
|
|
|
| 16 |
def __init__(self):
|
| 17 |
print("BasicAgent initialized.")
|
| 18 |
|
| 19 |
+
def __call__(self, question: str, file_url: str | None = None) -> str:
|
| 20 |
print(f"Agent received question (first 50 chars): {question[:50]}...")
|
| 21 |
+
if file_url:
|
| 22 |
+
print(f"Agent received file URL: {file_url}")
|
| 23 |
+
answer = agent_run(question, file_url=file_url)
|
| 24 |
print(f"Agent returning answer (first 50 chars): {answer[:50]}...")
|
| 25 |
return answer
|
| 26 |
|
|
|
|
| 85 |
if not task_id or question_text is None:
|
| 86 |
print(f"Skipping item with missing task_id or question: {item}")
|
| 87 |
continue
|
| 88 |
+
file_url = f"{api_url}/files/{task_id}"
|
| 89 |
try:
|
| 90 |
+
submitted_answer = agent(question_text, file_url=file_url)
|
| 91 |
answers_payload.append(
|
| 92 |
{"task_id": task_id, "submitted_answer": submitted_answer}
|
| 93 |
)
|
workspace/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
Workspace directory for downloaded files.
|