Update tools.py
Browse files
tools.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
-
from typing import List
|
2 |
from duckduckgo_search import DDGS # pip install -U duckduckgo-search
|
3 |
import re
|
|
|
4 |
|
5 |
# -------- helper to shorten very long GAIA questions (optional but helpful)
|
6 |
def tighten(q: str) -> str:
|
@@ -9,14 +10,10 @@ def tighten(q: str) -> str:
|
|
9 |
short = " ".join(quoted + caps)
|
10 |
return short or q
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
"""
|
17 |
-
query = tighten(query) # optional heuristic cleaner
|
18 |
-
with DDGS() as ddgs: # context-manager is the recommended way 🐤
|
19 |
-
raw = list(ddgs.text(keywords=query, max_results=max_results)) # DDGS.text() returns list of dicts
|
20 |
out = []
|
21 |
for r in raw:
|
22 |
try:
|
@@ -26,3 +23,62 @@ def simple_search(query: str, max_results: int = 5) -> List[str]:
|
|
26 |
except Exception:
|
27 |
pass
|
28 |
return out
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from typing import List, Callable
|
2 |
from duckduckgo_search import DDGS # pip install -U duckduckgo-search
|
3 |
import re
|
4 |
+
import time
|
5 |
|
6 |
# -------- helper to shorten very long GAIA questions (optional but helpful)
|
7 |
def tighten(q: str) -> str:
|
|
|
10 |
short = " ".join(quoted + caps)
|
11 |
return short or q
|
12 |
|
13 |
+
def _raw_search(query: str, max_results: int = 5) -> List[str]:
|
14 |
+
"""Internal function that performs the actual DuckDuckGo search."""
|
15 |
+
with DDGS() as ddgs:
|
16 |
+
raw = list(ddgs.text(keywords=query, max_results=max_results))
|
|
|
|
|
|
|
|
|
17 |
out = []
|
18 |
for r in raw:
|
19 |
try:
|
|
|
23 |
except Exception:
|
24 |
pass
|
25 |
return out
|
26 |
+
|
27 |
+
def retry_ddg(
|
28 |
+
query: str,
|
29 |
+
max_results: int = 5,
|
30 |
+
attempts: int = 4,
|
31 |
+
delay_sec: int = 10,
|
32 |
+
search_fn: Callable[[str, int], List[str]] = _raw_search,
|
33 |
+
) -> List[str]:
|
34 |
+
"""
|
35 |
+
Retry DuckDuckGo search up to *attempts* times, waiting *delay_sec* seconds
|
36 |
+
between attempts if no results were returned or an exception was raised.
|
37 |
+
|
38 |
+
Parameters
|
39 |
+
----------
|
40 |
+
query : str
|
41 |
+
Search query.
|
42 |
+
max_results : int, default 5
|
43 |
+
Number of results to return.
|
44 |
+
attempts : int, default 4
|
45 |
+
Maximum number of attempts before giving up.
|
46 |
+
delay_sec : int, default 10
|
47 |
+
Seconds to sleep between attempts.
|
48 |
+
search_fn : Callable
|
49 |
+
A function with signature (query: str, max_results: int) -> List[str].
|
50 |
+
Defaults to _raw_search.
|
51 |
+
|
52 |
+
Returns
|
53 |
+
-------
|
54 |
+
List[str]
|
55 |
+
List of result strings; may be empty if every attempt failed.
|
56 |
+
"""
|
57 |
+
last_err = None
|
58 |
+
for i in range(1, attempts + 1):
|
59 |
+
try:
|
60 |
+
results = search_fn(query, max_results)
|
61 |
+
if results: # Success
|
62 |
+
return results
|
63 |
+
print(f"Attempt {i}/{attempts}: no results, retrying in {delay_sec}s…")
|
64 |
+
except Exception as e:
|
65 |
+
last_err = e # Keep last error for optional logging
|
66 |
+
print(f"Attempt {i}/{attempts} failed: {e}. Retrying in {delay_sec}s…")
|
67 |
+
|
68 |
+
if i < attempts:
|
69 |
+
time.sleep(delay_sec)
|
70 |
+
|
71 |
+
# All attempts failed or returned empty
|
72 |
+
if last_err:
|
73 |
+
print(f"All {attempts} attempts failed. Last exception: {last_err}")
|
74 |
+
else:
|
75 |
+
print(f"All {attempts} attempts returned empty results.")
|
76 |
+
return []
|
77 |
+
|
78 |
+
# -------- the only search function your agent will call
|
79 |
+
def simple_search(query: str, max_results: int = 5) -> List[str]:
|
80 |
+
"""
|
81 |
+
Perform a DuckDuckGo search and return 'title – url' snippets.
|
82 |
+
"""
|
83 |
+
query = tighten(query) # optional heuristic cleaner
|
84 |
+
return retry_ddg(query, max_results) # retry on failure
|