Tesvia commited on
Commit
3f46b6e
·
verified ·
1 Parent(s): 25ee16d

Upload 8 files

Browse files
Files changed (4) hide show
  1. .gitignore +29 -0
  2. agent.py +88 -88
  3. config.py +7 -7
  4. exceptions.py +11 -11
.gitignore ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Virtual Environments
7
+ venv/
8
+ .venv/
9
+
10
+ # Environment variables file
11
+ .env
12
+
13
+ # Logs and debug
14
+ *.log
15
+ logs/
16
+
17
+ # OS-specific files
18
+ .DS_Store
19
+ Thumbs.db
20
+
21
+ # Machine specific devcontainer file
22
+ .devcontainer/devcontainer.local.json
23
+
24
+ # Firebase Studio addition
25
+ .vscode/
26
+
27
+ # Cache
28
+ cache/
29
+ .cache/
agent.py CHANGED
@@ -1,88 +1,88 @@
1
- """
2
- agent.py – central coordinator for smolagents-powered agent.
3
-
4
- This file exposes a single helper function `my_agent()` that returns an
5
- object which is **callable** (i.e. implements `__call__(question:str) -> str`)
6
- so that `app.py` can stay unchanged apart from a single import.
7
-
8
- * Adding new tools
9
- ------------------
10
- 1. Drop the tool file inside the ``/tools`` package.
11
- 2. Import the tool class in `my_agent` and append it to the ``tools`` list.
12
- The rest of the application will automatically pick it up.
13
- """
14
-
15
- from typing import List, Sequence
16
-
17
- try:
18
- from smolagents import Agent, Tool # type: ignore
19
- except ImportError as exc: # pragma: no cover
20
- raise ImportError(
21
- "smolagents must be in requirements.txt. "
22
- "Add `smolagents` to your dependencies."
23
- ) from exc
24
-
25
- # Available tools
26
- from tools.web_search import DuckDuckGoSearchTool # noqa: E402
27
-
28
-
29
- class SmolAgentWrapper:
30
- """
31
- Thin wrapper that makes a smolagents.Agent *callable*.
32
-
33
- The evaluation harness in app.py expects an object that can be called
34
- directly with a single question and that returns a string. The underlying
35
- smolagents agent is session-aware and can handle multi-turn conversations
36
- but we keep the public interface single-turn for now.
37
- """
38
-
39
- def __init__(self, tools: Sequence["Tool"] | None = None) -> None: # type: ignore[name-defined]
40
- if tools is None:
41
- tools = [DuckDuckGoSearchTool()]
42
- self._agent = Agent(tools=list(tools))
43
-
44
- # Allow the object itself to be called like a function
45
- def __call__(self, question: str) -> str: # noqa: D401 (simple summary ok)
46
- """
47
- Ask the underlying smolagents Agent a **single** question and return the answer.
48
-
49
- Any exception is caught and surfaced as a readable string in order not
50
- to crash the evaluation loop.
51
- """
52
- try:
53
- response = self._agent.run(question)
54
- # smolagents may return dicts or ToolOutput objects; normalise to str
55
- if isinstance(response, str):
56
- return response
57
- return str(response)
58
- except Exception as err: # pragma: no cover
59
- return f"ERROR: {type(err).__name__}: {err}"
60
-
61
-
62
- # --------------------------------------------------------------------------- #
63
- # Helper – this is what app.py will import
64
- # --------------------------------------------------------------------------- #
65
-
66
- def my_agent(extra_tools: Sequence["Tool"] | None = None) -> SmolAgentWrapper: # type: ignore[name-defined]
67
- """
68
- Factory that returns a ready-to-go agent.
69
-
70
- Parameters
71
- ----------
72
- extra_tools:
73
- Optional sequence of additional smolagents Tool objects to extend the
74
- agent's capabilities. They are appended **after** the default search
75
- tool so they can override it if they expose the same name.
76
-
77
- Returns
78
- -------
79
- SmolAgentWrapper
80
- A callable object compatible with the original BasicAgent.
81
- """
82
- tools: List["Tool"] = [DuckDuckGoSearchTool()]
83
- if extra_tools:
84
- tools.extend(extra_tools)
85
- return SmolAgentWrapper(tools=tools)
86
-
87
-
88
- __all__ = ["my_agent", "SmolAgentWrapper"]
 
