zrb 1.16.4__py3-none-any.whl → 1.17.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zrb/builtin/__init__.py +1 -0
- zrb/builtin/group.py +5 -1
- zrb/builtin/llm/llm_ask.py +7 -10
- zrb/builtin/llm/tool/api.py +85 -71
- zrb/builtin/llm/tool/note.py +3 -0
- zrb/builtin/llm/tool/web.py +31 -87
- zrb/builtin/searxng/config/settings.yml +5671 -0
- zrb/builtin/searxng/start.py +21 -0
- zrb/config/config.py +28 -8
- zrb/config/llm_config.py +100 -4
- zrb/group/any_group.py +1 -1
- zrb/task/llm/agent.py +1 -16
- zrb/task/llm/config.py +12 -3
- zrb/task/llm_task.py +30 -10
- {zrb-1.16.4.dist-info → zrb-1.17.0.dist-info}/METADATA +1 -2
- {zrb-1.16.4.dist-info → zrb-1.17.0.dist-info}/RECORD +18 -16
- {zrb-1.16.4.dist-info → zrb-1.17.0.dist-info}/WHEEL +0 -0
- {zrb-1.16.4.dist-info → zrb-1.17.0.dist-info}/entry_points.txt +0 -0
zrb/builtin/__init__.py
CHANGED
@@ -16,6 +16,7 @@ from zrb.builtin.project.add.fastapp.fastapp_task import add_fastapp_to_project
|
|
16
16
|
from zrb.builtin.project.create.project_task import create_project
|
17
17
|
from zrb.builtin.python import format_python_code
|
18
18
|
from zrb.builtin.random import shuffle_values, throw_dice
|
19
|
+
from zrb.builtin.searxng.start import start_searxng
|
19
20
|
from zrb.builtin.setup.asdf.asdf import setup_asdf
|
20
21
|
from zrb.builtin.setup.latex.ubuntu import setup_latex_on_ubuntu
|
21
22
|
from zrb.builtin.setup.tmux.tmux import setup_tmux
|
zrb/builtin/group.py
CHANGED
@@ -41,7 +41,7 @@ todo_group = _maybe_add_group(Group(name="todo", description="✅ Todo managemen
|
|
41
41
|
shell_group = _maybe_add_group(
|
42
42
|
Group(name="shell", description="💬 Shell related commands")
|
43
43
|
)
|
44
|
-
shell_autocomplete_group
|
44
|
+
shell_autocomplete_group = shell_group.add_group(
|
45
45
|
Group(name="autocomplete", description="⌨️ Shell autocomplete related commands")
|
46
46
|
)
|
47
47
|
|
@@ -59,3 +59,7 @@ setup_group = _maybe_add_group(Group(name="setup", description="🔧 Setup"))
|
|
59
59
|
setup_latex_group = setup_group.add_group(
|
60
60
|
Group(name="latex", description="✍️ Setup LaTeX")
|
61
61
|
)
|
62
|
+
|
63
|
+
searxng_group = _maybe_add_group(
|
64
|
+
Group(name="searxng", description="🔎 Searxng related command")
|
65
|
+
)
|
zrb/builtin/llm/llm_ask.py
CHANGED
@@ -6,7 +6,10 @@ from zrb.builtin.group import llm_group
|
|
6
6
|
from zrb.builtin.llm.chat_session import get_llm_ask_input_mapping, read_user_prompt
|
7
7
|
from zrb.builtin.llm.history import read_chat_conversation, write_chat_conversation
|
8
8
|
from zrb.builtin.llm.input import PreviousSessionInput
|
9
|
-
from zrb.builtin.llm.tool.api import
|
9
|
+
from zrb.builtin.llm.tool.api import (
|
10
|
+
create_get_current_location,
|
11
|
+
create_get_current_weather,
|
12
|
+
)
|
10
13
|
from zrb.builtin.llm.tool.cli import run_shell_command
|
11
14
|
from zrb.builtin.llm.tool.code import analyze_repo
|
12
15
|
from zrb.builtin.llm.tool.file import (
|
@@ -28,8 +31,6 @@ from zrb.builtin.llm.tool.note import (
|
|
28
31
|
from zrb.builtin.llm.tool.web import (
|
29
32
|
create_search_internet_tool,
|
30
33
|
open_web_page,
|
31
|
-
search_arxiv,
|
32
|
-
search_wikipedia,
|
33
34
|
)
|
34
35
|
from zrb.callback.callback import Callback
|
35
36
|
from zrb.config.config import CFG
|
@@ -85,16 +86,12 @@ def _get_tool(ctx: AnyContext) -> list["ToolOrCallable"]:
|
|
85
86
|
tools.append(run_shell_command)
|
86
87
|
if CFG.LLM_ALLOW_OPEN_WEB_PAGE:
|
87
88
|
tools.append(open_web_page)
|
88
|
-
if CFG.LLM_ALLOW_SEARCH_WIKIPEDIA:
|
89
|
-
tools.append(search_wikipedia)
|
90
|
-
if CFG.LLM_ALLOW_SEARCH_ARXIV:
|
91
|
-
tools.append(search_arxiv)
|
92
89
|
if CFG.LLM_ALLOW_GET_CURRENT_LOCATION:
|
93
|
-
tools.append(
|
90
|
+
tools.append(create_get_current_location())
|
94
91
|
if CFG.LLM_ALLOW_GET_CURRENT_WEATHER:
|
95
|
-
tools.append(
|
92
|
+
tools.append(create_get_current_weather())
|
96
93
|
if CFG.SERPAPI_KEY != "" and CFG.LLM_ALLOW_SEARCH_INTERNET:
|
97
|
-
tools.append(create_search_internet_tool(
|
94
|
+
tools.append(create_search_internet_tool())
|
98
95
|
return tools
|
99
96
|
|
100
97
|
|
zrb/builtin/llm/tool/api.py
CHANGED
@@ -1,71 +1,85 @@
|
|
1
|
-
from typing import Any, Literal
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
latitude
|
44
|
-
longitude
|
45
|
-
temperature_unit
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
1
|
+
from typing import Any, Callable, Literal
|
2
|
+
|
3
|
+
from zrb.config.llm_config import llm_config
|
4
|
+
|
5
|
+
|
6
|
+
def create_get_current_location() -> Callable:
|
7
|
+
if llm_config.default_current_location_tool is not None:
|
8
|
+
return llm_config.default_current_location_tool
|
9
|
+
|
10
|
+
def get_current_location() -> dict[str, float]:
|
11
|
+
"""
|
12
|
+
Fetches the user's current geographical location based on their IP address.
|
13
|
+
|
14
|
+
Use this tool when the user asks "Where am I?", "What is my current
|
15
|
+
location?", or has a query that requires knowing their location to be
|
16
|
+
answered.
|
17
|
+
|
18
|
+
Returns:
|
19
|
+
dict[str, float]: A dictionary containing the 'lat' and 'lon' of the current
|
20
|
+
location.
|
21
|
+
Example: {"lat": 48.8584, "lon": 2.2945}
|
22
|
+
Raises:
|
23
|
+
requests.RequestException: If the API request to the location service
|
24
|
+
fails.
|
25
|
+
"""
|
26
|
+
import requests
|
27
|
+
|
28
|
+
try:
|
29
|
+
response = requests.get("http://ip-api.com/json?fields=lat,lon", timeout=5)
|
30
|
+
response.raise_for_status()
|
31
|
+
return dict(response.json())
|
32
|
+
except requests.RequestException as e:
|
33
|
+
raise requests.RequestException(f"Failed to get location: {e}")
|
34
|
+
|
35
|
+
return get_current_location
|
36
|
+
|
37
|
+
|
38
|
+
def create_get_current_weather() -> Callable:
|
39
|
+
if llm_config.default_current_weather_tool is not None:
|
40
|
+
return llm_config.default_current_weather_tool
|
41
|
+
|
42
|
+
def get_current_weather(
|
43
|
+
latitude: float,
|
44
|
+
longitude: float,
|
45
|
+
temperature_unit: Literal["celsius", "fahrenheit"],
|
46
|
+
) -> dict[str, Any]:
|
47
|
+
"""
|
48
|
+
Retrieves the current weather conditions for a given geographical location.
|
49
|
+
|
50
|
+
Use this tool when the user asks about the weather. If the user does not
|
51
|
+
provide a location, first use the `get_current_location` tool to
|
52
|
+
determine their location.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
latitude (float): The latitude of the location.
|
56
|
+
longitude (float): The longitude of the location.
|
57
|
+
temperature_unit (Literal["celsius", "fahrenheit"]): The desired unit
|
58
|
+
for the temperature reading.
|
59
|
+
|
60
|
+
Returns:
|
61
|
+
dict[str, Any]: A dictionary containing detailed weather data, including
|
62
|
+
temperature, wind speed, and weather code.
|
63
|
+
Raises:
|
64
|
+
requests.RequestException: If the API request to the weather service
|
65
|
+
fails.
|
66
|
+
"""
|
67
|
+
import requests
|
68
|
+
|
69
|
+
try:
|
70
|
+
response = requests.get(
|
71
|
+
"https://api.open-meteo.com/v1/forecast",
|
72
|
+
params={
|
73
|
+
"latitude": latitude,
|
74
|
+
"longitude": longitude,
|
75
|
+
"temperature_unit": temperature_unit,
|
76
|
+
"current_weather": True,
|
77
|
+
},
|
78
|
+
timeout=5,
|
79
|
+
)
|
80
|
+
response.raise_for_status()
|
81
|
+
return dict(response.json())
|
82
|
+
except requests.RequestException as e:
|
83
|
+
raise requests.RequestException(f"Failed to get weather data: {e}")
|
84
|
+
|
85
|
+
return get_current_weather
|
zrb/builtin/llm/tool/note.py
CHANGED
@@ -20,6 +20,7 @@ def write_long_term_note(content: str) -> str:
|
|
20
20
|
Writes content to the global long-term note.
|
21
21
|
The content of this note is intended to be read by the AI Agent in the future.
|
22
22
|
It should contain global information/preference.
|
23
|
+
Use this tool proactively when you find information worth noted.
|
23
24
|
|
24
25
|
Args:
|
25
26
|
content: The content to write to the long-term note (overwriting the existing one).
|
@@ -58,6 +59,8 @@ def write_contextual_note(content: str, path: str | None = None) -> str:
|
|
58
59
|
|
59
60
|
If no path is provided, it defaults to the current working directory.
|
60
61
|
|
62
|
+
Use this tool proactively when you find information worth noted.
|
63
|
+
|
61
64
|
Args:
|
62
65
|
content: The new content of the note (overwriting the existing one).
|
63
66
|
path: The file or directory path to associate the note with.
|
zrb/builtin/llm/tool/web.py
CHANGED
@@ -2,6 +2,9 @@ from collections.abc import Callable
|
|
2
2
|
from typing import Any
|
3
3
|
from urllib.parse import urljoin
|
4
4
|
|
5
|
+
from zrb.config.config import CFG
|
6
|
+
from zrb.config.llm_config import llm_config
|
7
|
+
|
5
8
|
_DEFAULT_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36" # noqa
|
6
9
|
|
7
10
|
|
@@ -28,26 +31,11 @@ async def open_web_page(url: str) -> dict[str, Any]:
|
|
28
31
|
return {"content": markdown_content, "links_on_page": links}
|
29
32
|
|
30
33
|
|
31
|
-
def create_search_internet_tool(
|
32
|
-
|
33
|
-
|
34
|
-
"""
|
35
|
-
Creates a tool that searches the internet using the SerpAPI Google Search
|
36
|
-
API.
|
37
|
-
|
38
|
-
This factory returns a function that can be used to find information on the
|
39
|
-
web. The generated tool is the primary way to answer general knowledge
|
40
|
-
questions or to find information on topics you are unfamiliar with.
|
41
|
-
|
42
|
-
Args:
|
43
|
-
serp_api_key (str): The API key for SerpAPI.
|
44
|
-
|
45
|
-
Returns:
|
46
|
-
Callable: A function that takes a search query and returns a list of
|
47
|
-
search results.
|
48
|
-
"""
|
34
|
+
def create_search_internet_tool() -> Callable:
|
35
|
+
if llm_config.default_search_internet_tool is not None:
|
36
|
+
return llm_config.default_search_internet_tool
|
49
37
|
|
50
|
-
def search_internet(query: str,
|
38
|
+
def search_internet(query: str, page: int = 1) -> dict[str, Any]:
|
51
39
|
"""
|
52
40
|
Performs an internet search using Google and returns a summary of the results.
|
53
41
|
|
@@ -56,7 +44,7 @@ def create_search_internet_tool(
|
|
56
44
|
|
57
45
|
Args:
|
58
46
|
query (str): The search query.
|
59
|
-
|
47
|
+
Page (int, optional): The search page number, default to 1.
|
60
48
|
|
61
49
|
Returns:
|
62
50
|
dict[str, Any]: A formatted string summarizing the search results,
|
@@ -64,17 +52,29 @@ def create_search_internet_tool(
|
|
64
52
|
"""
|
65
53
|
import requests
|
66
54
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
55
|
+
if CFG.SEARCH_INTERNET_METHOD.strip() == "serpapi" and CFG.SERPAPI_KEY != "":
|
56
|
+
response = requests.get(
|
57
|
+
"https://serpapi.com/search",
|
58
|
+
headers={"User-Agent": _DEFAULT_USER_AGENT},
|
59
|
+
params={
|
60
|
+
"q": query,
|
61
|
+
"start": (page - 1) * 10,
|
62
|
+
"hl": "en",
|
63
|
+
"safe": "off",
|
64
|
+
"api_key": CFG.SERPAPI_KEY,
|
65
|
+
},
|
66
|
+
)
|
67
|
+
else:
|
68
|
+
response = requests.get(
|
69
|
+
url=f"{CFG.SEARXNG_BASE_URL}/search",
|
70
|
+
headers={"User-Agent": _DEFAULT_USER_AGENT},
|
71
|
+
params={
|
72
|
+
"q": query,
|
73
|
+
"format": "json",
|
74
|
+
"pageno": page,
|
75
|
+
"safesearch": 0,
|
76
|
+
},
|
77
|
+
)
|
78
78
|
if response.status_code != 200:
|
79
79
|
raise Exception(
|
80
80
|
f"Error: Unable to retrieve search results (status code: {response.status_code})" # noqa
|
@@ -84,62 +84,6 @@ def create_search_internet_tool(
|
|
84
84
|
return search_internet
|
85
85
|
|
86
86
|
|
87
|
-
def search_wikipedia(query: str) -> dict[str, Any]:
|
88
|
-
"""
|
89
|
-
Searches for articles on Wikipedia.
|
90
|
-
|
91
|
-
This is a specialized search tool for querying Wikipedia. It's best for
|
92
|
-
when the user is asking for definitions, historical information, or
|
93
|
-
biographical details that are likely to be found on an encyclopedia.
|
94
|
-
|
95
|
-
Args:
|
96
|
-
query (str): The search term or question.
|
97
|
-
|
98
|
-
Returns:
|
99
|
-
dict[str, Any]: The raw JSON response from the Wikipedia API, containing a list of
|
100
|
-
search results.
|
101
|
-
"""
|
102
|
-
import requests
|
103
|
-
|
104
|
-
params = {"action": "query", "list": "search", "srsearch": query, "format": "json"}
|
105
|
-
response = requests.get(
|
106
|
-
"https://en.wikipedia.org/w/api.php",
|
107
|
-
headers={"User-Agent": _DEFAULT_USER_AGENT},
|
108
|
-
params=params,
|
109
|
-
)
|
110
|
-
return response.json()
|
111
|
-
|
112
|
-
|
113
|
-
def search_arxiv(query: str, num_results: int = 10) -> dict[str, Any]:
|
114
|
-
"""
|
115
|
-
Searches for academic papers and preprints on ArXiv.
|
116
|
-
|
117
|
-
Use this tool when the user's query is scientific or technical in nature
|
118
|
-
and they are likely looking for research papers, articles, or academic
|
119
|
-
publications.
|
120
|
-
|
121
|
-
Args:
|
122
|
-
query (str): The search query, which can include keywords, author
|
123
|
-
names, or titles.
|
124
|
-
num_results (int, optional): The maximum number of results to return.
|
125
|
-
Defaults to 10.
|
126
|
-
|
127
|
-
Returns:
|
128
|
-
dict[str, Any]: The raw XML response from the ArXiv API, containing a list of
|
129
|
-
matching papers.
|
130
|
-
"""
|
131
|
-
import requests
|
132
|
-
import xmltodict
|
133
|
-
|
134
|
-
params = {"search_query": f"all:{query}", "start": 0, "max_results": num_results}
|
135
|
-
response = requests.get(
|
136
|
-
"http://export.arxiv.org/api/query",
|
137
|
-
headers={"User-Agent": _DEFAULT_USER_AGENT},
|
138
|
-
params=params,
|
139
|
-
)
|
140
|
-
return xmltodict.parse(response.content)
|
141
|
-
|
142
|
-
|
143
87
|
async def _fetch_page_content(url: str) -> tuple[str, list[str]]:
|
144
88
|
"""Fetches the HTML content and all absolute links from a URL."""
|
145
89
|
try:
|