zrb 1.13.1__py3-none-any.whl → 1.21.17__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.
Files changed (105) hide show
  1. zrb/__init__.py +2 -6
  2. zrb/attr/type.py +8 -8
  3. zrb/builtin/__init__.py +2 -0
  4. zrb/builtin/group.py +31 -15
  5. zrb/builtin/http.py +7 -8
  6. zrb/builtin/llm/attachment.py +40 -0
  7. zrb/builtin/llm/chat_session.py +130 -144
  8. zrb/builtin/llm/chat_session_cmd.py +226 -0
  9. zrb/builtin/llm/chat_trigger.py +73 -0
  10. zrb/builtin/llm/history.py +4 -4
  11. zrb/builtin/llm/llm_ask.py +218 -110
  12. zrb/builtin/llm/tool/api.py +74 -62
  13. zrb/builtin/llm/tool/cli.py +35 -16
  14. zrb/builtin/llm/tool/code.py +49 -47
  15. zrb/builtin/llm/tool/file.py +262 -251
  16. zrb/builtin/llm/tool/note.py +84 -0
  17. zrb/builtin/llm/tool/rag.py +25 -18
  18. zrb/builtin/llm/tool/sub_agent.py +29 -22
  19. zrb/builtin/llm/tool/web.py +135 -143
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  22. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  23. zrb/builtin/searxng/config/settings.yml +5671 -0
  24. zrb/builtin/searxng/start.py +21 -0
  25. zrb/builtin/setup/latex/ubuntu.py +1 -0
  26. zrb/builtin/setup/ubuntu.py +1 -1
  27. zrb/builtin/shell/autocomplete/bash.py +4 -3
  28. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  29. zrb/config/config.py +255 -78
  30. zrb/config/default_prompt/file_extractor_system_prompt.md +109 -9
  31. zrb/config/default_prompt/interactive_system_prompt.md +24 -30
  32. zrb/config/default_prompt/persona.md +1 -1
  33. zrb/config/default_prompt/repo_extractor_system_prompt.md +31 -31
  34. zrb/config/default_prompt/repo_summarizer_system_prompt.md +27 -8
  35. zrb/config/default_prompt/summarization_prompt.md +8 -13
  36. zrb/config/default_prompt/system_prompt.md +36 -30
  37. zrb/config/llm_config.py +129 -24
  38. zrb/config/llm_context/config.py +127 -90
  39. zrb/config/llm_context/config_parser.py +1 -7
  40. zrb/config/llm_context/workflow.py +81 -0
  41. zrb/config/llm_rate_limitter.py +89 -45
  42. zrb/context/any_shared_context.py +7 -1
  43. zrb/context/context.py +8 -2
  44. zrb/context/shared_context.py +6 -8
  45. zrb/group/any_group.py +12 -5
  46. zrb/group/group.py +67 -3
  47. zrb/input/any_input.py +5 -1
  48. zrb/input/base_input.py +18 -6
  49. zrb/input/text_input.py +7 -24
  50. zrb/runner/cli.py +21 -20
  51. zrb/runner/common_util.py +24 -19
  52. zrb/runner/web_route/task_input_api_route.py +5 -5
  53. zrb/runner/web_route/task_session_api_route.py +1 -4
  54. zrb/runner/web_util/user.py +7 -3
  55. zrb/session/any_session.py +12 -6
  56. zrb/session/session.py +39 -18
  57. zrb/task/any_task.py +24 -3
  58. zrb/task/base/context.py +17 -9
  59. zrb/task/base/execution.py +15 -8
  60. zrb/task/base/lifecycle.py +8 -4
  61. zrb/task/base/monitoring.py +12 -7
  62. zrb/task/base_task.py +69 -5
  63. zrb/task/base_trigger.py +12 -5
  64. zrb/task/llm/agent.py +138 -52
  65. zrb/task/llm/config.py +45 -13
  66. zrb/task/llm/conversation_history.py +76 -6
  67. zrb/task/llm/conversation_history_model.py +0 -168
  68. zrb/task/llm/default_workflow/coding/workflow.md +41 -0
  69. zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
  70. zrb/task/llm/default_workflow/git/workflow.md +118 -0
  71. zrb/task/llm/default_workflow/golang/workflow.md +128 -0
  72. zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
  73. zrb/task/llm/default_workflow/java/workflow.md +146 -0
  74. zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
  75. zrb/task/llm/default_workflow/python/workflow.md +160 -0
  76. zrb/task/llm/default_workflow/researching/workflow.md +153 -0
  77. zrb/task/llm/default_workflow/rust/workflow.md +162 -0
  78. zrb/task/llm/default_workflow/shell/workflow.md +299 -0
  79. zrb/task/llm/file_replacement.py +206 -0
  80. zrb/task/llm/file_tool_model.py +57 -0
  81. zrb/task/llm/history_summarization.py +22 -35
  82. zrb/task/llm/history_summarization_tool.py +24 -0
  83. zrb/task/llm/print_node.py +182 -63
  84. zrb/task/llm/prompt.py +213 -153
  85. zrb/task/llm/tool_wrapper.py +210 -53
  86. zrb/task/llm/workflow.py +76 -0
  87. zrb/task/llm_task.py +98 -47
  88. zrb/task/make_task.py +2 -3
  89. zrb/task/rsync_task.py +25 -10
  90. zrb/task/scheduler.py +4 -4
  91. zrb/util/attr.py +50 -40
  92. zrb/util/cli/markdown.py +12 -0
  93. zrb/util/cli/text.py +30 -0
  94. zrb/util/file.py +27 -11
  95. zrb/util/{llm/prompt.py → markdown.py} +2 -3
  96. zrb/util/string/conversion.py +1 -1
  97. zrb/util/truncate.py +23 -0
  98. zrb/util/yaml.py +204 -0
  99. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/METADATA +40 -20
  100. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/RECORD +102 -79
  101. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/WHEEL +1 -1
  102. zrb/task/llm/default_workflow/coding.md +0 -24
  103. zrb/task/llm/default_workflow/copywriting.md +0 -17
  104. zrb/task/llm/default_workflow/researching.md +0 -18
  105. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,21 @@
