zrb 1.8.10__py3-none-any.whl → 1.21.29__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.

Potentially problematic release.


This version of zrb might be problematic. Click here for more details.

Files changed (147) hide show
  1. zrb/__init__.py +126 -113
  2. zrb/__main__.py +1 -1
  3. zrb/attr/type.py +10 -7
  4. zrb/builtin/__init__.py +2 -50
  5. zrb/builtin/git.py +12 -1
  6. zrb/builtin/group.py +31 -15
  7. zrb/builtin/http.py +7 -8
  8. zrb/builtin/llm/attachment.py +40 -0
  9. zrb/builtin/llm/chat_completion.py +274 -0
  10. zrb/builtin/llm/chat_session.py +152 -85
  11. zrb/builtin/llm/chat_session_cmd.py +288 -0
  12. zrb/builtin/llm/chat_trigger.py +79 -0
  13. zrb/builtin/llm/history.py +7 -9
  14. zrb/builtin/llm/llm_ask.py +221 -98
  15. zrb/builtin/llm/tool/api.py +74 -52
  16. zrb/builtin/llm/tool/cli.py +46 -17
  17. zrb/builtin/llm/tool/code.py +71 -90
  18. zrb/builtin/llm/tool/file.py +301 -241
  19. zrb/builtin/llm/tool/note.py +84 -0
  20. zrb/builtin/llm/tool/rag.py +38 -8
  21. zrb/builtin/llm/tool/sub_agent.py +67 -50
  22. zrb/builtin/llm/tool/web.py +146 -122
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  25. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  26. zrb/builtin/searxng/config/settings.yml +5671 -0
  27. zrb/builtin/searxng/start.py +21 -0
  28. zrb/builtin/setup/latex/ubuntu.py +1 -0
  29. zrb/builtin/setup/ubuntu.py +1 -1
  30. zrb/builtin/shell/autocomplete/bash.py +4 -3
  31. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  32. zrb/builtin/todo.py +13 -2
  33. zrb/config/config.py +614 -0
  34. zrb/config/default_prompt/file_extractor_system_prompt.md +112 -0
  35. zrb/config/default_prompt/interactive_system_prompt.md +29 -0
  36. zrb/config/default_prompt/persona.md +1 -0
  37. zrb/config/default_prompt/repo_extractor_system_prompt.md +112 -0
  38. zrb/config/default_prompt/repo_summarizer_system_prompt.md +29 -0
  39. zrb/config/default_prompt/summarization_prompt.md +57 -0
  40. zrb/config/default_prompt/system_prompt.md +38 -0
  41. zrb/config/llm_config.py +339 -0
  42. zrb/config/llm_context/config.py +166 -0
  43. zrb/config/llm_context/config_parser.py +40 -0
  44. zrb/config/llm_context/workflow.py +81 -0
  45. zrb/config/llm_rate_limitter.py +190 -0
  46. zrb/{runner → config}/web_auth_config.py +17 -22
  47. zrb/context/any_shared_context.py +17 -1
  48. zrb/context/context.py +16 -2
  49. zrb/context/shared_context.py +18 -8
  50. zrb/group/any_group.py +12 -5
  51. zrb/group/group.py +67 -3
  52. zrb/input/any_input.py +5 -1
  53. zrb/input/base_input.py +18 -6
  54. zrb/input/option_input.py +13 -1
  55. zrb/input/text_input.py +8 -25
  56. zrb/runner/cli.py +25 -23
  57. zrb/runner/common_util.py +24 -19
  58. zrb/runner/web_app.py +3 -3
  59. zrb/runner/web_route/docs_route.py +1 -1
  60. zrb/runner/web_route/error_page/serve_default_404.py +1 -1
  61. zrb/runner/web_route/error_page/show_error_page.py +1 -1
  62. zrb/runner/web_route/home_page/home_page_route.py +2 -2
  63. zrb/runner/web_route/login_api_route.py +1 -1
  64. zrb/runner/web_route/login_page/login_page_route.py +2 -2
  65. zrb/runner/web_route/logout_api_route.py +1 -1
  66. zrb/runner/web_route/logout_page/logout_page_route.py +2 -2
  67. zrb/runner/web_route/node_page/group/show_group_page.py +1 -1
  68. zrb/runner/web_route/node_page/node_page_route.py +1 -1
  69. zrb/runner/web_route/node_page/task/show_task_page.py +1 -1
  70. zrb/runner/web_route/refresh_token_api_route.py +1 -1
  71. zrb/runner/web_route/static/static_route.py +1 -1
  72. zrb/runner/web_route/task_input_api_route.py +6 -6
  73. zrb/runner/web_route/task_session_api_route.py +20 -12
  74. zrb/runner/web_util/cookie.py +1 -1
  75. zrb/runner/web_util/token.py +1 -1
  76. zrb/runner/web_util/user.py +8 -4
  77. zrb/session/any_session.py +24 -17
  78. zrb/session/session.py +50 -25
  79. zrb/session_state_logger/any_session_state_logger.py +9 -4
  80. zrb/session_state_logger/file_session_state_logger.py +16 -6
  81. zrb/session_state_logger/session_state_logger_factory.py +1 -1
  82. zrb/task/any_task.py +30 -9
  83. zrb/task/base/context.py +17 -9
  84. zrb/task/base/execution.py +15 -8
  85. zrb/task/base/lifecycle.py +8 -4
  86. zrb/task/base/monitoring.py +12 -7
  87. zrb/task/base_task.py +69 -5
  88. zrb/task/base_trigger.py +12 -5
  89. zrb/task/cmd_task.py +1 -1
  90. zrb/task/llm/agent.py +154 -161
  91. zrb/task/llm/agent_runner.py +152 -0
  92. zrb/task/llm/config.py +47 -18
  93. zrb/task/llm/conversation_history.py +209 -0
  94. zrb/task/llm/conversation_history_model.py +67 -0
  95. zrb/task/llm/default_workflow/coding/workflow.md +41 -0
  96. zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
  97. zrb/task/llm/default_workflow/git/workflow.md +118 -0
  98. zrb/task/llm/default_workflow/golang/workflow.md +128 -0
  99. zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
  100. zrb/task/llm/default_workflow/java/workflow.md +146 -0
  101. zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
  102. zrb/task/llm/default_workflow/python/workflow.md +160 -0
  103. zrb/task/llm/default_workflow/researching/workflow.md +153 -0
  104. zrb/task/llm/default_workflow/rust/workflow.md +162 -0
  105. zrb/task/llm/default_workflow/shell/workflow.md +299 -0
  106. zrb/task/llm/error.py +24 -10
  107. zrb/task/llm/file_replacement.py +206 -0
  108. zrb/task/llm/file_tool_model.py +57 -0
  109. zrb/task/llm/history_processor.py +206 -0
  110. zrb/task/llm/history_summarization.py +11 -166
  111. zrb/task/llm/print_node.py +193 -69
  112. zrb/task/llm/prompt.py +242 -45
  113. zrb/task/llm/subagent_conversation_history.py +41 -0
  114. zrb/task/llm/tool_wrapper.py +260 -57
  115. zrb/task/llm/workflow.py +76 -0
  116. zrb/task/llm_task.py +182 -171
  117. zrb/task/make_task.py +2 -3
  118. zrb/task/rsync_task.py +26 -11
  119. zrb/task/scheduler.py +4 -4
  120. zrb/util/attr.py +54 -39
  121. zrb/util/callable.py +23 -0
  122. zrb/util/cli/markdown.py +12 -0
  123. zrb/util/cli/text.py +30 -0
  124. zrb/util/file.py +29 -11
  125. zrb/util/git.py +8 -11
  126. zrb/util/git_diff_model.py +10 -0
  127. zrb/util/git_subtree.py +9 -14
  128. zrb/util/git_subtree_model.py +32 -0
  129. zrb/util/init_path.py +1 -1
  130. zrb/util/markdown.py +62 -0
  131. zrb/util/string/conversion.py +2 -2
  132. zrb/util/todo.py +17 -50
  133. zrb/util/todo_model.py +46 -0
  134. zrb/util/truncate.py +23 -0
  135. zrb/util/yaml.py +204 -0
  136. zrb/xcom/xcom.py +10 -0
  137. zrb-1.21.29.dist-info/METADATA +270 -0
  138. {zrb-1.8.10.dist-info → zrb-1.21.29.dist-info}/RECORD +140 -98
  139. {zrb-1.8.10.dist-info → zrb-1.21.29.dist-info}/WHEEL +1 -1
  140. zrb/config.py +0 -335
  141. zrb/llm_config.py +0 -411
  142. zrb/llm_rate_limitter.py +0 -125
  143. zrb/task/llm/context.py +0 -102
  144. zrb/task/llm/context_enrichment.py +0 -199
  145. zrb/task/llm/history.py +0 -211
  146. zrb-1.8.10.dist-info/METADATA +0 -264
  147. {zrb-1.8.10.dist-info → zrb-1.21.29.dist-info}/entry_points.txt +0 -0
