zrb 1.5.16__py3-none-any.whl → 1.6.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/__init__.py +2 -2
- zrb/__main__.py +12 -12
- zrb/builtin/__init__.py +2 -2
- zrb/builtin/llm/chat_session.py +202 -0
- zrb/builtin/llm/history.py +6 -6
- zrb/builtin/llm/llm_ask.py +142 -0
- zrb/builtin/llm/tool/rag.py +39 -23
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/gateway/view/static/default/script.js +1 -1
- zrb/builtin/todo.py +21 -19
- zrb/callback/any_callback.py +1 -1
- zrb/callback/callback.py +69 -7
- zrb/config.py +261 -91
- zrb/context/shared_context.py +4 -2
- zrb/input/text_input.py +9 -6
- zrb/llm_config.py +65 -74
- zrb/runner/cli.py +13 -4
- zrb/runner/web_app.py +3 -3
- zrb/runner/web_config/config_factory.py +11 -22
- zrb/runner/web_route/error_page/show_error_page.py +16 -6
- zrb/runner/web_route/home_page/home_page_route.py +23 -7
- zrb/runner/web_route/home_page/view.html +19 -33
- zrb/runner/web_route/login_page/login_page_route.py +14 -4
- zrb/runner/web_route/login_page/view.html +33 -51
- zrb/runner/web_route/logout_page/logout_page_route.py +15 -5
- zrb/runner/web_route/logout_page/view.html +23 -41
- zrb/runner/web_route/node_page/group/show_group_page.py +26 -10
- zrb/runner/web_route/node_page/group/view.html +22 -37
- zrb/runner/web_route/node_page/task/show_task_page.py +34 -19
- zrb/runner/web_route/node_page/task/view.html +74 -88
- zrb/runner/web_route/static/global_template.html +27 -0
- zrb/runner/web_route/static/resources/common.css +21 -0
- zrb/runner/web_route/static/resources/common.js +28 -0
- zrb/runner/web_route/task_session_api_route.py +3 -1
- zrb/session_state_logger/session_state_logger_factory.py +2 -2
- zrb/task/base_task.py +4 -1
- zrb/task/base_trigger.py +47 -2
- zrb/task/cmd_task.py +3 -3
- zrb/task/llm/agent.py +10 -1
- zrb/task/llm/print_node.py +5 -6
- zrb/task/llm_task.py +1 -1
- zrb/util/git_subtree.py +1 -1
- {zrb-1.5.16.dist-info → zrb-1.6.0.dist-info}/METADATA +1 -1
- {zrb-1.5.16.dist-info → zrb-1.6.0.dist-info}/RECORD +45 -42
- zrb/builtin/llm/llm_chat.py +0 -124
- {zrb-1.5.16.dist-info → zrb-1.6.0.dist-info}/WHEEL +0 -0
- {zrb-1.5.16.dist-info → zrb-1.6.0.dist-info}/entry_points.txt +0 -0
zrb/builtin/todo.py
CHANGED
@@ -4,7 +4,7 @@ import os
|
|
4
4
|
from typing import Any
|
5
5
|
|
6
6
|
from zrb.builtin.group import todo_group
|
7
|
-
from zrb.config import
|
7
|
+
from zrb.config import CFG
|
8
8
|
from zrb.context.any_context import AnyContext
|
9
9
|
from zrb.input.str_input import StrInput
|
10
10
|
from zrb.input.text_input import TextInput
|
@@ -25,7 +25,9 @@ from zrb.util.todo import (
|
|
25
25
|
)
|
26
26
|
|
27
27
|
|
28
|
-
def _get_filter_input(
|
28
|
+
def _get_filter_input(
|
29
|
+
allow_positional_parsing: bool = False, default: str | None = None
|
30
|
+
) -> StrInput:
|
29
31
|
return StrInput(
|
30
32
|
name="filter",
|
31
33
|
description="Visual filter",
|
@@ -33,7 +35,7 @@ def _get_filter_input(allow_positional_parsing: bool = False) -> StrInput:
|
|
33
35
|
allow_empty=True,
|
34
36
|
allow_positional_parsing=allow_positional_parsing,
|
35
37
|
always_prompt=False,
|
36
|
-
default=TODO_VISUAL_FILTER,
|
38
|
+
default=default if default is not None else CFG.TODO_VISUAL_FILTER,
|
37
39
|
)
|
38
40
|
|
39
41
|
|
@@ -70,12 +72,12 @@ def _get_filter_input(allow_positional_parsing: bool = False) -> StrInput:
|
|
70
72
|
alias="add",
|
71
73
|
)
|
72
74
|
def add_todo(ctx: AnyContext):
|
73
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
75
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
74
76
|
todo_list: list[TodoTaskModel] = []
|
75
77
|
if os.path.isfile(todo_file_path):
|
76
78
|
todo_list = load_todo_list(todo_file_path)
|
77
79
|
else:
|
78
|
-
os.makedirs(TODO_DIR, exist_ok=True)
|
80
|
+
os.makedirs(CFG.TODO_DIR, exist_ok=True)
|
79
81
|
todo_list.append(
|
80
82
|
cascade_todo_task(
|
81
83
|
TodoTaskModel(
|
@@ -106,7 +108,7 @@ def add_todo(ctx: AnyContext):
|
|
106
108
|
alias="list",
|
107
109
|
)
|
108
110
|
def list_todo(ctx: AnyContext):
|
109
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
111
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
110
112
|
todo_list: list[TodoTaskModel] = []
|
111
113
|
if os.path.isfile(todo_file_path):
|
112
114
|
todo_list = load_todo_list(todo_file_path)
|
@@ -121,7 +123,7 @@ def list_todo(ctx: AnyContext):
|
|
121
123
|
alias="show",
|
122
124
|
)
|
123
125
|
def show_todo(ctx: AnyContext):
|
124
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
126
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
125
127
|
todo_list: list[TodoTaskModel] = []
|
126
128
|
todo_list: list[TodoTaskModel] = []
|
127
129
|
if os.path.isfile(todo_file_path):
|
@@ -137,7 +139,7 @@ def show_todo(ctx: AnyContext):
|
|
137
139
|
# Update todo task
|
138
140
|
todo_task = cascade_todo_task(todo_task)
|
139
141
|
task_id = todo_task.keyval.get("id", "")
|
140
|
-
log_work_path = os.path.join(TODO_DIR, "log-work", f"{task_id}.json")
|
142
|
+
log_work_path = os.path.join(CFG.TODO_DIR, "log-work", f"{task_id}.json")
|
141
143
|
log_work_list = []
|
142
144
|
if os.path.isfile(log_work_path):
|
143
145
|
log_work_list = json.loads(read_file(log_work_path))
|
@@ -155,7 +157,7 @@ def show_todo(ctx: AnyContext):
|
|
155
157
|
alias="complete",
|
156
158
|
)
|
157
159
|
def complete_todo(ctx: AnyContext):
|
158
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
160
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
159
161
|
todo_list: list[TodoTaskModel] = []
|
160
162
|
if os.path.isfile(todo_file_path):
|
161
163
|
todo_list = load_todo_list(todo_file_path)
|
@@ -185,11 +187,11 @@ def complete_todo(ctx: AnyContext):
|
|
185
187
|
alias="archive",
|
186
188
|
)
|
187
189
|
def archive_todo(ctx: AnyContext):
|
188
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
190
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
189
191
|
todo_list: list[TodoTaskModel] = []
|
190
192
|
if os.path.isfile(todo_file_path):
|
191
193
|
todo_list = load_todo_list(todo_file_path)
|
192
|
-
retention_duration = datetime.timedelta(seconds=parse_duration(TODO_RETENTION))
|
194
|
+
retention_duration = datetime.timedelta(seconds=parse_duration(CFG.TODO_RETENTION))
|
193
195
|
threshold_date = datetime.date.today() - retention_duration
|
194
196
|
new_archived_todo_list = [
|
195
197
|
todo_task
|
@@ -204,9 +206,9 @@ def archive_todo(ctx: AnyContext):
|
|
204
206
|
if len(new_archived_todo_list) == 0:
|
205
207
|
ctx.print("No completed task to archive")
|
206
208
|
return get_visual_todo_list(todo_list, filter=ctx.input.filter)
|
207
|
-
archive_file_path = os.path.join(TODO_DIR, "archive.txt")
|
208
|
-
if not os.path.isdir(TODO_DIR):
|
209
|
-
os.make_dirs(TODO_DIR, exist_ok=True)
|
209
|
+
archive_file_path = os.path.join(CFG.TODO_DIR, "archive.txt")
|
210
|
+
if not os.path.isdir(CFG.TODO_DIR):
|
211
|
+
os.make_dirs(CFG.TODO_DIR, exist_ok=True)
|
210
212
|
# Get archived todo list
|
211
213
|
archived_todo_list = []
|
212
214
|
if os.path.isfile(archive_file_path):
|
@@ -246,7 +248,7 @@ def archive_todo(ctx: AnyContext):
|
|
246
248
|
alias="log",
|
247
249
|
)
|
248
250
|
def log_todo(ctx: AnyContext):
|
249
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
251
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
250
252
|
todo_list: list[TodoTaskModel] = []
|
251
253
|
if os.path.isfile(todo_file_path):
|
252
254
|
todo_list = load_todo_list(todo_file_path)
|
@@ -264,7 +266,7 @@ def log_todo(ctx: AnyContext):
|
|
264
266
|
# Save todo list
|
265
267
|
save_todo_list(todo_file_path, todo_list)
|
266
268
|
# Add log work
|
267
|
-
log_work_dir = os.path.join(TODO_DIR, "log-work")
|
269
|
+
log_work_dir = os.path.join(CFG.TODO_DIR, "log-work")
|
268
270
|
os.makedirs(log_work_dir, exist_ok=True)
|
269
271
|
log_work_file_path = os.path.join(
|
270
272
|
log_work_dir, f"{todo_task.keyval.get('id')}.json"
|
@@ -286,7 +288,7 @@ def log_todo(ctx: AnyContext):
|
|
286
288
|
write_file(log_work_file_path, json.dumps(log_work, indent=2))
|
287
289
|
# get log work list
|
288
290
|
task_id = todo_task.keyval.get("id", "")
|
289
|
-
log_work_path = os.path.join(TODO_DIR, "log-work", f"{task_id}.json")
|
291
|
+
log_work_path = os.path.join(CFG.TODO_DIR, "log-work", f"{task_id}.json")
|
290
292
|
log_work_list = []
|
291
293
|
if os.path.isfile(log_work_path):
|
292
294
|
log_work_list = json.loads(read_file(log_work_path))
|
@@ -333,14 +335,14 @@ def edit_todo(ctx: AnyContext):
|
|
333
335
|
if line.strip() != ""
|
334
336
|
]
|
335
337
|
new_content = "\n".join(todo_task_to_line(todo_task) for todo_task in todo_list)
|
336
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
338
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
337
339
|
write_file(todo_file_path, new_content)
|
338
340
|
todo_list = load_todo_list(todo_file_path)
|
339
341
|
return get_visual_todo_list(todo_list, filter=ctx.input.filter)
|
340
342
|
|
341
343
|
|
342
344
|
def _get_todo_txt_content() -> str:
|
343
|
-
todo_file_path = os.path.join(TODO_DIR, "todo.txt")
|
345
|
+
todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
|
344
346
|
if not os.path.isfile(todo_file_path):
|
345
347
|
return ""
|
346
348
|
return read_file(todo_file_path)
|
zrb/callback/any_callback.py
CHANGED
zrb/callback/callback.py
CHANGED
@@ -5,23 +5,85 @@ from zrb.callback.any_callback import AnyCallback
|
|
5
5
|
from zrb.session.any_session import AnySession
|
6
6
|
from zrb.task.any_task import AnyTask
|
7
7
|
from zrb.util.attr import get_str_dict_attr
|
8
|
+
from zrb.util.string.conversion import to_snake_case
|
9
|
+
from zrb.xcom.xcom import Xcom
|
8
10
|
|
9
11
|
|
10
12
|
class Callback(AnyCallback):
|
13
|
+
"""
|
14
|
+
Represents a callback that runs a task after a trigger or scheduler event.
|
15
|
+
|
16
|
+
It handles input mapping and can publish results and session names
|
17
|
+
back to the parent session via XCom.
|
18
|
+
"""
|
19
|
+
|
11
20
|
def __init__(
|
12
21
|
self,
|
13
|
-
input_mapping: StrDictAttr,
|
14
22
|
task: AnyTask,
|
15
|
-
|
23
|
+
input_mapping: StrDictAttr,
|
24
|
+
render_input_mapping: bool = True,
|
25
|
+
result_queue: str | None = None,
|
26
|
+
session_name_queue: str | None = None,
|
16
27
|
):
|
17
|
-
|
28
|
+
"""
|
29
|
+
Initializes a new instance of the Callback class.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
task: The task to be executed by the callback.
|
33
|
+
input_mapping: A dictionary or attribute mapping to prepare inputs for the task.
|
34
|
+
render_input_mapping: Whether to render the input mapping using
|
35
|
+
f-string like syntax.
|
36
|
+
result_queue: The name of the XCom queue in the parent session
|
37
|
+
to publish the task result.
|
38
|
+
session_name_queue: The name of the XCom queue in the parent
|
39
|
+
session to publish the session name.
|
40
|
+
"""
|
18
41
|
self._task = task
|
19
|
-
self.
|
42
|
+
self._input_mapping = input_mapping
|
43
|
+
self._render_input_mapping = render_input_mapping
|
44
|
+
self._result_queue = result_queue
|
45
|
+
self._session_name_queue = session_name_queue
|
20
46
|
|
21
|
-
async def async_run(self, session: AnySession) -> Any:
|
47
|
+
async def async_run(self, parent_session: AnySession, session: AnySession) -> Any:
|
48
|
+
self._maybe_publish_session_name_to_parent_session(
|
49
|
+
parent_session=parent_session, session=session
|
50
|
+
)
|
51
|
+
# prepare input
|
22
52
|
inputs = get_str_dict_attr(
|
23
|
-
session.shared_ctx,
|
53
|
+
session.shared_ctx,
|
54
|
+
self._input_mapping,
|
55
|
+
auto_render=self._render_input_mapping,
|
24
56
|
)
|
25
57
|
for name, value in inputs.items():
|
26
58
|
session.shared_ctx.input[name] = value
|
27
|
-
|
59
|
+
session.shared_ctx.input[to_snake_case(name)] = value
|
60
|
+
# run task and get result
|
61
|
+
result = await self._task.async_run(session)
|
62
|
+
self._maybe_publish_result_to_parent_session(parent_session, result)
|
63
|
+
return result
|
64
|
+
|
65
|
+
def _maybe_publish_session_name_to_parent_session(
|
66
|
+
self, parent_session: AnySession, session: AnySession
|
67
|
+
):
|
68
|
+
self._maybe_publish_to_parent_session(
|
69
|
+
parent_session=parent_session,
|
70
|
+
xcom_name=self._session_name_queue,
|
71
|
+
value=session.name,
|
72
|
+
)
|
73
|
+
|
74
|
+
def _maybe_publish_result_to_parent_session(
|
75
|
+
self, parent_session: AnySession, result: Any
|
76
|
+
):
|
77
|
+
self._maybe_publish_to_parent_session(
|
78
|
+
parent_session=parent_session, xcom_name=self._result_queue, value=result
|
79
|
+
)
|
80
|
+
|
81
|
+
def _maybe_publish_to_parent_session(
|
82
|
+
self, parent_session: AnySession, xcom_name: str | None, value: Any
|
83
|
+
):
|
84
|
+
if xcom_name is None:
|
85
|
+
return
|
86
|
+
parent_xcom = parent_session.shared_ctx.xcom
|
87
|
+
if xcom_name not in parent_xcom:
|
88
|
+
parent_xcom[xcom_name] = Xcom([])
|
89
|
+
parent_xcom[xcom_name].push(value)
|
zrb/config.py
CHANGED
@@ -2,108 +2,278 @@ import importlib.metadata as metadata
|
|
2
2
|
import logging
|
3
3
|
import os
|
4
4
|
import platform
|
5
|
+
from textwrap import dedent
|
5
6
|
|
6
7
|
from zrb.util.string.conversion import to_boolean
|
8
|
+
from zrb.util.string.format import fstring_format
|
7
9
|
|
8
|
-
|
9
|
-
def _get_current_shell() -> str:
|
10
|
-
if platform.system() == "Windows":
|
11
|
-
return "PowerShell"
|
12
|
-
current_shell = os.getenv("SHELL", "")
|
13
|
-
if current_shell.endswith("zsh"):
|
14
|
-
return "zsh"
|
15
|
-
return "bash"
|
16
|
-
|
17
|
-
|
18
|
-
def _get_log_level(level: str) -> int:
|
19
|
-
level = level.upper()
|
20
|
-
log_levels = {
|
21
|
-
"CRITICAL": logging.CRITICAL, # 50
|
22
|
-
"ERROR": logging.ERROR, # 40
|
23
|
-
"WARN": logging.WARNING, # 30
|
24
|
-
"WARNING": logging.WARNING, # 30
|
25
|
-
"INFO": logging.INFO, # 20
|
26
|
-
"DEBUG": logging.DEBUG, # 10
|
27
|
-
"NOTSET": logging.NOTSET, # 0
|
28
|
-
}
|
29
|
-
if level in log_levels:
|
30
|
-
return log_levels[level]
|
31
|
-
return logging.WARNING
|
32
|
-
|
33
|
-
|
34
|
-
LOGGER = logging.getLogger()
|
35
|
-
DEFAULT_SHELL = os.getenv("ZRB_SHELL", _get_current_shell())
|
36
|
-
DEFAULT_EDITOR = os.getenv("ZRB_EDITOR", "nano")
|
37
|
-
INIT_MODULES_STR = os.getenv("ZRB_INIT_MODULES", "")
|
38
|
-
INIT_MODULES = (
|
39
|
-
[module.strip() for module in INIT_MODULES_STR.split(":") if module.strip() != ""]
|
40
|
-
if INIT_MODULES_STR != ""
|
41
|
-
else []
|
42
|
-
)
|
43
|
-
INIT_SCRIPTS_STR = os.getenv("ZRB_INIT_SCRIPTS", "")
|
44
|
-
INIT_SCRIPTS = (
|
45
|
-
[script.strip() for script in INIT_SCRIPTS_STR.split(":") if script.strip() != ""]
|
46
|
-
if INIT_SCRIPTS_STR != ""
|
47
|
-
else []
|
48
|
-
)
|
49
|
-
LOGGING_LEVEL = _get_log_level(os.getenv("ZRB_LOGGING_LEVEL", "WARNING"))
|
50
|
-
LOAD_BUILTIN = to_boolean(os.getenv("ZRB_LOAD_BUILTIN", "1"))
|
51
|
-
WARN_UNRECOMMENDED_COMMAND = to_boolean(
|
52
|
-
os.getenv("ZRB_WARN_UNRECOMMENDED_COMMAND", "1")
|
53
|
-
)
|
54
|
-
SESSION_LOG_DIR = os.getenv(
|
55
|
-
"ZRB_SESSION_LOG_DIR", os.path.expanduser(os.path.join("~", ".zrb-session"))
|
56
|
-
)
|
57
|
-
TODO_DIR = os.getenv("ZRB_TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
|
58
|
-
TODO_VISUAL_FILTER = os.getenv("ZRB_TODO_FILTER", "")
|
59
|
-
TODO_RETENTION = os.getenv("ZRB_TODO_RETENTION", "2w")
|
60
|
-
VERSION = metadata.version("zrb")
|
61
|
-
WEB_HTTP_PORT = int(os.getenv("ZRB_WEB_HTTP_PORT", "21213"))
|
62
|
-
WEB_GUEST_USERNAME = os.getenv("ZRB_WEB_GUEST_USERNAME", "user")
|
63
|
-
WEB_SUPER_ADMIN_USERNAME = os.getenv("ZRB_WEB_SUPERADMIN_USERNAME", "admin")
|
64
|
-
WEB_SUPER_ADMIN_PASSWORD = os.getenv("ZRB_WEB_SUPERADMIN_PASSWORD", "admin")
|
65
|
-
WEB_ACCESS_TOKEN_COOKIE_NAME = os.getenv(
|
66
|
-
"ZRB_WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token"
|
67
|
-
)
|
68
|
-
WEB_REFRESH_TOKEN_COOKIE_NAME = os.getenv(
|
69
|
-
"ZRB_WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token"
|
70
|
-
)
|
71
|
-
WEB_SECRET_KEY = os.getenv("ZRB_WEB_SECRET", "zrb")
|
72
|
-
WEB_ENABLE_AUTH = to_boolean(os.getenv("ZRB_WEB_ENABLE_AUTH", "0"))
|
73
|
-
WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES = int(
|
74
|
-
os.getenv("ZRB_WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30")
|
75
|
-
)
|
76
|
-
WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES = int(
|
77
|
-
os.getenv("ZRB_WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60")
|
78
|
-
)
|
79
|
-
|
80
|
-
LLM_HISTORY_DIR = os.getenv(
|
81
|
-
"ZRB_LLM_HISTORY_DIR", os.path.expanduser(os.path.join("~", ".zrb-llm-history"))
|
82
|
-
)
|
83
|
-
LLM_ALLOW_ACCESS_LOCAL_FILE = to_boolean(os.getenv("ZRB_LLM_ACCESS_LOCAL_FILE", "1"))
|
84
|
-
LLM_ALLOW_ACCESS_SHELL = to_boolean(os.getenv("ZRB_LLM_ACCESS_SHELL", "1"))
|
85
|
-
LLM_ALLOW_ACCESS_INTERNET = to_boolean(os.getenv("ZRB_LLM_ACCESS_INTERNET", "1"))
|
86
|
-
# RAG Configuration
|
87
|
-
RAG_EMBEDDING_API_KEY = os.getenv("ZRB_RAG_EMBEDDING_API_KEY", None)
|
88
|
-
RAG_EMBEDDING_BASE_URL = os.getenv("ZRB_RAG_EMBEDDING_BASE_URL", None)
|
89
|
-
RAG_EMBEDDING_MODEL = os.getenv("ZRB_RAG_EMBEDDING_MODEL", "text-embedding-ada-002")
|
90
|
-
RAG_CHUNK_SIZE = int(os.getenv("ZRB_RAG_CHUNK_SIZE", "1024"))
|
91
|
-
RAG_OVERLAP = int(os.getenv("ZRB_RAG_OVERLAP", "128"))
|
92
|
-
RAG_MAX_RESULT_COUNT = int(os.getenv("ZRB_RAG_MAX_RESULT_COUNT", "5"))
|
93
|
-
SERP_API_KEY = os.getenv("SERP_API_KEY", "")
|
94
|
-
|
95
|
-
|
96
|
-
BANNER = f"""
|
10
|
+
_DEFAULT_BANNER = """
|
97
11
|
bb
|
98
12
|
zzzzz rr rr bb
|
99
13
|
zz rrr r bbbbbb
|
100
14
|
zz rr bb bb
|
101
15
|
zzzzz rr bbbbbb {VERSION} Janggala
|
102
16
|
_ _ . . . _ . _ . . .
|
103
|
-
|
104
17
|
Your Automation Powerhouse
|
105
|
-
|
106
18
|
☕ Donate at: https://stalchmst.com/donation
|
107
19
|
🐙 Submit issues/PR at: https://github.com/state-alchemists/zrb
|
108
20
|
🐤 Follow us at: https://twitter.com/zarubastalchmst
|
109
21
|
"""
|
22
|
+
|
23
|
+
|
24
|
+
class Config:
|
25
|
+
@property
|
26
|
+
def LOGGER(self) -> logging.Logger:
|
27
|
+
return logging.getLogger()
|
28
|
+
|
29
|
+
@property
|
30
|
+
def DEFAULT_SHELL(self) -> str:
|
31
|
+
return os.getenv("ZRB_SHELL", self._get_current_shell())
|
32
|
+
|
33
|
+
def _get_current_shell(self) -> str:
|
34
|
+
if platform.system() == "Windows":
|
35
|
+
return "PowerShell"
|
36
|
+
current_shell = os.getenv("SHELL", "")
|
37
|
+
if current_shell.endswith("zsh"):
|
38
|
+
return "zsh"
|
39
|
+
return "bash"
|
40
|
+
|
41
|
+
@property
|
42
|
+
def DEFAULT_EDITOR(self) -> str:
|
43
|
+
return os.getenv("ZRB_EDITOR", "nano")
|
44
|
+
|
45
|
+
@property
|
46
|
+
def INIT_MODULES(self) -> list[str]:
|
47
|
+
init_modules_str = os.getenv("ZRB_INIT_MODULES", "")
|
48
|
+
return (
|
49
|
+
[
|
50
|
+
module.strip()
|
51
|
+
for module in init_modules_str.split(":")
|
52
|
+
if module.strip() != ""
|
53
|
+
]
|
54
|
+
if init_modules_str != ""
|
55
|
+
else []
|
56
|
+
)
|
57
|
+
|
58
|
+
@property
|
59
|
+
def INIT_SCRIPTS(self) -> list[str]:
|
60
|
+
init_scripts_str = os.getenv("ZRB_INIT_SCRIPTS", "")
|
61
|
+
return (
|
62
|
+
[
|
63
|
+
script.strip()
|
64
|
+
for script in init_scripts_str.split(":")
|
65
|
+
if script.strip() != ""
|
66
|
+
]
|
67
|
+
if init_scripts_str != ""
|
68
|
+
else []
|
69
|
+
)
|
70
|
+
|
71
|
+
@property
|
72
|
+
def INIT_FILE_NAME(self) -> str:
|
73
|
+
return os.getenv("ZRB_INIT_FILE_NAME", "zrb_init.py")
|
74
|
+
|
75
|
+
@property
|
76
|
+
def LOGGING_LEVEL(self) -> int:
|
77
|
+
return self._get_log_level(os.getenv("ZRB_LOGGING_LEVEL", "WARNING"))
|
78
|
+
|
79
|
+
def _get_log_level(self, level: str) -> int:
|
80
|
+
level = level.upper()
|
81
|
+
log_levels = {
|
82
|
+
"CRITICAL": logging.CRITICAL, # 50
|
83
|
+
"ERROR": logging.ERROR, # 40
|
84
|
+
"WARN": logging.WARNING, # 30
|
85
|
+
"WARNING": logging.WARNING, # 30
|
86
|
+
"INFO": logging.INFO, # 20
|
87
|
+
"DEBUG": logging.DEBUG, # 10
|
88
|
+
"NOTSET": logging.NOTSET, # 0
|
89
|
+
}
|
90
|
+
if level in log_levels:
|
91
|
+
return log_levels[level]
|
92
|
+
return logging.WARNING
|
93
|
+
|
94
|
+
@property
|
95
|
+
def LOAD_BUILTIN(self) -> bool:
|
96
|
+
return to_boolean(os.getenv("ZRB_LOAD_BUILTIN", "1"))
|
97
|
+
|
98
|
+
@property
|
99
|
+
def WARN_UNRECOMMENDED_COMMAND(self) -> bool:
|
100
|
+
return to_boolean(os.getenv("ZRB_WARN_UNRECOMMENDED_COMMAND", "1"))
|
101
|
+
|
102
|
+
@property
|
103
|
+
def SESSION_LOG_DIR(self) -> str:
|
104
|
+
return os.getenv(
|
105
|
+
"ZRB_SESSION_LOG_DIR", os.path.expanduser(os.path.join("~", ".zrb-session"))
|
106
|
+
)
|
107
|
+
|
108
|
+
@property
|
109
|
+
def TODO_DIR(self) -> str:
|
110
|
+
return os.getenv("ZRB_TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
|
111
|
+
|
112
|
+
@property
|
113
|
+
def TODO_VISUAL_FILTER(self) -> str:
|
114
|
+
return os.getenv("ZRB_TODO_FILTER", "")
|
115
|
+
|
116
|
+
@property
|
117
|
+
def TODO_RETENTION(self) -> str:
|
118
|
+
return os.getenv("ZRB_TODO_RETENTION", "2w")
|
119
|
+
|
120
|
+
@property
|
121
|
+
def VERSION(self) -> str:
|
122
|
+
return metadata.version("zrb")
|
123
|
+
|
124
|
+
@property
|
125
|
+
def WEB_HTTP_PORT(self) -> int:
|
126
|
+
return int(os.getenv("ZRB_WEB_HTTP_PORT", "21213"))
|
127
|
+
|
128
|
+
@property
|
129
|
+
def WEB_GUEST_USERNAME(self) -> str:
|
130
|
+
return os.getenv("ZRB_WEB_GUEST_USERNAME", "user")
|
131
|
+
|
132
|
+
@property
|
133
|
+
def WEB_SUPER_ADMIN_USERNAME(self) -> str:
|
134
|
+
return os.getenv("ZRB_WEB_SUPERADMIN_USERNAME", "admin")
|
135
|
+
|
136
|
+
@property
|
137
|
+
def WEB_SUPER_ADMIN_PASSWORD(self) -> str:
|
138
|
+
return os.getenv("ZRB_WEB_SUPERADMIN_PASSWORD", "admin")
|
139
|
+
|
140
|
+
@property
|
141
|
+
def WEB_ACCESS_TOKEN_COOKIE_NAME(self) -> str:
|
142
|
+
return os.getenv("ZRB_WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token")
|
143
|
+
|
144
|
+
@property
|
145
|
+
def WEB_REFRESH_TOKEN_COOKIE_NAME(self) -> str:
|
146
|
+
return os.getenv("ZRB_WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token")
|
147
|
+
|
148
|
+
@property
|
149
|
+
def WEB_SECRET_KEY(self) -> str:
|
150
|
+
return os.getenv("ZRB_WEB_SECRET", "zrb")
|
151
|
+
|
152
|
+
@property
|
153
|
+
def WEB_ENABLE_AUTH(self) -> bool:
|
154
|
+
return to_boolean(os.getenv("ZRB_WEB_ENABLE_AUTH", "0"))
|
155
|
+
|
156
|
+
@property
|
157
|
+
def WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES(self) -> int:
|
158
|
+
return int(os.getenv("ZRB_WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
|
159
|
+
|
160
|
+
@property
|
161
|
+
def WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES(self) -> int:
|
162
|
+
return int(os.getenv("ZRB_WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60"))
|
163
|
+
|
164
|
+
@property
|
165
|
+
def WEB_TITLE(self) -> str:
|
166
|
+
return os.getenv("ZRB_WEB_TITLE", "Zrb")
|
167
|
+
|
168
|
+
@property
|
169
|
+
def WEB_JARGON(self) -> str:
|
170
|
+
return os.getenv("ZRB_WEB_JARGON", "Your Automation PowerHouse")
|
171
|
+
|
172
|
+
@property
|
173
|
+
def WEB_HOMEPAGE_INTRO(self) -> str:
|
174
|
+
return os.getenv("ZRB_WEB_HOMEPAGE_INTRO", "Welcome to Zrb Web Interface")
|
175
|
+
|
176
|
+
@property
|
177
|
+
def LLM_MODEL(self) -> str | None:
|
178
|
+
return os.getenv("ZRB_LLM_MODEL", None)
|
179
|
+
|
180
|
+
@property
|
181
|
+
def LLM_BASE_URL(self) -> str | None:
|
182
|
+
return os.getenv("ZRB_LLM_BASE_URL", None)
|
183
|
+
|
184
|
+
@property
|
185
|
+
def LLM_API_KEY(self) -> str | None:
|
186
|
+
return os.getenv("ZRB_LLM_API_KEY", None)
|
187
|
+
|
188
|
+
@property
|
189
|
+
def LLM_SYSTEM_PROMPT(self) -> str | None:
|
190
|
+
return os.getenv("ZRB_LLM_SYSTEM_PROMPT", None)
|
191
|
+
|
192
|
+
@property
|
193
|
+
def LLM_PERSONA(self) -> str | None:
|
194
|
+
return os.getenv("ZRB_LLM_PERSONA", None)
|
195
|
+
|
196
|
+
@property
|
197
|
+
def LLM_SPECIAL_INSTRUCTION_PROMPT(self) -> str | None:
|
198
|
+
return os.getenv("ZRB_LLM_SPECIAL_INSTRUCTION_PROMPT", None)
|
199
|
+
|
200
|
+
@property
|
201
|
+
def LLM_SUMMARIZATION_PROMPT(self) -> str | None:
|
202
|
+
return os.getenv("ZRB_LLM_SUMMARIZATION_PROMPT", None)
|
203
|
+
|
204
|
+
@property
|
205
|
+
def LLM_CONTEXT_ENRICHMENT_PROMPT(self) -> str | None:
|
206
|
+
return os.getenv("ZRB_LLM_CONTEXT_ENRICHMENT_PROMPT", None)
|
207
|
+
|
208
|
+
@property
|
209
|
+
def LLM_SUMMARIZE_HISTORY(self) -> bool:
|
210
|
+
return to_boolean(os.getenv("ZRB_LLM_SUMMARIZE_HISTORY", "true"))
|
211
|
+
|
212
|
+
@property
|
213
|
+
def LLM_HISTORY_SUMMARIZATION_THRESHOLD(self) -> int:
|
214
|
+
return int(os.getenv("ZRB_LLM_HISTORY_SUMMARIZATION_THRESHOLD", "5"))
|
215
|
+
|
216
|
+
@property
|
217
|
+
def LLM_ENRICH_CONTEXT(self) -> bool:
|
218
|
+
return to_boolean(os.getenv("ZRB_LLM_ENRICH_CONTEXT", "true"))
|
219
|
+
|
220
|
+
@property
|
221
|
+
def LLM_CONTEXT_ENRICHMENT_THRESHOLD(self) -> int:
|
222
|
+
return int(os.getenv("ZRB_LLM_CONTEXT_ENRICHMENT_THRESHOLD", "5"))
|
223
|
+
|
224
|
+
@property
|
225
|
+
def LLM_HISTORY_DIR(self) -> str:
|
226
|
+
return os.getenv(
|
227
|
+
"ZRB_LLM_HISTORY_DIR",
|
228
|
+
os.path.expanduser(os.path.join("~", ".zrb-llm-history")),
|
229
|
+
)
|
230
|
+
|
231
|
+
@property
|
232
|
+
def LLM_ALLOW_ACCESS_LOCAL_FILE(self) -> bool:
|
233
|
+
return to_boolean(os.getenv("ZRB_LLM_ACCESS_LOCAL_FILE", "1"))
|
234
|
+
|
235
|
+
@property
|
236
|
+
def LLM_ALLOW_ACCESS_SHELL(self) -> bool:
|
237
|
+
return to_boolean(os.getenv("ZRB_LLM_ACCESS_SHELL", "1"))
|
238
|
+
|
239
|
+
@property
|
240
|
+
def LLM_ALLOW_ACCESS_INTERNET(self) -> bool:
|
241
|
+
return to_boolean(os.getenv("ZRB_LLM_ACCESS_INTERNET", "1"))
|
242
|
+
|
243
|
+
@property
|
244
|
+
def RAG_EMBEDDING_API_KEY(self) -> str:
|
245
|
+
return os.getenv("ZRB_RAG_EMBEDDING_API_KEY", None)
|
246
|
+
|
247
|
+
@property
|
248
|
+
def RAG_EMBEDDING_BASE_URL(self) -> str:
|
249
|
+
return os.getenv("ZRB_RAG_EMBEDDING_BASE_URL", None)
|
250
|
+
|
251
|
+
@property
|
252
|
+
def RAG_EMBEDDING_MODEL(self) -> str:
|
253
|
+
return os.getenv("ZRB_RAG_EMBEDDING_MODEL", "text-embedding-ada-002")
|
254
|
+
|
255
|
+
@property
|
256
|
+
def RAG_CHUNK_SIZE(self) -> int:
|
257
|
+
return int(os.getenv("ZRB_RAG_CHUNK_SIZE", "1024"))
|
258
|
+
|
259
|
+
@property
|
260
|
+
def RAG_OVERLAP(self) -> int:
|
261
|
+
return int(os.getenv("ZRB_RAG_OVERLAP", "128"))
|
262
|
+
|
263
|
+
@property
|
264
|
+
def RAG_MAX_RESULT_COUNT(self) -> int:
|
265
|
+
return int(os.getenv("ZRB_RAG_MAX_RESULT_COUNT", "5"))
|
266
|
+
|
267
|
+
@property
|
268
|
+
def SERP_API_KEY(self) -> str:
|
269
|
+
return os.getenv("SERP_API_KEY", "")
|
270
|
+
|
271
|
+
@property
|
272
|
+
def BANNER(self) -> str:
|
273
|
+
return fstring_format(
|
274
|
+
os.getenv("ZRB_BANNER", _DEFAULT_BANNER),
|
275
|
+
{"VERSION": self.VERSION},
|
276
|
+
)
|
277
|
+
|
278
|
+
|
279
|
+
CFG = Config()
|
zrb/context/shared_context.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import datetime
|
2
2
|
from typing import Any
|
3
3
|
|
4
|
-
from zrb.config import
|
4
|
+
from zrb.config import CFG
|
5
5
|
from zrb.context.any_shared_context import AnySharedContext
|
6
6
|
from zrb.dot_dict.dot_dict import DotDict
|
7
7
|
from zrb.session.any_session import AnySession
|
@@ -25,7 +25,7 @@ class SharedContext(AnySharedContext):
|
|
25
25
|
args: list[Any] = [],
|
26
26
|
env: dict[str, str] = {},
|
27
27
|
xcom: dict[str, Xcom] = {},
|
28
|
-
logging_level: int =
|
28
|
+
logging_level: int | None = None,
|
29
29
|
):
|
30
30
|
self.__logging_level = logging_level
|
31
31
|
self._input = DotDict(input)
|
@@ -79,6 +79,8 @@ class SharedContext(AnySharedContext):
|
|
79
79
|
self._session = session
|
80
80
|
|
81
81
|
def get_logging_level(self) -> int:
|
82
|
+
if self.__logging_level is None:
|
83
|
+
return CFG.LOGGING_LEVEL
|
82
84
|
return self.__logging_level
|
83
85
|
|
84
86
|
def render(self, template: str) -> str:
|
zrb/input/text_input.py
CHANGED
@@ -3,7 +3,7 @@ import subprocess
|
|
3
3
|
import tempfile
|
4
4
|
from collections.abc import Callable
|
5
5
|
|
6
|
-
from zrb.config import
|
6
|
+
from zrb.config import CFG
|
7
7
|
from zrb.context.any_shared_context import AnySharedContext
|
8
8
|
from zrb.input.base_input import BaseInput
|
9
9
|
from zrb.util.file import read_file
|
@@ -20,7 +20,7 @@ class TextInput(BaseInput):
|
|
20
20
|
allow_empty: bool = False,
|
21
21
|
allow_positional_parsing: bool = True,
|
22
22
|
always_prompt: bool = True,
|
23
|
-
editor: str =
|
23
|
+
editor: str | None = None,
|
24
24
|
extension: str = ".txt",
|
25
25
|
comment_start: str | None = None,
|
26
26
|
comment_end: str | None = None,
|
@@ -86,10 +86,13 @@ class TextInput(BaseInput):
|
|
86
86
|
if default_value:
|
87
87
|
temp_file.write(default_value.encode())
|
88
88
|
temp_file.flush()
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
# Open the editor
|
90
|
+
editor_cmd = (
|
91
|
+
self._editor if self._editor is not None else CFG.DEFAULT_EDITOR
|
92
|
+
)
|
93
|
+
subprocess.call([editor_cmd, temp_file_name])
|
94
|
+
# Read the edited content
|
95
|
+
edited_content = read_file(temp_file_name)
|
93
96
|
parts = [
|
94
97
|
text.strip() for text in edited_content.split(comment_prompt_message, 1)
|
95
98
|
]
|