1
+ """
2
+ agent.py – central coordinator for smolagents-powered agent.
3
+
4
+ This file exposes a single helper function `my_agent()` that returns an
5
+ object which is **callable** (i.e. implements `__call__(question:str) -> str`)
6
+ so that `app.py` can stay unchanged apart from a single import.
7
+
8
+ * Adding new tools
9
+ ------------------
10
+ 1. Drop the tool file inside the ``/tools`` package.
11
+ 2. Import the tool class in `my_agent` and append it to the ``tools`` list.
12
+ The rest of the application will automatically pick it up.
13
+ """
14
+
15
+ from typing import List, Sequence
16
+
17
+ try:
18
+ from smolagents import Agent, Tool # type: ignore
19
+ except ImportError as exc: # pragma: no cover
20
+ raise ImportError(
21
+ "smolagents must be in requirements.txt. "
22
+ "Add `smolagents` to your dependencies."
23
+ ) from exc
24
+
25
+ # Available tools
26
+ from tools.web_search import DuckDuckGoSearchTool # noqa: E402
27
+
28
+
29
+ class SmolAgentWrapper:
30
+ """
31
+ Thin wrapper that makes a smolagents.Agent *callable*.
32
+
33
+ The evaluation harness in app.py expects an object that can be called
34
+ directly with a single question and that returns a string. The underlying
35
+ smolagents agent is session-aware and can handle multi-turn conversations
36
+ but we keep the public interface single-turn for now.
37
+ """
38
+
39
+ def __init__(self, tools: Sequence["Tool"] | None = None) -> None: # type: ignore[name-defined]
40
+ if tools is None:
41
+ tools = [DuckDuckGoSearchTool()]
42
+ self._agent = Agent(tools=list(tools))
43
+
44
+ # Allow the object itself to be called like a function
45
+ def __call__(self, question: str) -> str: # noqa: D401 (simple summary ok)
46
+ """
47
+ Ask the underlying smolagents Agent a **single** question and return the answer.
48
+
49
+ Any exception is caught and surfaced as a readable string in order not
50
+ to crash the evaluation loop.
51
+ """
52
+ try:
53
+ response = self._agent.run(question)
54
+ # smolagents may return dicts or ToolOutput objects; normalise to str
55
+ if isinstance(response, str):
56
+ return response
57
+ return str(response)
58
+ except Exception as err: # pragma: no cover
59
+ return f"ERROR: {type(err).__name__}: {err}"
60
+
61
+
62
+ # --------------------------------------------------------------------------- #
63
+ # Helper – this is what app.py will import
64
+ # --------------------------------------------------------------------------- #
65
+
66
+ def my_agent(extra_tools: Sequence["Tool"] | None = None) -> SmolAgentWrapper: # type: ignore[name-defined]
67
+ """
68
+ Factory that returns a ready-to-go agent.
69
+
70
+ Parameters
71
+ ----------
72
+ extra_tools:
73
+ Optional sequence of additional smolagents Tool objects to extend the
74
+ agent's capabilities. They are appended **after** the default search
75
+ tool so they can override it if they expose the same name.
76
+
77
+ Returns
78
+ -------
79
+ SmolAgentWrapper
80
+ A callable object compatible with the original BasicAgent.
81
+ """
82
+ tools: List["Tool"] = [DuckDuckGoSearchTool()]
83
+ if extra_tools:
84
+ tools.extend(extra_tools)
85
+ return SmolAgentWrapper(tools=tools)
86
+
87
+
88
+ __all__ = ["my_agent", "SmolAgentWrapper"]
config.py CHANGED
@@ -1,7 +1,7 @@
1
- # DuckDuckGo-specific settings
2
- DUCKDUCKGO_MAX_RESULTS = 10
3
- DUCKDUCKGO_TIMEOUT = 15 # seconds
4
- SEARCH_DEFAULT_ENGINE = 'duckduckgo' # Make it easy to add others
5
-
6
- # Logging
7
- LOG_LEVEL = "INFO"
 
1
+ # DuckDuckGo-specific settings
2
+ DUCKDUCKGO_MAX_RESULTS = 10
3
+ DUCKDUCKGO_TIMEOUT = 15 # seconds
4
+ SEARCH_DEFAULT_ENGINE = 'duckduckgo' # Make it easy to add others
5
+
6
+ # Logging
7
+ LOG_LEVEL = "INFO"
exceptions.py CHANGED
@@ -1,11 +1,11 @@
1
- class SearchError(Exception):
2
- """Base exception for search errors."""
3
- pass
4
-
5
- class NoResultsFound(SearchError):
6
- """Raised when no search results are returned."""
7
- pass
8
-
9
- class SearchEngineUnavailable(SearchError):
10
- """Raised when the search engine is down or unreachable."""
11
- pass
 
1
+ class SearchError(Exception):
2
+ """Base exception for search errors."""
3
+ pass
4
+
5
+ class NoResultsFound(SearchError):
6
+ """Raised when no search results are returned."""
7
+ pass
8
+
9
+ class SearchEngineUnavailable(SearchError):
10
+ """Raised when the search engine is down or unreachable."""
11
+ pass