1
+ import os
2
+
3
+ from zrb.builtin.group import searxng_group
4
+ from zrb.config.config import CFG
5
+ from zrb.input.int_input import IntInput
6
+ from zrb.task.cmd_task import CmdTask
7
+ from zrb.task.http_check import HttpCheck
8
+
9
+ start_searxng = searxng_group.add_task(
10
+ CmdTask(
11
+ name="start-searxng",
12
+ input=IntInput(name="port", default=CFG.SEARXNG_PORT),
13
+ cwd=os.path.dirname(__file__),
14
+ cmd="docker run --rm -p {ctx.input.port}:8080 -v ./config/:/etc/searxng/ docker.io/searxng/searxng:latest -d", # noqa
15
+ readiness_check=HttpCheck(
16
+ "check-searxng",
17
+ url="http://localhost:{ctx.input.port}",
18
+ ),
19
+ ),
20
+ alias="start",
21
+ )
@@ -12,6 +12,7 @@ setup_latex_on_ubuntu = setup_latex_group.add_task(
12
12
  "texlive-fonts-extra texlive-latex-extra",
13
13
  ],
14
14
  render_cmd=False,
15
+ is_interactive=True,
15
16
  ),
16
17
  alias="ubuntu",
17
18
  )
@@ -22,7 +22,7 @@ setup_ubuntu = setup_group.add_task(
22
22
  description="🐧 Setup ubuntu",
23
23
  cmd=[
24
24
  "sudo apt install -y \\",
25
- "build-essential python3-distutils libssl-dev zlib1g-dev \\"
25
+ "build-essential libssl-dev zlib1g-dev \\"
26
26
  "libbz2-dev libreadline-dev libsqlite3-dev libpq-dev python3-dev \\",
27
27
  "llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libffi-dev \\",
28
28
  "liblzma-dev python3-openssl libblas-dev liblapack-dev rustc \\",
@@ -1,5 +1,6 @@
1
1
  from zrb.builtin.group import shell_autocomplete_group
2
- from zrb.context.context import Context
2
+ from zrb.config.config import CFG
3
+ from zrb.context.context import AnyContext
3
4
  from zrb.task.make_task import make_task
4
5
 
5
6
  _COMPLETION_SCRIPT = """
@@ -36,5 +37,5 @@ complete -F _zrb_complete zrb
36
37
  group=shell_autocomplete_group,
37
38
  alias="bash",
38
39
  )
39
- def make_bash_autocomplete(ctx: Context):
40
- return _COMPLETION_SCRIPT
40
+ def make_bash_autocomplete(ctx: AnyContext):
41
+ return _COMPLETION_SCRIPT.replace("zrb", CFG.ROOT_GROUP_NAME)
@@ -1,5 +1,6 @@
1
1
  from zrb.builtin.group import shell_autocomplete_group
2
- from zrb.context.context import Context
2
+ from zrb.config.config import CFG
3
+ from zrb.context.context import AnyContext
3
4
  from zrb.task.make_task import make_task
4
5
 
5
6
  _COMPLETION_SCRIPT = """
@@ -33,5 +34,5 @@ compdef _zrb_complete zrb
33
34
  group=shell_autocomplete_group,
34
35
  alias="zsh",
35
36
  )
36
- def make_zsh_autocomplete(ctx: Context):
37
- return _COMPLETION_SCRIPT
37
+ def make_zsh_autocomplete(ctx: AnyContext):
38
+ return _COMPLETION_SCRIPT.replace("zrb", CFG.ROOT_GROUP_NAME)
zrb/config/config.py CHANGED
@@ -24,6 +24,13 @@ class Config:
24
24
  def __init__(self):
25
25
  self.__internal_default_prompt: dict[str, str] = {}
26
26
 
27
+ @property
28
+ def ENV_PREFIX(self) -> str:
29
+ return os.getenv("_ZRB_ENV_PREFIX", "ZRB")
30
+
31
+ def _getenv(self, env_name: str, default: str = "") -> str:
32
+ return os.getenv(f"{self.ENV_PREFIX}_{env_name}", default)
33
+
27
34
  def _get_internal_default_prompt(self, name: str) -> str:
28
35
  if name not in self.__internal_default_prompt:
29
36
  file_path = os.path.join(
@@ -39,7 +46,7 @@ class Config:
39
46
 
40
47
  @property
41
48
  def DEFAULT_SHELL(self) -> str:
42
- return os.getenv("ZRB_SHELL", self._get_current_shell())
49
+ return self._getenv("SHELL", self._get_current_shell())
43
50
 
44
51
  def _get_current_shell(self) -> str:
45
52
  if platform.system() == "Windows":
@@ -51,11 +58,43 @@ class Config:
51
58
 
52
59
  @property
53
60
  def DEFAULT_EDITOR(self) -> str:
54
- return os.getenv("ZRB_EDITOR", "nano")
61
+ return self._getenv("EDITOR", "nano")
62
+
63
+ @property
64
+ def DEFAULT_DIFF_EDIT_COMMAND_TPL(self) -> str:
65
+ return self._getenv("DIFF_EDIT_COMMAND", self._get_default_diff_edit_command())
66
+
67
+ def _get_default_diff_edit_command(self) -> str:
68
+ editor = self.DEFAULT_EDITOR
69
+ if editor in [
70
+ "code",
71
+ "vscode",
72
+ "vscodium",
73
+ "windsurf",
74
+ "cursor",
75
+ "zed",
76
+ "zeditor",
77
+ "agy",
78
+ ]:
79
+ return f"{editor} --wait --diff {{old}} {{new}}"
80
+ if editor == "emacs":
81
+ return 'emacs --eval \'(ediff-files "{old}" "{new}")\''
82
+ if editor in ["nvim", "vim"]:
83
+ return (
84
+ f"{editor} -d {{old}} {{new}} "
85
+ "-i NONE "
86
+ '-c "wincmd h | set readonly | wincmd l" '
87
+ '-c "highlight DiffAdd cterm=bold ctermbg=22 guibg=#005f00 | highlight DiffChange cterm=bold ctermbg=24 guibg=#005f87 | highlight DiffText ctermbg=21 guibg=#0000af | highlight DiffDelete ctermbg=52 guibg=#5f0000" ' # noqa
88
+ '-c "set showtabline=2 | set tabline=[Instructions]\\ :wqa(save\\ &\\ quit)\\ \\|\\ i/esc(toggle\\ edit\\ mode)" ' # noqa
89
+ '-c "wincmd h | setlocal statusline=OLD\\ FILE" '
90
+ '-c "wincmd l | setlocal statusline=%#StatusBold#NEW\\ FILE\\ :wqa(save\\ &\\ quit)\\ \\|\\ i/esc(toggle\\ edit\\ mode)" ' # noqa
91
+ '-c "autocmd BufWritePost * wqa"'
92
+ )
93
+ return 'vimdiff {old} {new} +"setlocal ro" +"wincmd l" +"autocmd BufWritePost <buffer> qa"' # noqa
55
94
 
56
95
  @property
57
96
  def INIT_MODULES(self) -> list[str]:
58
- init_modules_str = os.getenv("ZRB_INIT_MODULES", "")
97
+ init_modules_str = self._getenv("INIT_MODULES", "")
59
98
  if init_modules_str != "":
60
99
  return [
61
100
  module.strip()
@@ -66,15 +105,15 @@ class Config:
66
105
 
67
106
  @property
68
107
  def ROOT_GROUP_NAME(self) -> str:
69
- return os.getenv("ZRB_ROOT_GROUP_NAME", "zrb")
108
+ return self._getenv("ROOT_GROUP_NAME", "zrb")
70
109
 
71
110
  @property
72
111
  def ROOT_GROUP_DESCRIPTION(self) -> str:
73
- return os.getenv("ZRB_ROOT_GROUP_DESCRIPTION", "Your Automation Powerhouse")
112
+ return self._getenv("ROOT_GROUP_DESCRIPTION", "Your Automation Powerhouse")
74
113
 
75
114
  @property
76
115
  def INIT_SCRIPTS(self) -> list[str]:
77
- init_scripts_str = os.getenv("ZRB_INIT_SCRIPTS", "")
116
+ init_scripts_str = self._getenv("INIT_SCRIPTS", "")
78
117
  if init_scripts_str != "":
79
118
  return [
80
119
  script.strip()
@@ -85,16 +124,17 @@ class Config:
85
124
 
86
125
  @property
87
126
  def INIT_FILE_NAME(self) -> str:
88
- return os.getenv("ZRB_INIT_FILE_NAME", "zrb_init.py")
127
+ return self._getenv("INIT_FILE_NAME", "zrb_init.py")
89
128
 
90
129
  @property
91
130
  def LOGGING_LEVEL(self) -> int:
92
- return self._get_log_level(os.getenv("ZRB_LOGGING_LEVEL", "WARNING"))
131
+ return self._get_log_level(self._getenv("LOGGING_LEVEL", "WARNING"))
93
132
 
94
133
  def _get_log_level(self, level: str) -> int:
95
134
  level = level.upper()
96
135
  log_levels = {
97
136
  "CRITICAL": logging.CRITICAL, # 50
137
+ "FATAL": logging.CRITICAL, # 50
98
138
  "ERROR": logging.ERROR, # 40
99
139
  "WARN": logging.WARNING, # 30
100
140
  "WARNING": logging.WARNING, # 30
@@ -108,11 +148,11 @@ class Config:
108
148
 
109
149
  @property
110
150
  def LOAD_BUILTIN(self) -> bool:
111
- return to_boolean(os.getenv("ZRB_LOAD_BUILTIN", "1"))
151
+ return to_boolean(self._getenv("LOAD_BUILTIN", "1"))
112
152
 
113
153
  @property
114
154
  def WARN_UNRECOMMENDED_COMMAND(self) -> bool:
115
- return to_boolean(os.getenv("ZRB_WARN_UNRECOMMENDED_COMMAND", "1"))
155
+ return to_boolean(self._getenv("WARN_UNRECOMMENDED_COMMAND", "1"))
116
156
 
117
157
  @property
118
158
  def SESSION_LOG_DIR(self) -> str:
@@ -122,15 +162,15 @@ class Config:
122
162
 
123
163
  @property
124
164
  def TODO_DIR(self) -> str:
125
- return os.getenv("ZRB_TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
165
+ return self._getenv("TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
126
166
 
127
167
  @property
128
168
  def TODO_VISUAL_FILTER(self) -> str:
129
- return os.getenv("ZRB_TODO_FILTER", "")
169
+ return self._getenv("TODO_FILTER", "")
130
170
 
131
171
  @property
132
172
  def TODO_RETENTION(self) -> str:
133
- return os.getenv("ZRB_TODO_RETENTION", "2w")
173
+ return self._getenv("TODO_RETENTION", "2w")
134
174
 
135
175
  @property
136
176
  def VERSION(self) -> str:
@@ -141,7 +181,7 @@ class Config:
141
181
 
142
182
  @property
143
183
  def WEB_CSS_PATH(self) -> list[str]:
144
- web_css_path_str = os.getenv("ZRB_WEB_CSS_PATH", "")
184
+ web_css_path_str = self._getenv("WEB_CSS_PATH", "")
145
185
  if web_css_path_str != "":
146
186
  return [
147
187
  path.strip()
@@ -152,7 +192,7 @@ class Config:
152
192
 
153
193
  @property
154
194
  def WEB_JS_PATH(self) -> list[str]:
155
- web_js_path_str = os.getenv("ZRB_WEB_JS_PATH", "")
195
+ web_js_path_str = self._getenv("WEB_JS_PATH", "")
156
196
  if web_js_path_str != "":
157
197
  return [
158
198
  path.strip()
@@ -163,103 +203,140 @@ class Config:
163
203
 
164
204
  @property
165
205
  def WEB_FAVICON_PATH(self) -> str:
166
- return os.getenv("ZRB_WEB_FAVICON_PATH", "/static/favicon-32x32.png")
206
+ return self._getenv("WEB_FAVICON_PATH", "/static/favicon-32x32.png")
167
207
 
168
208
  @property
169
209
  def WEB_COLOR(self) -> str:
170
- return os.getenv("ZRB_WEB_COLOR", "")
210
+ return self._getenv("WEB_COLOR", "")
171
211
 
172
212
  @property
173
213
  def WEB_HTTP_PORT(self) -> int:
174
- return int(os.getenv("ZRB_WEB_HTTP_PORT", "21213"))
214
+ return int(self._getenv("WEB_HTTP_PORT", "21213"))
175
215
 
176
216
  @property
177
217
  def WEB_GUEST_USERNAME(self) -> str:
178
- return os.getenv("ZRB_WEB_GUEST_USERNAME", "user")
218
+ return self._getenv("WEB_GUEST_USERNAME", "user")
179
219
 
180
220
  @property
181
221
  def WEB_SUPER_ADMIN_USERNAME(self) -> str:
182
- return os.getenv("ZRB_WEB_SUPER_ADMIN_USERNAME", "admin")
222
+ return self._getenv("WEB_SUPER_ADMIN_USERNAME", "admin")
183
223
 
184
224
  @property
185
225
  def WEB_SUPER_ADMIN_PASSWORD(self) -> str:
186
- return os.getenv("ZRB_WEB_SUPER_ADMIN_PASSWORD", "admin")
226
+ return self._getenv("WEB_SUPER_ADMIN_PASSWORD", "admin")
187
227
 
188
228
  @property
189
229
  def WEB_ACCESS_TOKEN_COOKIE_NAME(self) -> str:
190
- return os.getenv("ZRB_WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token")
230
+ return self._getenv("WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token")
191
231
 
192
232
  @property
193
233
  def WEB_REFRESH_TOKEN_COOKIE_NAME(self) -> str:
194
- return os.getenv("ZRB_WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token")
234
+ return self._getenv("WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token")
195
235
 
196
236
  @property
197
237
  def WEB_SECRET_KEY(self) -> str:
198
- return os.getenv("ZRB_WEB_SECRET", "zrb")
238
+ return self._getenv("WEB_SECRET", "zrb")
199
239
 
200
240
  @property
201
241
  def WEB_ENABLE_AUTH(self) -> bool:
202
- return to_boolean(os.getenv("ZRB_WEB_ENABLE_AUTH", "0"))
242
+ return to_boolean(self._getenv("WEB_ENABLE_AUTH", "0"))
203
243
 
204
244
  @property
205
245
  def WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES(self) -> int:
206
- return int(os.getenv("ZRB_WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
246
+ return int(self._getenv("WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
207
247
 
208
248
  @property
209
249
  def WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES(self) -> int:
210
- return int(os.getenv("ZRB_WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60"))
250
+ return int(self._getenv("WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60"))
211
251
 
212
252
  @property
213
253
  def WEB_TITLE(self) -> str:
214
- return os.getenv("ZRB_WEB_TITLE", "Zrb")
254
+ return self._getenv("WEB_TITLE", "Zrb")
215
255
 
216
256
  @property
217
257
  def WEB_JARGON(self) -> str:
218
- return os.getenv("ZRB_WEB_JARGON", "Your Automation PowerHouse")
258
+ return self._getenv("WEB_JARGON", "Your Automation PowerHouse")
219
259
 
220
260
  @property
221
261
  def WEB_HOMEPAGE_INTRO(self) -> str:
222
- return os.getenv("ZRB_WEB_HOMEPAGE_INTRO", "Welcome to Zrb Web Interface")
262
+ return self._getenv("WEB_HOMEPAGE_INTRO", "Welcome to Zrb Web Interface")
223
263
 
224
264
  @property
225
265
  def LLM_MODEL(self) -> str | None:
226
- return os.getenv("ZRB_LLM_MODEL", None)
266
+ value = self._getenv("LLM_MODEL")
267
+ return None if value == "" else value
227
268
 
228
269
  @property
229
270
  def LLM_BASE_URL(self) -> str | None:
230
- return os.getenv("ZRB_LLM_BASE_URL", None)
271
+ value = self._getenv("LLM_BASE_URL")
272
+ return None if value == "" else value
231
273
 
232
274
  @property
233
275
  def LLM_API_KEY(self) -> str | None:
234
- return os.getenv("ZRB_LLM_API_KEY", None)
276
+ value = self._getenv("LLM_API_KEY")
277
+ return None if value == "" else value
278
+
279
+ @property
280
+ def LLM_MODEL_SMALL(self) -> str | None:
281
+ value = self._getenv("LLM_MODEL_SMALL")
282
+ return None if value == "" else value
283
+
284
+ @property
285
+ def LLM_BASE_URL_SMALL(self) -> str | None:
286
+ value = self._getenv("LLM_BASE_URL_SMALL")
287
+ return None if value == "" else value
288
+
289
+ @property
290
+ def LLM_API_KEY_SMALL(self) -> str | None:
291
+ value = self._getenv("LLM_API_KEY_SMALL")
292
+ return None if value == "" else value
235
293
 
236
294
  @property
237
295
  def LLM_SYSTEM_PROMPT(self) -> str | None:
238
- return os.getenv("ZRB_LLM_SYSTEM_PROMPT", None)
296
+ value = self._getenv("LLM_SYSTEM_PROMPT")
297
+ return None if value == "" else value
239
298
 
240
299
  @property
241
300
  def LLM_INTERACTIVE_SYSTEM_PROMPT(self) -> str | None:
242
- return os.getenv("ZRB_LLM_INTERACTIVE_SYSTEM_PROMPT", None)
301
+ value = self._getenv("LLM_INTERACTIVE_SYSTEM_PROMPT")
302
+ return None if value == "" else value
243
303
 
244
304
  @property
245
305
  def LLM_PERSONA(self) -> str | None:
246
- return os.getenv("ZRB_LLM_PERSONA", None)
306
+ value = self._getenv("LLM_PERSONA")
307
+ return None if value == "" else value
247
308
 
248
309
  @property
249
- def LLM_MODES(self) -> list[str]:
250
- return [
251
- mode.strip()
252
- for mode in os.getenv("ZRB_LLM_MODES", "coding").split(",")
253
- if mode.strip() != ""
254
- ]
310
+ def LLM_WORKFLOWS(self) -> list[str]:
311
+ """Get a list of LLM workflows from environment variables."""
312
+ workflows = []
313
+ for workflow in self._getenv("LLM_WORKFLOWS", "").split(","):
314
+ workflow = workflow.strip()
315
+ if workflow != "":
316
+ workflows.append(workflow)
317
+ return workflows
318
+
319
+ @property
320
+ def LLM_BUILTIN_WORKFLOW_PATHS(self) -> list[str]:
321
+ """Get a list of additional builtin workflow paths from environment variables."""
322
+ builtin_workflow_paths_str = self._getenv("LLM_BUILTIN_WORKFLOW_PATHS", "")
323
+ if builtin_workflow_paths_str != "":
324
+ return [
325
+ path.strip()
326
+ for path in builtin_workflow_paths_str.split(":")
327
+ if path.strip() != ""
328
+ ]
329
+ return []
255
330
 
256
331
  @property
257
332
  def LLM_SPECIAL_INSTRUCTION_PROMPT(self) -> str | None:
258
- return os.getenv("ZRB_LLM_SPECIAL_INSTRUCTION_PROMPT", None)
333
+ value = self._getenv("LLM_SPECIAL_INSTRUCTION_PROMPT")
334
+ return None if value == "" else value
259
335
 
260
336
  @property
261
337
  def LLM_SUMMARIZATION_PROMPT(self) -> str | None:
262
- return os.getenv("ZRB_LLM_SUMMARIZATION_PROMPT", None)
338
+ value = self._getenv("LLM_SUMMARIZATION_PROMPT")
339
+ return None if value == "" else value
263
340
 
264
341
  @property
265
342
  def LLM_MAX_REQUESTS_PER_MINUTE(self) -> int:
@@ -267,7 +344,7 @@ class Config:
267
344
  Maximum number of LLM requests allowed per minute.
268
345
  Default is conservative to accommodate free-tier LLM providers.
269
346
  """
270
- return int(os.getenv("LLM_MAX_REQUESTS_PER_MINUTE", "15"))
347
+ return int(self._getenv("LLM_MAX_REQUESTS_PER_MINUTE", "60"))
271
348
 
272
349
  @property
273
350
  def LLM_MAX_TOKENS_PER_MINUTE(self) -> int:
@@ -275,122 +352,222 @@ class Config:
275
352
  Maximum number of LLM tokens allowed per minute.
276
353
  Default is conservative to accommodate free-tier LLM providers.
277
354
  """
278
- return int(os.getenv("ZRB_LLM_MAX_TOKENS_PER_MINUTE", "100000"))
355
+ return int(self._getenv("LLM_MAX_TOKENS_PER_MINUTE", "100000"))
279
356
 
280
357
  @property
281
358
  def LLM_MAX_TOKENS_PER_REQUEST(self) -> int:
282
359
  """Maximum number of tokens allowed per individual LLM request."""
283
- return int(os.getenv("ZRB_LLM_MAX_TOKENS_PER_REQUEST", "50000"))
360
+ return int(self._getenv("LLM_MAX_TOKENS_PER_REQUEST", "100000"))
361
+
362
+ @property
363
+ def LLM_MAX_TOKENS_PER_TOOL_CALL_RESULT(self) -> int:
364
+ """Maximum number of tokens allowed per tool call result."""
365
+ return int(self._getenv("LLM_MAX_TOKENS_PER_TOOL_CALL_RESULT", "75000"))
284
366
 
285
367
  @property
286
368
  def LLM_THROTTLE_SLEEP(self) -> float:
287
369
  """Number of seconds to sleep when throttling is required."""
288
- return float(os.getenv("ZRB_LLM_THROTTLE_SLEEP", "1.0"))
370
+ return float(self._getenv("LLM_THROTTLE_SLEEP", "5.0"))
289
371
 
290
372
  @property
291
- def LLM_YOLO_MODE(self) -> bool:
292
- return to_boolean(os.getenv("ZRB_LLM_YOLO_MODE", "false"))
373
+ def LLM_YOLO_MODE(self) -> bool | list[str]:
374
+ str_val = self._getenv("LLM_YOLO_MODE", "false")
375
+ try:
376
+ return to_boolean(str_val)
377
+ except Exception:
378
+ return [val.strip() for val in str_val.split(",") if val.strip() != ""]
293
379
 
294
380
  @property
295
381
  def LLM_SUMMARIZE_HISTORY(self) -> bool:
296
- return to_boolean(os.getenv("ZRB_LLM_SUMMARIZE_HISTORY", "true"))
382
+ return to_boolean(self._getenv("LLM_SUMMARIZE_HISTORY", "true"))
297
383
 
298
384
  @property
299
385
  def LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
300
- return int(os.getenv("ZRB_LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD", "20000"))
386
+ threshold = int(
387
+ self._getenv("LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD", "20000")
388
+ )
389
+ return self._limit_token_threshold(threshold)
301
390
 
302
391
  @property
303
392
  def LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD(self) -> int:
304
- return int(os.getenv("ZRB_LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_LIMIT", "35000"))
393
+ threshold = int(
394
+ self._getenv("LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_LIMIT", "50000")
395
+ )
396
+ return self._limit_token_threshold(threshold)
305
397
 
306
398
  @property
307
399
  def LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
308
- return int(
309
- os.getenv("ZRB_LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_LIMIT", "35000")
400
+ threshold = int(
401
+ self._getenv("LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_LIMIT", "20000")
402
+ )
403
+ min(
404
+ threshold,
405
+ self.LLM_MAX_TOKENS_PER_MINUTE // 2,
406
+ self.LLM_MAX_TOKENS_PER_REQUEST // 2,
310
407
  )
408
+ return self._limit_token_threshold(threshold)
311
409
 
312
410
  @property
313
411
  def LLM_FILE_ANALYSIS_TOKEN_LIMIT(self) -> int:
314
- return int(os.getenv("ZRB_LLM_FILE_ANALYSIS_TOKEN_LIMIT", "35000"))
412
+ threshold = int(self._getenv("LLM_FILE_ANALYSIS_TOKEN_LIMIT", "50000"))
413
+ return self._limit_token_threshold(threshold)
414
+
415
+ def _limit_token_threshold(self, threshold: int) -> int:
416
+ return min(
417
+ threshold,
418
+ self.LLM_MAX_TOKENS_PER_MINUTE // 2,
419
+ self.LLM_MAX_TOKENS_PER_REQUEST // 2,
420
+ )
315
421
 
316
422
  @property
317
423
  def LLM_FILE_EXTRACTOR_SYSTEM_PROMPT(self) -> str:
318
- return os.getenv(
319
- "ZRB_LLM_FILE_EXTRACTOR_SYSTEM_PROMPT",
424
+ return self._getenv(
425
+ "LLM_FILE_EXTRACTOR_SYSTEM_PROMPT",
320
426
  self._get_internal_default_prompt("file_extractor_system_prompt"),
321
427
  )
322
428
 
323
429
  @property
324
430
  def LLM_REPO_EXTRACTOR_SYSTEM_PROMPT(self) -> str:
325
- return os.getenv(
326
- "ZRB_LLM_REPO_EXTRACTOR_SYSTEM_PROMPT",
431
+ return self._getenv(
432
+ "LLM_REPO_EXTRACTOR_SYSTEM_PROMPT",
327
433
  self._get_internal_default_prompt("repo_extractor_system_prompt"),
328
434
  )
329
435
 
330
436
  @property
331
437
  def LLM_REPO_SUMMARIZER_SYSTEM_PROMPT(self) -> str:
332
- return os.getenv(
333
- "ZRB_LLM_REPO_SUMMARIZER_SYSTEM_PROMPT",
438
+ return self._getenv(
439
+ "LLM_REPO_SUMMARIZER_SYSTEM_PROMPT",
334
440
  self._get_internal_default_prompt("repo_summarizer_system_prompt"),
335
441
  )
336
442
 
337
443
  @property
338
444
  def LLM_HISTORY_DIR(self) -> str:
339
- return os.getenv(
340
- "ZRB_LLM_HISTORY_DIR",
445
+ return self._getenv(
446
+ "LLM_HISTORY_DIR",
341
447
  os.path.expanduser(os.path.join("~", ".zrb-llm-history")),
342
448
  )
343
449
 
344
450
  @property
345
451
  def LLM_ALLOW_ACCESS_LOCAL_FILE(self) -> bool:
346
- return to_boolean(os.getenv("ZRB_LLM_ACCESS_LOCAL_FILE", "1"))
452
+ return to_boolean(self._getenv("LLM_ALLOW_ACCESS_LOCAL_FILE", "1"))
453
+
454
+ @property
455
+ def LLM_ALLOW_ANALYZE_FILE(self) -> bool:
456
+ return to_boolean(self._getenv("LLM_ALLOW_ANALYZE_LOCAL_FILE", "1"))
457
+
458
+ @property
459
+ def LLM_ALLOW_ANALYZE_REPO(self) -> bool:
460
+ return to_boolean(self._getenv("LLM_ALLOW_ANALYZE_REPO", "1"))
347
461
 
348
462
  @property
349
463
  def LLM_ALLOW_ACCESS_SHELL(self) -> bool:
350
- return to_boolean(os.getenv("ZRB_LLM_ACCESS_SHELL", "1"))
464
+ return to_boolean(self._getenv("LLM_ALLOW_ACCESS_SHELL", "1"))
351
465
 
352
466
  @property
353
- def LLM_ALLOW_ACCESS_INTERNET(self) -> bool:
354
- return to_boolean(os.getenv("ZRB_LLM_ACCESS_INTERNET", "1"))
467
+ def LLM_ALLOW_OPEN_WEB_PAGE(self) -> bool:
468
+ return to_boolean(self._getenv("LLM_ALLOW_OPEN_WEB_PAGE", "1"))
355
469
 
356
470
  @property
357
- def RAG_EMBEDDING_API_KEY(self) -> str:
358
- return os.getenv("ZRB_RAG_EMBEDDING_API_KEY", None)
471
+ def LLM_ALLOW_SEARCH_INTERNET(self) -> bool:
472
+ return to_boolean(self._getenv("LLM_ALLOW_SEARCH_INTERNET", "1"))
359
473
 
360
474
  @property
361
- def RAG_EMBEDDING_BASE_URL(self) -> str:
362
- return os.getenv("ZRB_RAG_EMBEDDING_BASE_URL", None)
475
+ def LLM_ALLOW_GET_CURRENT_LOCATION(self) -> bool:
476
+ return to_boolean(self._getenv("LLM_ALLOW_GET_CURRENT_LOCATION", "1"))
477
+
478
+ @property
479
+ def LLM_ALLOW_GET_CURRENT_WEATHER(self) -> bool:
480
+ return to_boolean(self._getenv("LLM_ALLOW_GET_CURRENT_WEATHER", "1"))
481
+
482
+ @property
483
+ def RAG_EMBEDDING_API_KEY(self) -> str | None:
484
+ value = self._getenv("RAG_EMBEDDING_API_KEY")
485
+ return None if value == "" else value
486
+
487
+ @property
488
+ def RAG_EMBEDDING_BASE_URL(self) -> str | None:
489
+ value = self._getenv("RAG_EMBEDDING_BASE_URL")
490
+ return None if value == "" else value
363
491
 
364
492
  @property
365
493
  def RAG_EMBEDDING_MODEL(self) -> str:
366
- return os.getenv("ZRB_RAG_EMBEDDING_MODEL", "text-embedding-ada-002")
494
+ return self._getenv("RAG_EMBEDDING_MODEL", "text-embedding-ada-002")
367
495
 
368
496
  @property
369
497
  def RAG_CHUNK_SIZE(self) -> int:
370
- return int(os.getenv("ZRB_RAG_CHUNK_SIZE", "1024"))
498
+ return int(self._getenv("RAG_CHUNK_SIZE", "1024"))
371
499
 
372
500
  @property
373
501
  def RAG_OVERLAP(self) -> int:
374
- return int(os.getenv("ZRB_RAG_OVERLAP", "128"))
502
+ return int(self._getenv("RAG_OVERLAP", "128"))
375
503
 
376
504
  @property
377
505
  def RAG_MAX_RESULT_COUNT(self) -> int:
378
- return int(os.getenv("ZRB_RAG_MAX_RESULT_COUNT", "5"))
506
+ return int(self._getenv("RAG_MAX_RESULT_COUNT", "5"))
507
+
508
+ @property
509
+ def SEARCH_INTERNET_METHOD(self) -> str:
510
+ """Either serpapi or searxng"""
511
+ return self._getenv("SEARCH_INTERNET_METHOD", "serpapi")
512
+
513
+ @property
514
+ def BRAVE_API_KEY(self) -> str:
515
+ return os.getenv("BRAVE_API_KEY", "")
516
+
517
+ @property
518
+ def BRAVE_API_SAFE(self) -> str:
519
+ return self._getenv("BRAVE_API_SAFE", "off")
520
+
521
+ @property
522
+ def BRAVE_API_LANG(self) -> str:
523
+ return self._getenv("BRAVE_API_LANG", "en")
379
524
 
380
525
  @property
381
526
  def SERPAPI_KEY(self) -> str:
382
527
  return os.getenv("SERPAPI_KEY", "")
383
528
 
529
+ @property
530
+ def SERPAPI_SAFE(self) -> str:
531
+ return self._getenv("SERPAPI_SAFE", "off")
532
+
533
+ @property
534
+ def SERPAPI_LANG(self) -> str:
535
+ return self._getenv("SERPAPI_LANG", "en")
536
+
537
+ @property
538
+ def SEARXNG_PORT(self) -> int:
539
+ return int(self._getenv("SEARXNG_PORT", "8080"))
540
+
541
+ @property
542
+ def SEARXNG_BASE_URL(self) -> str:
543
+ return self._getenv("SEARXNG_BASE_URL", f"http://localhost:{self.SEARXNG_PORT}")
544
+
545
+ @property
546
+ def SEARXNG_SAFE(self) -> int:
547
+ return int(self._getenv("SEARXNG_SAFE", "0"))
548
+
549
+ @property
550
+ def SEARXNG_LANG(self) -> str:
551
+ return self._getenv("SEARXNG_LANG", "en")
552
+
384
553
  @property
385
554
  def BANNER(self) -> str:
386
555
  return fstring_format(
387
- os.getenv("ZRB_BANNER", _DEFAULT_BANNER),
556
+ self._getenv("BANNER", _DEFAULT_BANNER),
388
557
  {"VERSION": self.VERSION},
389
558
  )
390
559
 
391
560
  @property
392
561
  def LLM_CONTEXT_FILE(self) -> str:
393
- return os.getenv("LLM_CONTEXT_FILE", "ZRB.md")
562
+ return self._getenv("LLM_CONTEXT_FILE", "ZRB.md")
563
+
564
+ @property
565
+ def USE_TIKTOKEN(self) -> bool:
566
+ return to_boolean(self._getenv("USE_TIKTOKEN", "true"))
567
+
568
+ @property
569
+ def TIKTOKEN_ENCODING_NAME(self) -> str:
570
+ return self._getenv("TIKTOKEN_ENCODING_NAME", "cl100k_base")
394
571
 
395
572
 
396
573
  CFG = Config()