Spaces:
Sleeping
Add CodeAgent subagent with Qwen coder model + expose compute tool
Browse filesNew architecture at manager level (4 subagents):
BasicAgent
├── web_research -> WebResearchAgent
├── file_analysis -> FileAnalysisAgent
├── media_analysis -> MediaAgent
├── compute -> CodeAgent (NEW)
└── AnswerNormalizer
CodeAgent wraps python_exec + calculator behind a specialist that
writes Python, runs it, and iterates on errors. Uses Qwen 2.5 Coder
32B by default via GROQ_CODE_MODEL env var (override to
openai/gpt-oss-120b or deepseek-r1-distill-llama-70b if Groq drops
the Qwen model).
tools.py: python_exec + calculator no longer in ALL_TOOLS; wrapped
by compute() which delegates to CodeAgent.
app.py: manager system prompt updated to describe 4 specialists.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ryPUj8AtsFopnufGRSc4L
|
@@ -13,6 +13,16 @@ def _make_llm(model: str = "openai/gpt-oss-120b", temperature: float = 0.1) -> C
|
|
| 13 |
)
|
| 14 |
|
| 15 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
WEB_RESEARCH_PROMPT = """You are a web research specialist.
|
| 17 |
|
| 18 |
For each question:
|
|
@@ -45,6 +55,22 @@ Workflow:
|
|
| 45 |
verbatim when possible. Do not speculate."""
|
| 46 |
|
| 47 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
MEDIA_ANALYSIS_PROMPT = """You are a media analysis specialist (image, audio, video).
|
| 49 |
|
| 50 |
You handle questions that reference a task_id, URL, or file path pointing to
|
|
@@ -144,6 +170,21 @@ class MediaAgent:
|
|
| 144 |
return result["messages"][-1].content
|
| 145 |
|
| 146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 147 |
class AnswerNormalizer:
|
| 148 |
def __init__(self):
|
| 149 |
self.llm = _make_llm(temperature=0.0)
|
|
|
|
| 13 |
)
|
| 14 |
|
| 15 |
|
| 16 |
+
def _make_code_llm() -> ChatGroq:
|
| 17 |
+
"""LLM for CodeAgent. Defaults to Qwen 2.5 Coder 32B on Groq.
|
| 18 |
+
|
| 19 |
+
Override with GROQ_CODE_MODEL env var if Groq drops it (e.g. set to
|
| 20 |
+
``openai/gpt-oss-120b`` or ``deepseek-r1-distill-llama-70b``).
|
| 21 |
+
"""
|
| 22 |
+
model = os.getenv("GROQ_CODE_MODEL", "qwen-2.5-coder-32b")
|
| 23 |
+
return _make_llm(model=model, temperature=0.1)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
WEB_RESEARCH_PROMPT = """You are a web research specialist.
|
| 27 |
|
| 28 |
For each question:
|
|
|
|
| 55 |
verbatim when possible. Do not speculate."""
|
| 56 |
|
| 57 |
|
| 58 |
+
CODE_AGENT_PROMPT = """You are a Python computation specialist.
|
| 59 |
+
|
| 60 |
+
You answer questions that need arithmetic, list/string manipulation, date math,
|
| 61 |
+
pandas transforms, unit conversions, or any calculation better *computed* than
|
| 62 |
+
reasoned about.
|
| 63 |
+
|
| 64 |
+
Workflow:
|
| 65 |
+
1. Prefer `calculator` for a single closed-form math expression.
|
| 66 |
+
2. Otherwise write a short Python snippet and run it via `python_exec`.
|
| 67 |
+
You MUST `print()` any value you want to see back — the tool returns stdout.
|
| 68 |
+
3. If `python_exec` returns an error, read the traceback, fix the code, and
|
| 69 |
+
retry. Do not give up after one failure; iterate up to 3 times.
|
| 70 |
+
4. Return ONLY the final computed value. No code in the final answer, no
|
| 71 |
+
explanation, no units unless asked."""
|
| 72 |
+
|
| 73 |
+
|
| 74 |
MEDIA_ANALYSIS_PROMPT = """You are a media analysis specialist (image, audio, video).
|
| 75 |
|
| 76 |
You handle questions that reference a task_id, URL, or file path pointing to
|
|
|
|
| 170 |
return result["messages"][-1].content
|
| 171 |
|
| 172 |
|
| 173 |
+
class CodeAgent:
|
| 174 |
+
def __init__(self):
|
| 175 |
+
from tools import calculator, python_exec # lazy: avoids circular import
|
| 176 |
+
|
| 177 |
+
self.graph = create_agent(
|
| 178 |
+
_make_code_llm(),
|
| 179 |
+
tools=[python_exec, calculator],
|
| 180 |
+
system_prompt=CODE_AGENT_PROMPT,
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
def __call__(self, question: str) -> str:
|
| 184 |
+
result = self.graph.invoke({"messages": [("user", question)]})
|
| 185 |
+
return result["messages"][-1].content
|
| 186 |
+
|
| 187 |
+
|
| 188 |
class AnswerNormalizer:
|
| 189 |
def __init__(self):
|
| 190 |
self.llm = _make_llm(temperature=0.0)
|
|
@@ -17,22 +17,22 @@ from langgraph.prebuilt import ToolNode
|
|
| 17 |
|
| 18 |
MANAGER_SYSTEM_PROMPT = """You are a QA agent for the GAIA benchmark.
|
| 19 |
|
| 20 |
-
You have
|
| 21 |
-
- web_research(question): factual/current world knowledge (people, dates,
|
|
|
|
| 22 |
- file_analysis(question): question about an attached document
|
| 23 |
-
(pdf/xlsx/csv/txt/json). Include the task_id or URL in your question.
|
| 24 |
- media_analysis(question): question about an image, audio, or video (also
|
| 25 |
YouTube URLs). Include the task_id or URL in your question.
|
| 26 |
-
-
|
| 27 |
-
|
| 28 |
-
- calculator(expression): plain math expressions.
|
| 29 |
|
| 30 |
Rules:
|
| 31 |
1. When a task has an attached file (mentioned by task_id), route to
|
| 32 |
file_analysis or media_analysis with the task_id embedded in the question.
|
| 33 |
2. Ask each specialist ONE precise question at a time.
|
| 34 |
-
3. Chain tools when needed (e.g. web_research to find
|
| 35 |
-
|
| 36 |
4. Final answer: give ONLY the value the question asks for. No preamble,
|
| 37 |
no explanation."""
|
| 38 |
|
|
|
|
| 17 |
|
| 18 |
MANAGER_SYSTEM_PROMPT = """You are a QA agent for the GAIA benchmark.
|
| 19 |
|
| 20 |
+
You have four specialist tools:
|
| 21 |
+
- web_research(question): factual / current world knowledge (people, dates,
|
| 22 |
+
events, statistics).
|
| 23 |
- file_analysis(question): question about an attached document
|
| 24 |
+
(pdf / xlsx / csv / txt / json). Include the task_id or URL in your question.
|
| 25 |
- media_analysis(question): question about an image, audio, or video (also
|
| 26 |
YouTube URLs). Include the task_id or URL in your question.
|
| 27 |
+
- compute(question): math, arithmetic, list ops, date math, string parsing,
|
| 28 |
+
unit conversions. State the computation in plain language with the inputs.
|
|
|
|
| 29 |
|
| 30 |
Rules:
|
| 31 |
1. When a task has an attached file (mentioned by task_id), route to
|
| 32 |
file_analysis or media_analysis with the task_id embedded in the question.
|
| 33 |
2. Ask each specialist ONE precise question at a time.
|
| 34 |
+
3. Chain tools when needed (e.g. web_research to find numbers, then
|
| 35 |
+
compute to combine them).
|
| 36 |
4. Final answer: give ONLY the value the question asks for. No preamble,
|
| 37 |
no explanation."""
|
| 38 |
|
|
@@ -13,7 +13,7 @@ from langchain_core.tools import tool
|
|
| 13 |
from langchain_groq import ChatGroq
|
| 14 |
from tavily import TavilyClient
|
| 15 |
|
| 16 |
-
from agents import FileAnalysisAgent, MediaAgent, WebResearchAgent
|
| 17 |
|
| 18 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 19 |
|
|
@@ -381,6 +381,7 @@ def youtube_transcript(url_or_id: str) -> str:
|
|
| 381 |
_web_agent = WebResearchAgent()
|
| 382 |
_file_agent = FileAnalysisAgent()
|
| 383 |
_media_agent = MediaAgent()
|
|
|
|
| 384 |
|
| 385 |
|
| 386 |
@tool
|
|
@@ -431,10 +432,24 @@ def media_analysis(question: str) -> str:
|
|
| 431 |
return _media_agent(question)
|
| 432 |
|
| 433 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 434 |
ALL_TOOLS = [
|
| 435 |
web_research,
|
| 436 |
file_analysis,
|
| 437 |
media_analysis,
|
| 438 |
-
|
| 439 |
-
calculator,
|
| 440 |
]
|
|
|
|
| 13 |
from langchain_groq import ChatGroq
|
| 14 |
from tavily import TavilyClient
|
| 15 |
|
| 16 |
+
from agents import CodeAgent, FileAnalysisAgent, MediaAgent, WebResearchAgent
|
| 17 |
|
| 18 |
DEFAULT_API_URL = "https://agents-course-unit4-scoring.hf.space"
|
| 19 |
|
|
|
|
| 381 |
_web_agent = WebResearchAgent()
|
| 382 |
_file_agent = FileAnalysisAgent()
|
| 383 |
_media_agent = MediaAgent()
|
| 384 |
+
_code_agent = CodeAgent()
|
| 385 |
|
| 386 |
|
| 387 |
@tool
|
|
|
|
| 432 |
return _media_agent(question)
|
| 433 |
|
| 434 |
|
| 435 |
+
@tool
|
| 436 |
+
def compute(question: str) -> str:
|
| 437 |
+
"""Delegate math, arithmetic, data manipulation, or string parsing to a code specialist.
|
| 438 |
+
|
| 439 |
+
The specialist writes Python, runs it, iterates on errors, and returns the
|
| 440 |
+
computed value. Use for anything better *computed* than reasoned about:
|
| 441 |
+
sums / averages / dates / list ops / unit conversions / regex extraction.
|
| 442 |
+
|
| 443 |
+
Args:
|
| 444 |
+
question: What to compute, plainly stated. Include any input data or
|
| 445 |
+
values needed to perform the computation.
|
| 446 |
+
"""
|
| 447 |
+
return _code_agent(question)
|
| 448 |
+
|
| 449 |
+
|
| 450 |
ALL_TOOLS = [
|
| 451 |
web_research,
|
| 452 |
file_analysis,
|
| 453 |
media_analysis,
|
| 454 |
+
compute,
|
|
|
|
| 455 |
]
|