zrb/config/config.py ADDED
@@ -0,0 +1,614 @@
1
+ import importlib.metadata as metadata
2
+ import logging
3
+ import os
4
+ import platform
5
+
6
+ from zrb.util.string.conversion import to_boolean
7
+ from zrb.util.string.format import fstring_format
8
+
9
+ _DEFAULT_BANNER = """
10
+ bb
11
+ zzzzz rr rr bb
12
+ zz rrr r bbbbbb
13
+ zz rr bb bb
14
+ zzzzz rr bbbbbb {VERSION} Janggala
15
+ _ _ . . . _ . _ . . .
16
+ Your Automation Powerhouse
17
+ ☕ Donate at: https://stalchmst.com
18
+ 🐙 Submit issues/PR at: https://github.com/state-alchemists/zrb
19
+ 🐤 Follow us at: https://twitter.com/zarubastalchmst
20
+ """
21
+
22
+
23
+ class Config:
24
+ def __init__(self):
25
+ self.__internal_default_prompt: dict[str, str] = {}
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 | list[str], default: str = "") -> str:
32
+ env_name_list = env_name if isinstance(env_name, list) else [env_name]
33
+ for env_name in env_name_list:
34
+ value = os.getenv(f"{self.ENV_PREFIX}_{env_name}", None)
35
+ if value is not None:
36
+ return value
37
+ return default
38
+
39
+ def _get_internal_default_prompt(self, name: str) -> str:
40
+ if name not in self.__internal_default_prompt:
41
+ file_path = os.path.join(
42
+ os.path.dirname(__file__), "default_prompt", f"{name}.md"
43
+ )
44
+ with open(file_path, "r") as f:
45
+ self.__internal_default_prompt[name] = f.read().strip()
46
+ return self.__internal_default_prompt[name]
47
+
48
+ @property
49
+ def LOGGER(self) -> logging.Logger:
50
+ return logging.getLogger()
51
+
52
+ @property
53
+ def DEFAULT_SHELL(self) -> str:
54
+ return self._getenv("SHELL", self._get_current_shell())
55
+
56
+ def _get_current_shell(self) -> str:
57
+ if platform.system() == "Windows":
58
+ return "PowerShell"
59
+ current_shell = os.getenv("SHELL", "")
60
+ if current_shell.endswith("zsh"):
61
+ return "zsh"
62
+ return "bash"
63
+
64
+ @property
65
+ def DEFAULT_EDITOR(self) -> str:
66
+ return self._getenv("EDITOR", "nano")
67
+
68
+ @property
69
+ def DEFAULT_DIFF_EDIT_COMMAND_TPL(self) -> str:
70
+ return self._getenv("DIFF_EDIT_COMMAND", self._get_default_diff_edit_command())
71
+
72
+ def _get_default_diff_edit_command(self) -> str:
73
+ editor = self.DEFAULT_EDITOR
74
+ if editor in [
75
+ "code",
76
+ "vscode",
77
+ "vscodium",
78
+ "windsurf",
79
+ "cursor",
80
+ "zed",
81
+ "zeditor",
82
+ "agy",
83
+ ]:
84
+ return f"{editor} --wait --diff {{old}} {{new}}"
85
+ if editor == "emacs":
86
+ return 'emacs --eval \'(ediff-files "{old}" "{new}")\''
87
+ if editor in ["nvim", "vim"]:
88
+ return (
89
+ f"{editor} -d {{old}} {{new}} "
90
+ "-i NONE "
91
+ '-c "wincmd h | set readonly | wincmd l" '
92
+ '-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
93
+ '-c "set showtabline=2 | set tabline=[Instructions]\\ :wqa(save\\ &\\ quit)\\ \\|\\ i/esc(toggle\\ edit\\ mode)" ' # noqa
94
+ '-c "wincmd h | setlocal statusline=OLD\\ FILE" '
95
+ '-c "wincmd l | setlocal statusline=%#StatusBold#NEW\\ FILE\\ :wqa(save\\ &\\ quit)\\ \\|\\ i/esc(toggle\\ edit\\ mode)" ' # noqa
96
+ '-c "autocmd BufWritePost * wqa"'
97
+ )
98
+ return 'vimdiff {old} {new} +"setlocal ro" +"wincmd l" +"autocmd BufWritePost <buffer> qa"' # noqa
99
+
100
+ @property
101
+ def INIT_MODULES(self) -> list[str]:
102
+ init_modules_str = self._getenv("INIT_MODULES", "")
103
+ if init_modules_str != "":
104
+ return [
105
+ module.strip()
106
+ for module in init_modules_str.split(":")
107
+ if module.strip() != ""
108
+ ]
109
+ return []
110
+
111
+ @property
112
+ def ROOT_GROUP_NAME(self) -> str:
113
+ return self._getenv("ROOT_GROUP_NAME", "zrb")
114
+
115
+ @property
116
+ def ROOT_GROUP_DESCRIPTION(self) -> str:
117
+ return self._getenv("ROOT_GROUP_DESCRIPTION", "Your Automation Powerhouse")
118
+
119
+ @property
120
+ def INIT_SCRIPTS(self) -> list[str]:
121
+ init_scripts_str = self._getenv("INIT_SCRIPTS", "")
122
+ if init_scripts_str != "":
123
+ return [
124
+ script.strip()
125
+ for script in init_scripts_str.split(":")
126
+ if script.strip() != ""
127
+ ]
128
+ return []
129
+
130
+ @property
131
+ def INIT_FILE_NAME(self) -> str:
132
+ return self._getenv("INIT_FILE_NAME", "zrb_init.py")
133
+
134
+ @property
135
+ def LOGGING_LEVEL(self) -> int:
136
+ return self._get_log_level(self._getenv("LOGGING_LEVEL", "WARNING"))
137
+
138
+ def _get_log_level(self, level: str) -> int:
139
+ level = level.upper()
140
+ log_levels = {
141
+ "CRITICAL": logging.CRITICAL, # 50
142
+ "FATAL": logging.CRITICAL, # 50
143
+ "ERROR": logging.ERROR, # 40
144
+ "WARN": logging.WARNING, # 30
145
+ "WARNING": logging.WARNING, # 30
146
+ "INFO": logging.INFO, # 20
147
+ "DEBUG": logging.DEBUG, # 10
148
+ "NOTSET": logging.NOTSET, # 0
149
+ }
150
+ if level in log_levels:
151
+ return log_levels[level]
152
+ return logging.WARNING
153
+
154
+ @property
155
+ def LOAD_BUILTIN(self) -> bool:
156
+ return to_boolean(self._getenv("LOAD_BUILTIN", "1"))
157
+
158
+ @property
159
+ def WARN_UNRECOMMENDED_COMMAND(self) -> bool:
160
+ return to_boolean(self._getenv("WARN_UNRECOMMENDED_COMMAND", "1"))
161
+
162
+ @property
163
+ def SESSION_LOG_DIR(self) -> str:
164
+ return os.getenv(
165
+ "ZRB_SESSION_LOG_DIR", os.path.expanduser(os.path.join("~", ".zrb-session"))
166
+ )
167
+
168
+ @property
169
+ def TODO_DIR(self) -> str:
170
+ return self._getenv("TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
171
+
172
+ @property
173
+ def TODO_VISUAL_FILTER(self) -> str:
174
+ return self._getenv("TODO_FILTER", "")
175
+
176
+ @property
177
+ def TODO_RETENTION(self) -> str:
178
+ return self._getenv("TODO_RETENTION", "2w")
179
+
180
+ @property
181
+ def VERSION(self) -> str:
182
+ custom_version = os.getenv("_ZRB_CUSTOM_VERSION", "")
183
+ if custom_version != "":
184
+ return custom_version
185
+ return metadata.version("zrb")
186
+
187
+ @property
188
+ def WEB_CSS_PATH(self) -> list[str]:
189
+ web_css_path_str = self._getenv("WEB_CSS_PATH", "")
190
+ if web_css_path_str != "":
191
+ return [
192
+ path.strip()
193
+ for path in web_css_path_str.split(":")
194
+ if path.strip() != ""
195
+ ]
196
+ return []
197
+
198
+ @property
199
+ def WEB_JS_PATH(self) -> list[str]:
200
+ web_js_path_str = self._getenv("WEB_JS_PATH", "")
201
+ if web_js_path_str != "":
202
+ return [
203
+ path.strip()
204
+ for path in web_js_path_str.split(":")
205
+ if path.strip() != ""
206
+ ]
207
+ return []
208
+
209
+ @property
210
+ def WEB_FAVICON_PATH(self) -> str:
211
+ return self._getenv("WEB_FAVICON_PATH", "/static/favicon-32x32.png")
212
+
213
+ @property
214
+ def WEB_COLOR(self) -> str:
215
+ return self._getenv("WEB_COLOR", "")
216
+
217
+ @property
218
+ def WEB_HTTP_PORT(self) -> int:
219
+ return int(self._getenv("WEB_HTTP_PORT", "21213"))
220
+
221
+ @property
222
+ def WEB_GUEST_USERNAME(self) -> str:
223
+ return self._getenv("WEB_GUEST_USERNAME", "user")
224
+
225
+ @property
226
+ def WEB_SUPER_ADMIN_USERNAME(self) -> str:
227
+ return self._getenv("WEB_SUPER_ADMIN_USERNAME", "admin")
228
+
229
+ @property
230
+ def WEB_SUPER_ADMIN_PASSWORD(self) -> str:
231
+ return self._getenv("WEB_SUPER_ADMIN_PASSWORD", "admin")
232
+
233
+ @property
234
+ def WEB_ACCESS_TOKEN_COOKIE_NAME(self) -> str:
235
+ return self._getenv("WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token")
236
+
237
+ @property
238
+ def WEB_REFRESH_TOKEN_COOKIE_NAME(self) -> str:
239
+ return self._getenv("WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token")
240
+
241
+ @property
242
+ def WEB_SECRET_KEY(self) -> str:
243
+ return self._getenv("WEB_SECRET", "zrb")
244
+
245
+ @property
246
+ def WEB_ENABLE_AUTH(self) -> bool:
247
+ return to_boolean(self._getenv("WEB_ENABLE_AUTH", "0"))
248
+
249
+ @property
250
+ def WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES(self) -> int:
251
+ return int(self._getenv("WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
252
+
253
+ @property
254
+ def WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES(self) -> int:
255
+ return int(self._getenv("WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60"))
256
+
257
+ @property
258
+ def WEB_TITLE(self) -> str:
259
+ return self._getenv("WEB_TITLE", "Zrb")
260
+
261
+ @property
262
+ def WEB_JARGON(self) -> str:
263
+ return self._getenv("WEB_JARGON", "Your Automation PowerHouse")
264
+
265
+ @property
266
+ def WEB_HOMEPAGE_INTRO(self) -> str:
267
+ return self._getenv("WEB_HOMEPAGE_INTRO", "Welcome to Zrb Web Interface")
268
+
269
+ @property
270
+ def LLM_MODEL(self) -> str | None:
271
+ value = self._getenv("LLM_MODEL")
272
+ return None if value == "" else value
273
+
274
+ @property
275
+ def LLM_BASE_URL(self) -> str | None:
276
+ value = self._getenv("LLM_BASE_URL")
277
+ return None if value == "" else value
278
+
279
+ @property
280
+ def LLM_API_KEY(self) -> str | None:
281
+ value = self._getenv("LLM_API_KEY")
282
+ return None if value == "" else value
283
+
284
+ @property
285
+ def LLM_MODEL_SMALL(self) -> str | None:
286
+ value = self._getenv("LLM_MODEL_SMALL")
287
+ return None if value == "" else value
288
+
289
+ @property
290
+ def LLM_BASE_URL_SMALL(self) -> str | None:
291
+ value = self._getenv("LLM_BASE_URL_SMALL")
292
+ return None if value == "" else value
293
+
294
+ @property
295
+ def LLM_API_KEY_SMALL(self) -> str | None:
296
+ value = self._getenv("LLM_API_KEY_SMALL")
297
+ return None if value == "" else value
298
+
299
+ @property
300
+ def LLM_SYSTEM_PROMPT(self) -> str | None:
301
+ value = self._getenv("LLM_SYSTEM_PROMPT")
302
+ return None if value == "" else value
303
+
304
+ @property
305
+ def LLM_INTERACTIVE_SYSTEM_PROMPT(self) -> str | None:
306
+ value = self._getenv("LLM_INTERACTIVE_SYSTEM_PROMPT")
307
+ return None if value == "" else value
308
+
309
+ @property
310
+ def LLM_PERSONA(self) -> str | None:
311
+ value = self._getenv("LLM_PERSONA")
312
+ return None if value == "" else value
313
+
314
+ @property
315
+ def LLM_WORKFLOWS(self) -> list[str]:
316
+ """Get a list of LLM workflows from environment variables."""
317
+ workflows = []
318
+ for workflow in self._getenv("LLM_WORKFLOWS", "").split(","):
319
+ workflow = workflow.strip()
320
+ if workflow != "":
321
+ workflows.append(workflow)
322
+ return workflows
323
+
324
+ @property
325
+ def LLM_BUILTIN_WORKFLOW_PATHS(self) -> list[str]:
326
+ """Get a list of additional builtin workflow paths from environment variables."""
327
+ builtin_workflow_paths_str = self._getenv(
328
+ ["LLM_BUILTIN_WORFKLOW_PATH", "LLM_BUILTIN_WORKFLOW_PATHS"], ""
329
+ )
330
+ if builtin_workflow_paths_str != "":
331
+ return [
332
+ path.strip()
333
+ for path in builtin_workflow_paths_str.split(":")
334
+ if path.strip() != ""
335
+ ]
336
+ return []
337
+
338
+ @property
339
+ def LLM_SPECIAL_INSTRUCTION_PROMPT(self) -> str | None:
340
+ value = self._getenv("LLM_SPECIAL_INSTRUCTION_PROMPT")
341
+ return None if value == "" else value
342
+
343
+ @property
344
+ def LLM_SUMMARIZATION_PROMPT(self) -> str | None:
345
+ value = self._getenv("LLM_SUMMARIZATION_PROMPT")
346
+ return None if value == "" else value
347
+
348
+ @property
349
+ def LLM_SHOW_TOOL_CALL_RESULT(self) -> bool:
350
+ return to_boolean(self._getenv("LLM_SHOW_TOOL_CALL_RESULT", "false"))
351
+
352
+ @property
353
+ def LLM_MAX_REQUESTS_PER_MINUTE(self) -> int:
354
+ """
355
+ Maximum number of LLM requests allowed per minute.
356
+ Default is conservative to accommodate free-tier LLM providers.
357
+ """
358
+ return int(
359
+ self._getenv(
360
+ ["LLM_MAX_REQUEST_PER_MINUTE", "LLM_MAX_REQUESTS_PER_MINUTE"], "60"
361
+ )
362
+ )
363
+
364
+ @property
365
+ def LLM_MAX_TOKENS_PER_MINUTE(self) -> int:
366
+ """
367
+ Maximum number of LLM tokens allowed per minute.
368
+ Default is conservative to accommodate free-tier LLM providers.
369
+ """
370
+ return int(
371
+ self._getenv(
372
+ ["LLM_MAX_TOKEN_PER_MINUTE", "LLM_MAX_TOKENS_PER_MINUTE"], "100000"
373
+ )
374
+ )
375
+
376
+ @property
377
+ def LLM_MAX_TOKENS_PER_REQUEST(self) -> int:
378
+ """Maximum number of tokens allowed per individual LLM request."""
379
+ return int(
380
+ self._getenv(
381
+ ["LLM_MAX_TOKEN_PER_REQUEST", "LLM_MAX_TOKENS_PER_REQUEST"], "120000"
382
+ )
383
+ )
384
+
385
+ @property
386
+ def LLM_MAX_TOKENS_PER_TOOL_CALL_RESULT(self) -> int:
387
+ """Maximum number of tokens allowed per tool call result."""
388
+ return int(
389
+ self._getenv(
390
+ [
391
+ "LLM_MAX_TOKEN_PER_TOOL_CALL_RESULT",
392
+ "LLM_MAX_TOKENS_PER_TOOL_CALL_RESULT",
393
+ ],
394
+ str(self._get_max_threshold(0.4)),
395
+ )
396
+ )
397
+
398
+ @property
399
+ def LLM_THROTTLE_SLEEP(self) -> float:
400
+ """Number of seconds to sleep when throttling is required."""
401
+ return float(self._getenv("LLM_THROTTLE_SLEEP", "5.0"))
402
+
403
+ @property
404
+ def LLM_YOLO_MODE(self) -> bool | list[str]:
405
+ str_val = self._getenv("LLM_YOLO_MODE", "false")
406
+ try:
407
+ return to_boolean(str_val)
408
+ except Exception:
409
+ return [val.strip() for val in str_val.split(",") if val.strip() != ""]
410
+
411
+ @property
412
+ def LLM_SUMMARIZE_HISTORY(self) -> bool:
413
+ return to_boolean(self._getenv("LLM_SUMMARIZE_HISTORY", "true"))
414
+
415
+ @property
416
+ def LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
417
+ threshold = int(
418
+ self._getenv(
419
+ "LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD",
420
+ str(self._get_max_threshold(0.6)),
421
+ )
422
+ )
423
+ return self._limit_token_threshold(threshold, 0.6)
424
+
425
+ @property
426
+ def LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD(self) -> int:
427
+ threshold = int(
428
+ self._getenv(
429
+ "LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD",
430
+ str(self._get_max_threshold(0.4)),
431
+ )
432
+ )
433
+ return self._limit_token_threshold(threshold, 0.4)
434
+
435
+ @property
436
+ def LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
437
+ threshold = int(
438
+ self._getenv(
439
+ "LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD",
440
+ str(self._get_max_threshold(0.4)),
441
+ )
442
+ )
443
+ return self._limit_token_threshold(threshold, 0.4)
444
+
445
+ @property
446
+ def LLM_FILE_ANALYSIS_TOKEN_THRESHOLD(self) -> int:
447
+ threshold = int(
448
+ self._getenv(
449
+ "LLM_FILE_ANALYSIS_TOKEN_THRESHOLD", str(self._get_max_threshold(0.4))
450
+ )
451
+ )
452
+ return self._limit_token_threshold(threshold, 0.4)
453
+
454
+ def _limit_token_threshold(self, threshold: int, factor: float) -> int:
455
+ return min(threshold, self._get_max_threshold(factor))
456
+
457
+ def _get_max_threshold(self, factor: float) -> int:
458
+ return round(
459
+ factor
460
+ * min(self.LLM_MAX_TOKENS_PER_MINUTE, self.LLM_MAX_TOKENS_PER_REQUEST)
461
+ )
462
+
463
+ @property
464
+ def LLM_FILE_EXTRACTOR_SYSTEM_PROMPT(self) -> str:
465
+ return self._getenv(
466
+ "LLM_FILE_EXTRACTOR_SYSTEM_PROMPT",
467
+ self._get_internal_default_prompt("file_extractor_system_prompt"),
468
+ )
469
+
470
+ @property
471
+ def LLM_REPO_EXTRACTOR_SYSTEM_PROMPT(self) -> str:
472
+ return self._getenv(
473
+ "LLM_REPO_EXTRACTOR_SYSTEM_PROMPT",
474
+ self._get_internal_default_prompt("repo_extractor_system_prompt"),
475
+ )
476
+
477
+ @property
478
+ def LLM_REPO_SUMMARIZER_SYSTEM_PROMPT(self) -> str:
479
+ return self._getenv(
480
+ "LLM_REPO_SUMMARIZER_SYSTEM_PROMPT",
481
+ self._get_internal_default_prompt("repo_summarizer_system_prompt"),
482
+ )
483
+
484
+ @property
485
+ def LLM_HISTORY_DIR(self) -> str:
486
+ return self._getenv(
487
+ "LLM_HISTORY_DIR",
488
+ os.path.expanduser(os.path.join("~", ".zrb-llm-history")),
489
+ )
490
+
491
+ @property
492
+ def LLM_ALLOW_ACCESS_LOCAL_FILE(self) -> bool:
493
+ return to_boolean(self._getenv("LLM_ALLOW_ACCESS_LOCAL_FILE", "1"))
494
+
495
+ @property
496
+ def LLM_ALLOW_ANALYZE_FILE(self) -> bool:
497
+ return to_boolean(self._getenv("LLM_ALLOW_ANALYZE_LOCAL_FILE", "1"))
498
+
499
+ @property
500
+ def LLM_ALLOW_ANALYZE_REPO(self) -> bool:
501
+ return to_boolean(self._getenv("LLM_ALLOW_ANALYZE_REPO", "1"))
502
+
503
+ @property
504
+ def LLM_ALLOW_ACCESS_SHELL(self) -> bool:
505
+ return to_boolean(self._getenv("LLM_ALLOW_ACCESS_SHELL", "1"))
506
+
507
+ @property
508
+ def LLM_ALLOW_OPEN_WEB_PAGE(self) -> bool:
509
+ return to_boolean(self._getenv("LLM_ALLOW_OPEN_WEB_PAGE", "1"))
510
+
511
+ @property
512
+ def LLM_ALLOW_SEARCH_INTERNET(self) -> bool:
513
+ return to_boolean(self._getenv("LLM_ALLOW_SEARCH_INTERNET", "1"))
514
+
515
+ @property
516
+ def LLM_ALLOW_GET_CURRENT_LOCATION(self) -> bool:
517
+ return to_boolean(self._getenv("LLM_ALLOW_GET_CURRENT_LOCATION", "1"))
518
+
519
+ @property
520
+ def LLM_ALLOW_GET_CURRENT_WEATHER(self) -> bool:
521
+ return to_boolean(self._getenv("LLM_ALLOW_GET_CURRENT_WEATHER", "1"))
522
+
523
+ @property
524
+ def RAG_EMBEDDING_API_KEY(self) -> str | None:
525
+ value = self._getenv("RAG_EMBEDDING_API_KEY")
526
+ return None if value == "" else value
527
+
528
+ @property
529
+ def RAG_EMBEDDING_BASE_URL(self) -> str | None:
530
+ value = self._getenv("RAG_EMBEDDING_BASE_URL")
531
+ return None if value == "" else value
532
+
533
+ @property
534
+ def RAG_EMBEDDING_MODEL(self) -> str:
535
+ return self._getenv("RAG_EMBEDDING_MODEL", "text-embedding-ada-002")
536
+
537
+ @property
538
+ def RAG_CHUNK_SIZE(self) -> int:
539
+ return int(self._getenv("RAG_CHUNK_SIZE", "1024"))
540
+
541
+ @property
542
+ def RAG_OVERLAP(self) -> int:
543
+ return int(self._getenv("RAG_OVERLAP", "128"))
544
+
545
+ @property
546
+ def RAG_MAX_RESULT_COUNT(self) -> int:
547
+ return int(self._getenv("RAG_MAX_RESULT_COUNT", "5"))
548
+
549
+ @property
550
+ def SEARCH_INTERNET_METHOD(self) -> str:
551
+ """Either serpapi or searxng"""
552
+ return self._getenv("SEARCH_INTERNET_METHOD", "serpapi")
553
+
554
+ @property
555
+ def BRAVE_API_KEY(self) -> str:
556
+ return os.getenv("BRAVE_API_KEY", "")
557
+
558
+ @property
559
+ def BRAVE_API_SAFE(self) -> str:
560
+ return self._getenv("BRAVE_API_SAFE", "off")
561
+
562
+ @property
563
+ def BRAVE_API_LANG(self) -> str:
564
+ return self._getenv("BRAVE_API_LANG", "en")
565
+
566
+ @property
567
+ def SERPAPI_KEY(self) -> str:
568
+ return os.getenv("SERPAPI_KEY", "")
569
+
570
+ @property
571
+ def SERPAPI_SAFE(self) -> str:
572
+ return self._getenv("SERPAPI_SAFE", "off")
573
+
574
+ @property
575
+ def SERPAPI_LANG(self) -> str:
576
+ return self._getenv("SERPAPI_LANG", "en")
577
+
578
+ @property
579
+ def SEARXNG_PORT(self) -> int:
580
+ return int(self._getenv("SEARXNG_PORT", "8080"))
581
+
582
+ @property
583
+ def SEARXNG_BASE_URL(self) -> str:
584
+ return self._getenv("SEARXNG_BASE_URL", f"http://localhost:{self.SEARXNG_PORT}")
585
+
586
+ @property
587
+ def SEARXNG_SAFE(self) -> int:
588
+ return int(self._getenv("SEARXNG_SAFE", "0"))
589
+
590
+ @property
591
+ def SEARXNG_LANG(self) -> str:
592
+ return self._getenv("SEARXNG_LANG", "en")
593
+
594
+ @property
595
+ def BANNER(self) -> str:
596
+ return fstring_format(
597
+ self._getenv("BANNER", _DEFAULT_BANNER),
598
+ {"VERSION": self.VERSION},
599
+ )
600
+
601
+ @property
602
+ def LLM_CONTEXT_FILE(self) -> str:
603
+ return self._getenv("LLM_CONTEXT_FILE", "ZRB.md")
604
+
605
+ @property
606
+ def USE_TIKTOKEN(self) -> bool:
607
+ return to_boolean(self._getenv("USE_TIKTOKEN", "true"))
608
+
609
+ @property
610
+ def TIKTOKEN_ENCODING_NAME(self) -> str:
611
+ return self._getenv("TIKTOKEN_ENCODING_NAME", "cl100k_base")
612
+
613
+
614
+ CFG = Config()