zrb 1.15.24__py3-none-any.whl → 1.15.26__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/__init__.py +2 -6
- zrb/builtin/group.py +26 -14
- zrb/builtin/llm/llm_ask.py +42 -40
- zrb/context/any_shared_context.py +7 -1
- zrb/context/shared_context.py +2 -2
- zrb/runner/web_util/user.py +7 -3
- zrb/session/any_session.py +12 -6
- zrb/session/session.py +39 -18
- zrb/task/any_task.py +8 -0
- zrb/task/base_trigger.py +11 -4
- zrb/task/llm/agent.py +41 -3
- zrb/task/scheduler.py +3 -3
- {zrb-1.15.24.dist-info → zrb-1.15.26.dist-info}/METADATA +1 -1
- {zrb-1.15.24.dist-info → zrb-1.15.26.dist-info}/RECORD +16 -16
- {zrb-1.15.24.dist-info → zrb-1.15.26.dist-info}/WHEEL +0 -0
- {zrb-1.15.24.dist-info → zrb-1.15.26.dist-info}/entry_points.txt +0 -0
zrb/__init__.py
CHANGED
@@ -61,6 +61,7 @@ _LAZY_LOAD = {
|
|
61
61
|
}
|
62
62
|
|
63
63
|
if TYPE_CHECKING:
|
64
|
+
from zrb import builtin
|
64
65
|
from zrb.attr.type import (
|
65
66
|
AnyAttr,
|
66
67
|
BoolAttr,
|
@@ -126,9 +127,4 @@ def __getattr__(name: str) -> Any:
|
|
126
127
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
127
128
|
|
128
129
|
|
129
|
-
|
130
|
-
CFG = __getattr__("CFG")
|
131
|
-
if CFG.LOAD_BUILTIN:
|
132
|
-
from zrb import builtin
|
133
|
-
|
134
|
-
assert builtin
|
130
|
+
from zrb import builtin
|
zrb/builtin/group.py
CHANGED
@@ -1,39 +1,51 @@
|
|
1
|
+
from zrb.config.config import CFG
|
1
2
|
from zrb.group.group import Group
|
2
3
|
from zrb.runner.cli import cli
|
3
4
|
|
4
|
-
|
5
|
-
|
5
|
+
|
6
|
+
def _maybe_add_group(group: Group):
|
7
|
+
if CFG.LOAD_BUILTIN:
|
8
|
+
cli.add_group(group)
|
9
|
+
return group
|
10
|
+
|
11
|
+
|
12
|
+
base64_group = _maybe_add_group(
|
13
|
+
Group(name="base64", description="📄 Base64 operations")
|
14
|
+
)
|
15
|
+
uuid_group = _maybe_add_group(Group(name="uuid", description="🆔 UUID operations"))
|
6
16
|
uuid_v1_group = uuid_group.add_group(Group(name="v1", description="UUID V1 operations"))
|
7
17
|
uuid_v3_group = uuid_group.add_group(Group(name="v3", description="UUID V3 operations"))
|
8
18
|
uuid_v4_group = uuid_group.add_group(Group(name="v4", description="UUID V4 operations"))
|
9
19
|
uuid_v5_group = uuid_group.add_group(Group(name="v5", description="UUID V5 operations"))
|
10
|
-
ulid_group =
|
11
|
-
jwt_group =
|
12
|
-
http_group =
|
20
|
+
ulid_group = _maybe_add_group(Group(name="ulid", description="🔢 ULID operations"))
|
21
|
+
jwt_group = _maybe_add_group(Group(name="jwt", description="🔒 JWT encode/decode"))
|
22
|
+
http_group = _maybe_add_group(
|
23
|
+
Group(name="http", description="🌐 HTTP request operations")
|
24
|
+
)
|
13
25
|
|
14
|
-
random_group =
|
15
|
-
git_group =
|
26
|
+
random_group = _maybe_add_group(Group(name="random", description="🔀 Random operation"))
|
27
|
+
git_group = _maybe_add_group(Group(name="git", description="🌱 Git related commands"))
|
16
28
|
git_branch_group = git_group.add_group(
|
17
29
|
Group(name="branch", description="🌿 Git branch related commands")
|
18
30
|
)
|
19
31
|
git_subtree_group = git_group.add_group(
|
20
32
|
Group(name="subtree", description="🌳 Git subtree related commands")
|
21
33
|
)
|
22
|
-
llm_group =
|
23
|
-
md5_group =
|
24
|
-
python_group =
|
34
|
+
llm_group = _maybe_add_group(Group(name="llm", description="🤖 LLM operations"))
|
35
|
+
md5_group = _maybe_add_group(Group(name="md5", description="🔢 Md5 operations"))
|
36
|
+
python_group = _maybe_add_group(
|
25
37
|
Group(name="python", description="🐍 Python related commands")
|
26
38
|
)
|
27
|
-
todo_group =
|
39
|
+
todo_group = _maybe_add_group(Group(name="todo", description="✅ Todo management"))
|
28
40
|
|
29
|
-
shell_group =
|
41
|
+
shell_group = _maybe_add_group(
|
30
42
|
Group(name="shell", description="💬 Shell related commands")
|
31
43
|
)
|
32
44
|
shell_autocomplete_group: Group = shell_group.add_group(
|
33
45
|
Group(name="autocomplete", description="⌨️ Shell autocomplete related commands")
|
34
46
|
)
|
35
47
|
|
36
|
-
project_group =
|
48
|
+
project_group = _maybe_add_group(
|
37
49
|
Group(name="project", description="📁 Project related commands")
|
38
50
|
)
|
39
51
|
add_to_project_group = project_group.add_group(
|
@@ -43,7 +55,7 @@ add_fastapp_to_project_group = add_to_project_group.add_group(
|
|
43
55
|
Group(name="fastapp", description="🚀 Add Fastapp resources")
|
44
56
|
)
|
45
57
|
|
46
|
-
setup_group =
|
58
|
+
setup_group = _maybe_add_group(Group(name="setup", description="🔧 Setup"))
|
47
59
|
setup_latex_group = setup_group.add_group(
|
48
60
|
Group(name="latex", description="✍️ Setup LaTeX")
|
49
61
|
)
|
zrb/builtin/llm/llm_ask.py
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
from collections.abc import Callable
|
2
|
+
from typing import TYPE_CHECKING
|
3
|
+
|
1
4
|
from zrb.builtin.group import llm_group
|
2
5
|
from zrb.builtin.llm.chat_session import get_llm_ask_input_mapping, read_user_prompt
|
3
6
|
from zrb.builtin.llm.history import read_chat_conversation, write_chat_conversation
|
@@ -32,6 +35,42 @@ from zrb.task.base_trigger import BaseTrigger
|
|
32
35
|
from zrb.task.llm_task import LLMTask
|
33
36
|
from zrb.util.string.conversion import to_boolean
|
34
37
|
|
38
|
+
if TYPE_CHECKING:
|
39
|
+
from pydantic_ai import Tool
|
40
|
+
|
41
|
+
ToolOrCallable = Tool | Callable
|
42
|
+
|
43
|
+
|
44
|
+
def _get_tool(ctx: AnyContext) -> list["ToolOrCallable"]:
|
45
|
+
tools = []
|
46
|
+
if CFG.LLM_ALLOW_ANALYZE_REPO:
|
47
|
+
tools.append(analyze_repo)
|
48
|
+
if CFG.LLM_ALLOW_ANALYZE_FILE:
|
49
|
+
tools.append(analyze_file)
|
50
|
+
if CFG.LLM_ALLOW_ACCESS_LOCAL_FILE:
|
51
|
+
tools.append(search_files)
|
52
|
+
tools.append(list_files)
|
53
|
+
tools.append(read_from_file)
|
54
|
+
tools.append(read_many_files)
|
55
|
+
tools.append(replace_in_file)
|
56
|
+
tools.append(write_to_file)
|
57
|
+
tools.append(write_many_files)
|
58
|
+
if CFG.LLM_ALLOW_ACCESS_SHELL:
|
59
|
+
tools.append(run_shell_command)
|
60
|
+
if CFG.LLM_ALLOW_OPEN_WEB_PAGE:
|
61
|
+
tools.append(open_web_page)
|
62
|
+
if CFG.LLM_ALLOW_SEARCH_WIKIPEDIA:
|
63
|
+
tools.append(search_wikipedia)
|
64
|
+
if CFG.LLM_ALLOW_SEARCH_ARXIV:
|
65
|
+
tools.append(search_arxiv)
|
66
|
+
if CFG.LLM_ALLOW_GET_CURRENT_LOCATION:
|
67
|
+
tools.append(get_current_location)
|
68
|
+
if CFG.LLM_ALLOW_GET_CURRENT_WEATHER:
|
69
|
+
tools.append(get_current_weather)
|
70
|
+
if CFG.SERPAPI_KEY != "" and CFG.LLM_ALLOW_SEARCH_INTERNET:
|
71
|
+
tools.append(create_search_internet_tool(CFG.SERPAPI_KEY))
|
72
|
+
return tools
|
73
|
+
|
35
74
|
|
36
75
|
def _get_default_yolo_mode(ctx: AnyContext) -> str:
|
37
76
|
default_value = llm_config.default_yolo_mode
|
@@ -92,7 +131,7 @@ _llm_ask_inputs = [
|
|
92
131
|
"modes",
|
93
132
|
description="Modes",
|
94
133
|
prompt="Modes",
|
95
|
-
default="
|
134
|
+
default=lambda ctx: ",".join(llm_config.default_modes),
|
96
135
|
allow_positional_parsing=False,
|
97
136
|
always_prompt=False,
|
98
137
|
),
|
@@ -123,7 +162,7 @@ _llm_ask_inputs = [
|
|
123
162
|
),
|
124
163
|
]
|
125
164
|
|
126
|
-
llm_ask
|
165
|
+
llm_ask = llm_group.add_task(
|
127
166
|
LLMTask(
|
128
167
|
name="llm-ask",
|
129
168
|
input=_llm_ask_inputs,
|
@@ -144,6 +183,7 @@ llm_ask: LLMTask = llm_group.add_task(
|
|
144
183
|
None if ctx.input.modes.strip() == "" else ctx.input.modes.split(",")
|
145
184
|
),
|
146
185
|
message="{ctx.input.message}",
|
186
|
+
tools=_get_tool,
|
147
187
|
yolo_mode=_render_yolo_mode_input,
|
148
188
|
retries=0,
|
149
189
|
),
|
@@ -169,41 +209,3 @@ llm_group.add_task(
|
|
169
209
|
),
|
170
210
|
alias="chat",
|
171
211
|
)
|
172
|
-
|
173
|
-
if CFG.LLM_ALLOW_ANALYZE_REPO:
|
174
|
-
llm_ask.append_tool(analyze_repo)
|
175
|
-
|
176
|
-
if CFG.LLM_ALLOW_ANALYZE_FILE:
|
177
|
-
llm_ask.append_tool(analyze_file)
|
178
|
-
|
179
|
-
if CFG.LLM_ALLOW_ACCESS_LOCAL_FILE:
|
180
|
-
llm_ask.append_tool(
|
181
|
-
search_files,
|
182
|
-
list_files,
|
183
|
-
read_from_file,
|
184
|
-
read_many_files,
|
185
|
-
replace_in_file,
|
186
|
-
write_to_file,
|
187
|
-
write_many_files,
|
188
|
-
)
|
189
|
-
|
190
|
-
if CFG.LLM_ALLOW_ACCESS_SHELL:
|
191
|
-
llm_ask.append_tool(run_shell_command)
|
192
|
-
|
193
|
-
if CFG.LLM_ALLOW_OPEN_WEB_PAGE:
|
194
|
-
llm_ask.append_tool(open_web_page)
|
195
|
-
|
196
|
-
if CFG.LLM_ALLOW_SEARCH_WIKIPEDIA:
|
197
|
-
llm_ask.append_tool(search_wikipedia)
|
198
|
-
|
199
|
-
if CFG.LLM_ALLOW_SEARCH_ARXIV:
|
200
|
-
llm_ask.append_tool(search_arxiv)
|
201
|
-
|
202
|
-
if CFG.LLM_ALLOW_GET_CURRENT_LOCATION:
|
203
|
-
llm_ask.append_tool(get_current_location)
|
204
|
-
|
205
|
-
if CFG.LLM_ALLOW_GET_CURRENT_WEATHER:
|
206
|
-
llm_ask.append_tool(get_current_weather)
|
207
|
-
|
208
|
-
if CFG.SERPAPI_KEY != "" and CFG.LLM_ALLOW_SEARCH_INTERNET:
|
209
|
-
llm_ask.append_tool(create_search_internet_tool(CFG.SERPAPI_KEY))
|
@@ -29,26 +29,32 @@ class AnySharedContext(ABC):
|
|
29
29
|
pass
|
30
30
|
|
31
31
|
@property
|
32
|
+
@abstractmethod
|
32
33
|
def input(self) -> DotDict:
|
33
34
|
pass
|
34
35
|
|
35
36
|
@property
|
37
|
+
@abstractmethod
|
36
38
|
def env(self) -> DotDict:
|
37
39
|
pass
|
38
40
|
|
39
41
|
@property
|
42
|
+
@abstractmethod
|
40
43
|
def args(self) -> list[Any]:
|
41
44
|
pass
|
42
45
|
|
43
46
|
@property
|
44
|
-
|
47
|
+
@abstractmethod
|
48
|
+
def xcom(self) -> DotDict:
|
45
49
|
pass
|
46
50
|
|
47
51
|
@property
|
52
|
+
@abstractmethod
|
48
53
|
def shared_log(self) -> list[str]:
|
49
54
|
pass
|
50
55
|
|
51
56
|
@property
|
57
|
+
@abstractmethod
|
52
58
|
def session(self) -> any_session.AnySession | None:
|
53
59
|
pass
|
54
60
|
|
zrb/context/shared_context.py
CHANGED
@@ -66,7 +66,7 @@ class SharedContext(AnySharedContext):
|
|
66
66
|
return self._args
|
67
67
|
|
68
68
|
@property
|
69
|
-
def xcom(self) -> DotDict
|
69
|
+
def xcom(self) -> DotDict:
|
70
70
|
return self._xcom
|
71
71
|
|
72
72
|
@property
|
@@ -81,7 +81,7 @@ class SharedContext(AnySharedContext):
|
|
81
81
|
self._log.append(message)
|
82
82
|
session = self.session
|
83
83
|
if session is not None:
|
84
|
-
session_parent: AnySession = session.parent
|
84
|
+
session_parent: AnySession | None = session.parent
|
85
85
|
if session_parent is not None:
|
86
86
|
session_parent.shared_ctx.append_to_shared_log(message)
|
87
87
|
|
zrb/runner/web_util/user.py
CHANGED
@@ -19,7 +19,7 @@ def get_user_by_credentials(
|
|
19
19
|
|
20
20
|
async def get_user_from_request(
|
21
21
|
web_auth_config: WebAuthConfig, request: "Request"
|
22
|
-
) -> User
|
22
|
+
) -> User:
|
23
23
|
from fastapi.security import OAuth2PasswordBearer
|
24
24
|
|
25
25
|
if not web_auth_config.enable_auth:
|
@@ -45,7 +45,11 @@ def _get_user_from_cookie(
|
|
45
45
|
return None
|
46
46
|
|
47
47
|
|
48
|
-
def _get_user_from_token(
|
48
|
+
def _get_user_from_token(
|
49
|
+
web_auth_config: WebAuthConfig, token: str | None
|
50
|
+
) -> User | None:
|
51
|
+
if token is None:
|
52
|
+
return None
|
49
53
|
try:
|
50
54
|
from jose import jwt
|
51
55
|
|
@@ -54,7 +58,7 @@ def _get_user_from_token(web_auth_config: WebAuthConfig, token: str) -> User | N
|
|
54
58
|
web_auth_config.secret_key,
|
55
59
|
options={"require_sub": True, "require_exp": True},
|
56
60
|
)
|
57
|
-
username: str = payload.get("sub")
|
61
|
+
username: str | None = payload.get("sub")
|
58
62
|
if username is None:
|
59
63
|
return None
|
60
64
|
user = web_auth_config.find_user_by_username(username)
|
zrb/session/any_session.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations # Enables forward references
|
2
2
|
|
3
|
+
import asyncio
|
3
4
|
from abc import ABC, abstractmethod
|
4
5
|
from typing import TYPE_CHECKING, Any, Coroutine, TypeVar
|
5
6
|
|
@@ -62,12 +63,13 @@ class AnySession(ABC):
|
|
62
63
|
|
63
64
|
@property
|
64
65
|
@abstractmethod
|
65
|
-
def parent(self) ->
|
66
|
+
def parent(self) -> "AnySession | None":
|
66
67
|
"""Parent session"""
|
67
68
|
pass
|
68
69
|
|
70
|
+
@property
|
69
71
|
@abstractmethod
|
70
|
-
def task_path(self) -> str:
|
72
|
+
def task_path(self) -> list[str]:
|
71
73
|
"""Main task's path"""
|
72
74
|
pass
|
73
75
|
|
@@ -105,7 +107,9 @@ class AnySession(ABC):
|
|
105
107
|
pass
|
106
108
|
|
107
109
|
@abstractmethod
|
108
|
-
def defer_monitoring(
|
110
|
+
def defer_monitoring(
|
111
|
+
self, task: "AnyTask", coro: Coroutine[Any, Any, Any] | asyncio.Task[Any]
|
112
|
+
):
|
109
113
|
"""Defers the execution of a task's monitoring coroutine for later processing.
|
110
114
|
|
111
115
|
Args:
|
@@ -115,7 +119,9 @@ class AnySession(ABC):
|
|
115
119
|
pass
|
116
120
|
|
117
121
|
@abstractmethod
|
118
|
-
def defer_action(
|
122
|
+
def defer_action(
|
123
|
+
self, task: "AnyTask", coro: Coroutine[Any, Any, Any] | asyncio.Task[Any]
|
124
|
+
):
|
119
125
|
"""Defers the execution of a task's coroutine for later processing.
|
120
126
|
|
121
127
|
Args:
|
@@ -125,7 +131,7 @@ class AnySession(ABC):
|
|
125
131
|
pass
|
126
132
|
|
127
133
|
@abstractmethod
|
128
|
-
def defer_coro(self, coro: Coroutine):
|
134
|
+
def defer_coro(self, coro: Coroutine[Any, Any, Any] | asyncio.Task[Any]):
|
129
135
|
"""Defers the execution of a coroutine for later processing.
|
130
136
|
|
131
137
|
Args:
|
@@ -185,7 +191,7 @@ class AnySession(ABC):
|
|
185
191
|
pass
|
186
192
|
|
187
193
|
@abstractmethod
|
188
|
-
def is_allowed_to_run(self, task: "AnyTask"):
|
194
|
+
def is_allowed_to_run(self, task: "AnyTask") -> bool:
|
189
195
|
"""Determines if the specified task is allowed to run based on its current state.
|
190
196
|
|
191
197
|
Args:
|
zrb/session/session.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import asyncio
|
2
4
|
from typing import TYPE_CHECKING, Any, Coroutine
|
3
5
|
|
4
6
|
from zrb.context.any_shared_context import AnySharedContext
|
5
7
|
from zrb.context.context import AnyContext, Context
|
6
8
|
from zrb.group.any_group import AnyGroup
|
7
|
-
from zrb.session.any_session import AnySession
|
9
|
+
from zrb.session.any_session import AnySession, TAnySession
|
8
10
|
from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
|
9
11
|
from zrb.session_state_logger.session_state_logger_factory import session_state_logger
|
10
12
|
from zrb.task.any_task import AnyTask
|
@@ -48,10 +50,10 @@ class Session(AnySession):
|
|
48
50
|
self._context: dict[AnyTask, Context] = {}
|
49
51
|
self._shared_ctx = shared_ctx
|
50
52
|
self._shared_ctx.set_session(self)
|
51
|
-
self._parent = parent
|
52
|
-
self._action_coros: dict[AnyTask, asyncio.Task] = {}
|
53
|
-
self._monitoring_coros: dict[AnyTask, asyncio.Task] = {}
|
54
|
-
self._coros: list[asyncio.Task] = []
|
53
|
+
self._parent: AnySession | None = parent
|
54
|
+
self._action_coros: dict[AnyTask, asyncio.Task[Any]] = {}
|
55
|
+
self._monitoring_coros: dict[AnyTask, asyncio.Task[Any]] = {}
|
56
|
+
self._coros: list[asyncio.Task[Any]] = []
|
55
57
|
self._colors = [
|
56
58
|
GREEN,
|
57
59
|
YELLOW,
|
@@ -114,11 +116,13 @@ class Session(AnySession):
|
|
114
116
|
return self._parent
|
115
117
|
|
116
118
|
@property
|
117
|
-
def task_path(self) -> str:
|
119
|
+
def task_path(self) -> list[str]:
|
118
120
|
return self._main_task_path
|
119
121
|
|
120
122
|
@property
|
121
123
|
def final_result(self) -> Any:
|
124
|
+
if self._main_task is None:
|
125
|
+
return None
|
122
126
|
xcom: Xcom = self.shared_ctx.xcom[self._main_task.name]
|
123
127
|
try:
|
124
128
|
return xcom.peek()
|
@@ -134,7 +138,11 @@ class Session(AnySession):
|
|
134
138
|
def set_main_task(self, main_task: AnyTask):
|
135
139
|
self.register_task(main_task)
|
136
140
|
self._main_task = main_task
|
137
|
-
main_task_path =
|
141
|
+
main_task_path = (
|
142
|
+
None
|
143
|
+
if self._root_group is None
|
144
|
+
else get_node_path(self._root_group, main_task)
|
145
|
+
)
|
138
146
|
self._main_task_path = [] if main_task_path is None else main_task_path
|
139
147
|
|
140
148
|
def as_state_log(self) -> "SessionStateLog":
|
@@ -171,7 +179,7 @@ class Session(AnySession):
|
|
171
179
|
return SessionStateLog(
|
172
180
|
name=self.name,
|
173
181
|
start_time=log_start_time,
|
174
|
-
main_task_name=self._main_task.name,
|
182
|
+
main_task_name="" if self._main_task is None else self._main_task.name,
|
175
183
|
path=self.task_path,
|
176
184
|
final_result=(
|
177
185
|
remove_style(f"{self.final_result}")
|
@@ -188,16 +196,29 @@ class Session(AnySession):
|
|
188
196
|
self._register_single_task(task)
|
189
197
|
return self._context[task]
|
190
198
|
|
191
|
-
def defer_monitoring(
|
199
|
+
def defer_monitoring(
|
200
|
+
self, task: AnyTask, coro: Coroutine[Any, Any, Any] | asyncio.Task[Any]
|
201
|
+
):
|
192
202
|
self._register_single_task(task)
|
193
|
-
|
203
|
+
if isinstance(coro, asyncio.Task):
|
204
|
+
self._monitoring_coros[task] = coro
|
205
|
+
else:
|
206
|
+
self._monitoring_coros[task] = asyncio.create_task(coro)
|
194
207
|
|
195
|
-
def defer_action(
|
208
|
+
def defer_action(
|
209
|
+
self, task: AnyTask, coro: Coroutine[Any, Any, Any] | asyncio.Task[Any]
|
210
|
+
):
|
196
211
|
self._register_single_task(task)
|
197
|
-
|
212
|
+
if isinstance(coro, asyncio.Task):
|
213
|
+
self._action_coros[task] = coro
|
214
|
+
else:
|
215
|
+
self._action_coros[task] = asyncio.create_task(coro)
|
198
216
|
|
199
|
-
def defer_coro(self, coro: Coroutine):
|
200
|
-
|
217
|
+
def defer_coro(self, coro: Coroutine[Any, Any, Any] | asyncio.Task[Any]):
|
218
|
+
if isinstance(coro, asyncio.Task):
|
219
|
+
self._coros.append(coro)
|
220
|
+
else:
|
221
|
+
self._coros.append(asyncio.create_task(coro))
|
201
222
|
self._coros = [
|
202
223
|
existing_coro for existing_coro in self._coros if not existing_coro.done()
|
203
224
|
]
|
@@ -246,15 +267,15 @@ class Session(AnySession):
|
|
246
267
|
|
247
268
|
def get_next_tasks(self, task: AnyTask) -> list[AnyTask]:
|
248
269
|
self._register_single_task(task)
|
249
|
-
return self._downstreams.get(task)
|
270
|
+
return self._downstreams.get(task, [])
|
250
271
|
|
251
272
|
def get_task_status(self, task: AnyTask) -> TaskStatus:
|
252
273
|
self._register_single_task(task)
|
253
274
|
return self._task_status[task]
|
254
275
|
|
255
276
|
def _register_single_task(self, task: AnyTask):
|
256
|
-
if task.name not in self._shared_ctx.
|
257
|
-
self._shared_ctx.
|
277
|
+
if task.name not in self._shared_ctx.xcom:
|
278
|
+
self._shared_ctx.xcom[task.name] = Xcom([])
|
258
279
|
if task not in self._context:
|
259
280
|
self._context[task] = Context(
|
260
281
|
shared_ctx=self._shared_ctx,
|
@@ -278,7 +299,7 @@ class Session(AnySession):
|
|
278
299
|
self._color_index = 0
|
279
300
|
return chosen
|
280
301
|
|
281
|
-
def _get_icon(self, task: AnyTask) ->
|
302
|
+
def _get_icon(self, task: AnyTask) -> str:
|
282
303
|
if task.icon is not None:
|
283
304
|
return task.icon
|
284
305
|
chosen = self._icons[self._icon_index]
|
zrb/task/any_task.py
CHANGED
@@ -36,6 +36,14 @@ class AnyTask(ABC):
|
|
36
36
|
the actual implementation for these abstract members.
|
37
37
|
"""
|
38
38
|
|
39
|
+
@abstractmethod
|
40
|
+
def __rshift__(self, other: "AnyTask | list[AnyTask]") -> "AnyTask | list[AnyTask]":
|
41
|
+
pass
|
42
|
+
|
43
|
+
@abstractmethod
|
44
|
+
def __lshift__(self, other: "AnyTask | list[AnyTask]") -> "AnyTask":
|
45
|
+
pass
|
46
|
+
|
39
47
|
@property
|
40
48
|
@abstractmethod
|
41
49
|
def name(self) -> str:
|
zrb/task/base_trigger.py
CHANGED
@@ -127,7 +127,7 @@ class BaseTrigger(BaseTask):
|
|
127
127
|
return self._callbacks
|
128
128
|
|
129
129
|
async def exec_root_tasks(self, session: AnySession):
|
130
|
-
exchange_xcom = self.
|
130
|
+
exchange_xcom = self._get_exchange_xcom(session)
|
131
131
|
exchange_xcom.add_push_callback(lambda: self._exchange_push_callback(session))
|
132
132
|
return await super().exec_root_tasks(session)
|
133
133
|
|
@@ -136,8 +136,7 @@ class BaseTrigger(BaseTask):
|
|
136
136
|
session.defer_coro(coro)
|
137
137
|
|
138
138
|
async def _fanout_and_trigger_callback(self, session: AnySession):
|
139
|
-
|
140
|
-
data = exchange_xcom.pop()
|
139
|
+
data = self.pop_exchange_xcom(session)
|
141
140
|
coros = []
|
142
141
|
for callback in self.callbacks:
|
143
142
|
xcom_dict = DotDict({self.queue_name: Xcom([data])})
|
@@ -156,8 +155,16 @@ class BaseTrigger(BaseTask):
|
|
156
155
|
)
|
157
156
|
await asyncio.gather(*coros)
|
158
157
|
|
159
|
-
def
|
158
|
+
def _get_exchange_xcom(self, session: AnySession) -> Xcom:
|
160
159
|
shared_ctx = session.shared_ctx
|
161
160
|
if self.queue_name not in shared_ctx.xcom:
|
162
161
|
shared_ctx.xcom[self.queue_name] = Xcom()
|
163
162
|
return shared_ctx.xcom[self.queue_name]
|
163
|
+
|
164
|
+
def push_exchange_xcom(self, session: AnySession, data: Any):
|
165
|
+
exchange_xcom = self._get_exchange_xcom(session)
|
166
|
+
exchange_xcom.push(data)
|
167
|
+
|
168
|
+
def pop_exchange_xcom(self, session: AnySession) -> Any:
|
169
|
+
exchange_xcom = self._get_exchange_xcom(session)
|
170
|
+
return exchange_xcom.pop()
|
zrb/task/llm/agent.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
import inspect
|
1
2
|
import json
|
2
3
|
from collections.abc import Callable
|
4
|
+
from dataclasses import dataclass
|
3
5
|
from typing import TYPE_CHECKING, Any
|
4
6
|
|
5
7
|
from zrb.config.llm_rate_limitter import LLMRateLimiter, llm_rate_limitter
|
@@ -30,13 +32,44 @@ def create_agent_instance(
|
|
30
32
|
system_prompt: str = "",
|
31
33
|
model_settings: "ModelSettings | None" = None,
|
32
34
|
tools: "list[ToolOrCallable]" = [],
|
33
|
-
toolsets: list["AbstractToolset[
|
35
|
+
toolsets: list["AbstractToolset[None]"] = [],
|
34
36
|
retries: int = 3,
|
35
37
|
yolo_mode: bool | list[str] | None = None,
|
36
38
|
) -> "Agent[None, Any]":
|
37
39
|
"""Creates a new Agent instance with configured tools and servers."""
|
38
|
-
from pydantic_ai import Agent, Tool
|
40
|
+
from pydantic_ai import Agent, RunContext, Tool
|
39
41
|
from pydantic_ai.tools import GenerateToolJsonSchema
|
42
|
+
from pydantic_ai.toolsets import ToolsetTool, WrapperToolset
|
43
|
+
|
44
|
+
@dataclass
|
45
|
+
class ConfirmationWrapperToolset(WrapperToolset):
|
46
|
+
ctx: AnyContext
|
47
|
+
yolo_mode: bool | list[str]
|
48
|
+
|
49
|
+
async def call_tool(
|
50
|
+
self, name: str, tool_args: dict, ctx: RunContext, tool: ToolsetTool[None]
|
51
|
+
) -> Any:
|
52
|
+
# The `tool` object is passed in. Use it for inspection.
|
53
|
+
# Define a temporary function that performs the actual tool call.
|
54
|
+
async def execute_delegated_tool_call(**params):
|
55
|
+
# Pass all arguments down the chain.
|
56
|
+
return await self.wrapped.call_tool(name, tool_args, ctx, tool)
|
57
|
+
|
58
|
+
# For the confirmation UI, make our temporary function look like the real one.
|
59
|
+
try:
|
60
|
+
execute_delegated_tool_call.__name__ = tool.function.__name__
|
61
|
+
execute_delegated_tool_call.__doc__ = tool.function.__doc__
|
62
|
+
execute_delegated_tool_call.__signature__ = inspect.signature(
|
63
|
+
tool.function
|
64
|
+
)
|
65
|
+
except (AttributeError, TypeError):
|
66
|
+
pass # Ignore if we can't inspect the original function
|
67
|
+
# Use the existing wrap_func to get the confirmation logic
|
68
|
+
wrapped_executor = wrap_func(
|
69
|
+
execute_delegated_tool_call, self.ctx, self.yolo_mode
|
70
|
+
)
|
71
|
+
# Call the wrapped executor. This will trigger the confirmation prompt.
|
72
|
+
return await wrapped_executor(**tool_args)
|
40
73
|
|
41
74
|
if yolo_mode is None:
|
42
75
|
yolo_mode = False
|
@@ -64,13 +97,18 @@ def create_agent_instance(
|
|
64
97
|
else:
|
65
98
|
# Turn function into tool
|
66
99
|
tool_list.append(wrap_tool(tool_or_callable, ctx, yolo_mode))
|
100
|
+
# Wrap toolsets
|
101
|
+
wrapped_toolsets = [
|
102
|
+
ConfirmationWrapperToolset(wrapped=toolset, ctx=ctx, yolo_mode=yolo_mode)
|
103
|
+
for toolset in toolsets
|
104
|
+
]
|
67
105
|
# Return Agent
|
68
106
|
return Agent[None, Any](
|
69
107
|
model=model,
|
70
108
|
output_type=output_type,
|
71
109
|
system_prompt=system_prompt,
|
72
110
|
tools=tool_list,
|
73
|
-
toolsets=
|
111
|
+
toolsets=wrapped_toolsets,
|
74
112
|
model_settings=model_settings,
|
75
113
|
retries=retries,
|
76
114
|
)
|
zrb/task/scheduler.py
CHANGED
@@ -24,7 +24,7 @@ class Scheduler(BaseTrigger):
|
|
24
24
|
cli_only: bool = False,
|
25
25
|
input: list[AnyInput | None] | AnyInput | None = None,
|
26
26
|
env: list[AnyEnv | None] | AnyEnv | None = None,
|
27
|
-
schedule: StrAttr = None,
|
27
|
+
schedule: StrAttr | None = None,
|
28
28
|
execute_condition: bool | str | Callable[[AnySharedContext], bool] = True,
|
29
29
|
queue_name: fstring | None = None,
|
30
30
|
callback: list[AnyCallback] | AnyCallback = [],
|
@@ -76,6 +76,6 @@ class Scheduler(BaseTrigger):
|
|
76
76
|
ctx.print(f"Current time: {now}")
|
77
77
|
if match_cron(cron_pattern, now):
|
78
78
|
ctx.print(f"Matching {now} with pattern: {cron_pattern}")
|
79
|
-
|
80
|
-
|
79
|
+
if ctx.session is not None:
|
80
|
+
self.push_exchange_xcom(ctx.session, now)
|
81
81
|
await asyncio.sleep(60)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
zrb/__init__.py,sha256=
|
1
|
+
zrb/__init__.py,sha256=qkCV2EnAGIgvsawBHYvKgPAp0zzPcikYSmbQXATLzg4,5060
|
2
2
|
zrb/__main__.py,sha256=9SXH9MK4PVyU9lkEyHxiIUABbcsV2wseP94HmlqTR4M,2657
|
3
3
|
zrb/attr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
zrb/attr/type.py,sha256=4TV5gPYMMrKh5V-yB6iRYKCbsXAH_AvGXMsjxKLHcUs,568
|
@@ -6,13 +6,13 @@ zrb/builtin/__init__.py,sha256=NjXpvBgAiPH-dNsJx5Fa-zSZE5JVnmVb1GhMNtevpGQ,1614
|
|
6
6
|
zrb/builtin/base64.py,sha256=UjaFttE2oRx0T7_RpKtKfgMtWfiQXfJBAJmA16ek8Ic,1507
|
7
7
|
zrb/builtin/git.py,sha256=8_qVE_2lVQEVXQ9vhiw8Tn4Prj1VZB78ZjEJJS5Ab3M,5461
|
8
8
|
zrb/builtin/git_subtree.py,sha256=7BKwOkVTWDrR0DXXQ4iJyHqeR6sV5VYRt8y_rEB0EHg,3505
|
9
|
-
zrb/builtin/group.py,sha256=
|
9
|
+
zrb/builtin/group.py,sha256=zYC5uw0VE97TXiLCr464kFJ-CJIJyeQ2RXjnVRY5ovs,2577
|
10
10
|
zrb/builtin/http.py,sha256=L6RE73c65wWwG5iHFN-tpOhyh56KsrgVskDd3c3YXtk,4246
|
11
11
|
zrb/builtin/jwt.py,sha256=3M5uaQhJZbKQLjTUft1OwPz_JxtmK-xtkjxWjciOQho,2859
|
12
12
|
zrb/builtin/llm/chat_session.py,sha256=p0giSVYuQMQ5H1hbQzl7cMb49XZqWG0SF7X-ixB5EBU,10203
|
13
13
|
zrb/builtin/llm/history.py,sha256=LDOrL0p7r_AHLa5L8Dp7bHNsOALugmJd7OguXRWGnm4,3087
|
14
14
|
zrb/builtin/llm/input.py,sha256=Nw-26uTWp2QhUgKJcP_IMHmtk-b542CCSQ_vCOjhvhM,877
|
15
|
-
zrb/builtin/llm/llm_ask.py,sha256=
|
15
|
+
zrb/builtin/llm/llm_ask.py,sha256=b3eS31NA55OUyeZN3O-sD971kz1LeX4QWzQQECpMaXo,6579
|
16
16
|
zrb/builtin/llm/previous-session.js,sha256=xMKZvJoAbrwiyHS0OoPrWuaKxWYLoyR5sguePIoCjTY,816
|
17
17
|
zrb/builtin/llm/tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
zrb/builtin/llm/tool/api.py,sha256=T8NGhBe59sQiu8LfdPOIBmsTNMXWFEKaPPSY9bolsQ8,2401
|
@@ -235,9 +235,9 @@ zrb/content_transformer/any_content_transformer.py,sha256=v8ZUbcix1GGeDQwB6OKX_1
|
|
235
235
|
zrb/content_transformer/content_transformer.py,sha256=STl77wW-I69QaGzCXjvkppngYFLufow8ybPLSyAvlHs,2404
|
236
236
|
zrb/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
237
237
|
zrb/context/any_context.py,sha256=2hgVKbbDwmwrEl1h1L1FaTUjuUYaDd_b7YRGkaorW6Q,6362
|
238
|
-
zrb/context/any_shared_context.py,sha256=
|
238
|
+
zrb/context/any_shared_context.py,sha256=PlB6mPOe98LRGUg9SCY1miy3ObcJDNhMWVNmE7zL9l0,2038
|
239
239
|
zrb/context/context.py,sha256=pnFV7KjVMKWAkYidhZTVFpPZvvGbqGuj_TERpWOvCIw,6883
|
240
|
-
zrb/context/shared_context.py,sha256=
|
240
|
+
zrb/context/shared_context.py,sha256=vtp181CJc5qm_M7ss2DBSsmw9QsVSI01yQUywQPsRH4,2968
|
241
241
|
zrb/dot_dict/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
242
242
|
zrb/dot_dict/dot_dict.py,sha256=ubw_x8I7AOJ59xxtFVJ00VGmq_IYdZP3mUhNlO4nEK0,556
|
243
243
|
zrb/env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -323,10 +323,10 @@ zrb/runner/web_schema/user.py,sha256=Kp10amg4i-f8Y-4czogv1YN7rwy0HdbePFiuovYu1ts
|
|
323
323
|
zrb/runner/web_util/cookie.py,sha256=O5vfZfeZOBL6ECvT7WqD4LihrsXO6okJLBUp6b7RMj0,1085
|
324
324
|
zrb/runner/web_util/html.py,sha256=TuUHjX3eKCBzoa7TYdMt8dfWWy06idauyCaG66X4Ygc,1838
|
325
325
|
zrb/runner/web_util/token.py,sha256=uaQXSZ6mptiph1a_LOMdYtPYdcyOk3ygz5ZoLGOPkhE,2687
|
326
|
-
zrb/runner/web_util/user.py,sha256=
|
326
|
+
zrb/runner/web_util/user.py,sha256=1m9apTJ5s_kCFv0B5GSc4-1P4Rjr4dH5oVNetS6Gz9Y,2116
|
327
327
|
zrb/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
328
|
-
zrb/session/any_session.py,sha256=
|
329
|
-
zrb/session/session.py,sha256=
|
328
|
+
zrb/session/any_session.py,sha256=zEc_9xbLUcqu4WG2NScvtDMtnb4vdUmjBaOm_MO_Cz4,5381
|
329
|
+
zrb/session/session.py,sha256=_Of9kX4khDB6csBvXcmVP3s2Mf9vKrIiT3fISwO4aTk,11118
|
330
330
|
zrb/session_state_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
331
331
|
zrb/session_state_log/session_state_log.py,sha256=VVghDMU72PbrvnzQ7MJuc-KTJ5P5fX0FYuCh3Rlwd9M,709
|
332
332
|
zrb/session_state_logger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -334,7 +334,7 @@ zrb/session_state_logger/any_session_state_logger.py,sha256=T_-aJv63HwoTeiDOmXKH
|
|
334
334
|
zrb/session_state_logger/file_session_state_logger.py,sha256=NMyj_g2ImQc6ZRM9f35EpA-CM1UO-ZgoDnPkN1DSi9U,3915
|
335
335
|
zrb/session_state_logger/session_state_logger_factory.py,sha256=_oT1UIqm25nMwKhsUvXehnCdDvNqxCyuN8GLdv2D_U4,188
|
336
336
|
zrb/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
337
|
-
zrb/task/any_task.py,sha256=
|
337
|
+
zrb/task/any_task.py,sha256=AXcBLnDWrJsiq_VihrXeNNMsQZuHzc5k6j-mS60qbyM,6443
|
338
338
|
zrb/task/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
339
339
|
zrb/task/base/context.py,sha256=ptz9-Am1s4yq6EHZUpnSrB0Ps3k7BgyakVbE-ZpiBzc,3923
|
340
340
|
zrb/task/base/execution.py,sha256=scDLfNYBe8Bc8Ct1LCIKmFtjpPxm7FjqZ2bJXIQAzv8,11042
|
@@ -342,11 +342,11 @@ zrb/task/base/lifecycle.py,sha256=c2v977pUm7S4EqrTMcUJKhnYOWugACVwU3qORDKiLXQ,76
|
|
342
342
|
zrb/task/base/monitoring.py,sha256=UAOEcPiYNtZR4FFxzWCosuOEFE_P3c4GT5vAhQmohqI,5663
|
343
343
|
zrb/task/base/operators.py,sha256=uAMFqpZJsPnCrojgOl1FUDXTS15mtOa_IqiAXltyYRU,1576
|
344
344
|
zrb/task/base_task.py,sha256=upwuqAfwNDXTYM-uRDJhgZqqqARI03T6ksUbFHHLEH0,13321
|
345
|
-
zrb/task/base_trigger.py,sha256=
|
345
|
+
zrb/task/base_trigger.py,sha256=HVasUkIZc8ZdAkJCbhXeO1QTY9vF7BvENoxKRV3R_eY,7171
|
346
346
|
zrb/task/cmd_task.py,sha256=myM8WZm6NrUD-Wv0Vb5sTOrutrAVZLt5LVsSBKwX6SM,10860
|
347
347
|
zrb/task/http_check.py,sha256=Gf5rOB2Se2EdizuN9rp65HpGmfZkGc-clIAlHmPVehs,2565
|
348
348
|
zrb/task/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
349
|
-
zrb/task/llm/agent.py,sha256=
|
349
|
+
zrb/task/llm/agent.py,sha256=UqQoxhPDg25jm5UwlC0mmPypfV56mXGNpk5hiZ75nbA,10949
|
350
350
|
zrb/task/llm/config.py,sha256=zOPf4NpdWPuBc_R8d-kljYcOKfUAypDxiSjRDrxV66M,4059
|
351
351
|
zrb/task/llm/conversation_history.py,sha256=oMdKUV2__mBZ4znnA-prl-gfyoleKC8Nj5KNpmLQJ4o,6764
|
352
352
|
zrb/task/llm/conversation_history_model.py,sha256=kk-7niTl29Rm2EUIhTHzPXgZ5tp4IThMnIB3dS-1OdU,3062
|
@@ -364,7 +364,7 @@ zrb/task/llm_task.py,sha256=OxJ9QpqjEyeOI1_zqzNZHtQlRHi0ANOvL9FYaWLzO3Y,14913
|
|
364
364
|
zrb/task/make_task.py,sha256=PD3b_aYazthS8LHeJsLAhwKDEgdurQZpymJDKeN60u0,2265
|
365
365
|
zrb/task/rsync_task.py,sha256=WfqNSaicJgYWpunNU34eYxXDqHDHOftuDHyWJKjqwg0,6365
|
366
366
|
zrb/task/scaffolder.py,sha256=rME18w1HJUHXgi9eTYXx_T2G4JdqDYzBoNOkdOOo5-o,6806
|
367
|
-
zrb/task/scheduler.py,sha256=
|
367
|
+
zrb/task/scheduler.py,sha256=lPsemHq40QrYiw3QNJwoWG9fc28qDrhvwVYnQ797_7Q,3133
|
368
368
|
zrb/task/task.py,sha256=KCrCaWYOQQvv1RJsYtHDeo9RBFmlXQ28oKyEFU4Q7pA,73
|
369
369
|
zrb/task/tcp_check.py,sha256=P_QgGqwd5dXDaud3oQRxe_WuxyxG4s7CTY2wDk9Qcu0,2511
|
370
370
|
zrb/task_status/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -410,7 +410,7 @@ zrb/util/todo_model.py,sha256=hhzAX-uFl5rsg7iVX1ULlJOfBtblwQ_ieNUxBWfc-Os,1670
|
|
410
410
|
zrb/util/truncate.py,sha256=eSzmjBpc1Qod3lM3M73snNbDOcARHukW_tq36dWdPvc,921
|
411
411
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
412
412
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
413
|
-
zrb-1.15.
|
414
|
-
zrb-1.15.
|
415
|
-
zrb-1.15.
|
416
|
-
zrb-1.15.
|
413
|
+
zrb-1.15.26.dist-info/METADATA,sha256=Eu_JTWqERNjfPIA4s8ChoWYZ7Da_PsT4p4OwB5BtxIw,9892
|
414
|
+
zrb-1.15.26.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
415
|
+
zrb-1.15.26.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
416
|
+
zrb-1.15.26.dist-info/RECORD,,
|
File without changes
|
File without changes
|