Spaces:
Sleeping
Sleeping
""" | |
agent.py – central coordinator for smolagents-powered agent. | |
This file exposes a single helper function `my_agent()` that returns an | |
object which is **callable** (i.e. implements `__call__(question:str) -> str`) | |
so that `app.py` can stay unchanged apart from a single import. | |
* Adding new tools | |
------------------ | |
1. Drop the tool file inside the ``/tools`` package. | |
2. Import the tool class in `my_agent` and append it to the ``tools`` list. | |
The rest of the application will automatically pick it up. | |
""" | |
from typing import List, Sequence | |
try: | |
from smolagents import Agent, Tool # type: ignore | |
except ImportError as exc: # pragma: no cover | |
raise ImportError( | |
"smolagents must be in requirements.txt. " | |
"Add `smolagents` to your dependencies." | |
) from exc | |
# Available tools | |
from tools.web_search import DuckDuckGoSearchTool # noqa: E402 | |
class SmolAgentWrapper: | |
""" | |
Thin wrapper that makes a smolagents.Agent *callable*. | |
The evaluation harness in app.py expects an object that can be called | |
directly with a single question and that returns a string. The underlying | |
smolagents agent is session-aware and can handle multi-turn conversations | |
but we keep the public interface single-turn for now. | |
""" | |
def __init__(self, tools: Sequence["Tool"] | None = None) -> None: # type: ignore[name-defined] | |
if tools is None: | |
tools = [DuckDuckGoSearchTool()] | |
self._agent = Agent(tools=list(tools)) | |
# Allow the object itself to be called like a function | |
def __call__(self, question: str) -> str: # noqa: D401 (simple summary ok) | |
""" | |
Ask the underlying smolagents Agent a **single** question and return the answer. | |
Any exception is caught and surfaced as a readable string in order not | |
to crash the evaluation loop. | |
""" | |
try: | |
response = self._agent.run(question) | |
# smolagents may return dicts or ToolOutput objects; normalise to str | |
if isinstance(response, str): | |
return response | |
return str(response) | |
except Exception as err: # pragma: no cover | |
return f"ERROR: {type(err).__name__}: {err}" | |
# --------------------------------------------------------------------------- # | |
# Helper – this is what app.py will import | |
# --------------------------------------------------------------------------- # | |
def my_agent(extra_tools: Sequence["Tool"] | None = None) -> SmolAgentWrapper: # type: ignore[name-defined] | |
""" | |
Factory that returns a ready-to-go agent. | |
Parameters | |
---------- | |
extra_tools: | |
Optional sequence of additional smolagents Tool objects to extend the | |
agent's capabilities. They are appended **after** the default search | |
tool so they can override it if they expose the same name. | |
Returns | |
------- | |
SmolAgentWrapper | |
A callable object compatible with the original BasicAgent. | |
""" | |
tools: List["Tool"] = [DuckDuckGoSearchTool()] | |
if extra_tools: | |
tools.extend(extra_tools) | |
return SmolAgentWrapper(tools=tools) | |
__all__ = ["my_agent", "SmolAgentWrapper"] | |