zrb 1.15.3__py3-none-any.whl → 2.0.0a4__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 (204) hide show
  1. zrb/__init__.py +118 -133
  2. zrb/attr/type.py +10 -7
  3. zrb/builtin/__init__.py +55 -1
  4. zrb/builtin/git.py +12 -1
  5. zrb/builtin/group.py +31 -15
  6. zrb/builtin/llm/chat.py +147 -0
  7. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  9. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  10. zrb/builtin/searxng/config/settings.yml +5671 -0
  11. zrb/builtin/searxng/start.py +21 -0
  12. zrb/builtin/shell/autocomplete/bash.py +4 -3
  13. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  14. zrb/callback/callback.py +8 -1
  15. zrb/cmd/cmd_result.py +2 -1
  16. zrb/config/config.py +555 -169
  17. zrb/config/helper.py +84 -0
  18. zrb/config/web_auth_config.py +50 -35
  19. zrb/context/any_shared_context.py +20 -3
  20. zrb/context/context.py +39 -5
  21. zrb/context/print_fn.py +13 -0
  22. zrb/context/shared_context.py +17 -8
  23. zrb/group/any_group.py +3 -3
  24. zrb/group/group.py +3 -3
  25. zrb/input/any_input.py +5 -1
  26. zrb/input/base_input.py +18 -6
  27. zrb/input/option_input.py +41 -1
  28. zrb/input/text_input.py +7 -24
  29. zrb/llm/agent/__init__.py +9 -0
  30. zrb/llm/agent/agent.py +215 -0
  31. zrb/llm/agent/summarizer.py +20 -0
  32. zrb/llm/app/__init__.py +10 -0
  33. zrb/llm/app/completion.py +281 -0
  34. zrb/llm/app/confirmation/allow_tool.py +66 -0
  35. zrb/llm/app/confirmation/handler.py +178 -0
  36. zrb/llm/app/confirmation/replace_confirmation.py +77 -0
  37. zrb/llm/app/keybinding.py +34 -0
  38. zrb/llm/app/layout.py +117 -0
  39. zrb/llm/app/lexer.py +155 -0
  40. zrb/llm/app/redirection.py +28 -0
  41. zrb/llm/app/style.py +16 -0
  42. zrb/llm/app/ui.py +733 -0
  43. zrb/llm/config/__init__.py +4 -0
  44. zrb/llm/config/config.py +122 -0
  45. zrb/llm/config/limiter.py +247 -0
  46. zrb/llm/history_manager/__init__.py +4 -0
  47. zrb/llm/history_manager/any_history_manager.py +23 -0
  48. zrb/llm/history_manager/file_history_manager.py +91 -0
  49. zrb/llm/history_processor/summarizer.py +108 -0
  50. zrb/llm/note/__init__.py +3 -0
  51. zrb/llm/note/manager.py +122 -0
  52. zrb/llm/prompt/__init__.py +29 -0
  53. zrb/llm/prompt/claude_compatibility.py +92 -0
  54. zrb/llm/prompt/compose.py +55 -0
  55. zrb/llm/prompt/default.py +51 -0
  56. zrb/llm/prompt/markdown/file_extractor.md +112 -0
  57. zrb/llm/prompt/markdown/mandate.md +23 -0
  58. zrb/llm/prompt/markdown/persona.md +3 -0
  59. zrb/llm/prompt/markdown/repo_extractor.md +112 -0
  60. zrb/llm/prompt/markdown/repo_summarizer.md +29 -0
  61. zrb/llm/prompt/markdown/summarizer.md +21 -0
  62. zrb/llm/prompt/note.py +41 -0
  63. zrb/llm/prompt/system_context.py +46 -0
  64. zrb/llm/prompt/zrb.py +41 -0
  65. zrb/llm/skill/__init__.py +3 -0
  66. zrb/llm/skill/manager.py +86 -0
  67. zrb/llm/task/__init__.py +4 -0
  68. zrb/llm/task/llm_chat_task.py +316 -0
  69. zrb/llm/task/llm_task.py +245 -0
  70. zrb/llm/tool/__init__.py +39 -0
  71. zrb/llm/tool/bash.py +75 -0
  72. zrb/llm/tool/code.py +266 -0
  73. zrb/llm/tool/file.py +419 -0
  74. zrb/llm/tool/note.py +70 -0
  75. zrb/{builtin/llm → llm}/tool/rag.py +33 -37
  76. zrb/llm/tool/search/brave.py +53 -0
  77. zrb/llm/tool/search/searxng.py +47 -0
  78. zrb/llm/tool/search/serpapi.py +47 -0
  79. zrb/llm/tool/skill.py +19 -0
  80. zrb/llm/tool/sub_agent.py +70 -0
  81. zrb/llm/tool/web.py +97 -0
  82. zrb/llm/tool/zrb_task.py +66 -0
  83. zrb/llm/util/attachment.py +101 -0
  84. zrb/llm/util/prompt.py +104 -0
  85. zrb/llm/util/stream_response.py +178 -0
  86. zrb/runner/cli.py +21 -20
  87. zrb/runner/common_util.py +24 -19
  88. zrb/runner/web_route/task_input_api_route.py +5 -5
  89. zrb/runner/web_util/user.py +7 -3
  90. zrb/session/any_session.py +12 -9
  91. zrb/session/session.py +38 -17
  92. zrb/task/any_task.py +24 -3
  93. zrb/task/base/context.py +42 -22
  94. zrb/task/base/execution.py +67 -55
  95. zrb/task/base/lifecycle.py +14 -7
  96. zrb/task/base/monitoring.py +12 -7
  97. zrb/task/base_task.py +113 -50
  98. zrb/task/base_trigger.py +16 -6
  99. zrb/task/cmd_task.py +6 -0
  100. zrb/task/http_check.py +11 -5
  101. zrb/task/make_task.py +5 -3
  102. zrb/task/rsync_task.py +30 -10
  103. zrb/task/scaffolder.py +7 -4
  104. zrb/task/scheduler.py +7 -4
  105. zrb/task/tcp_check.py +6 -4
  106. zrb/util/ascii_art/art/bee.txt +17 -0
  107. zrb/util/ascii_art/art/cat.txt +9 -0
  108. zrb/util/ascii_art/art/ghost.txt +16 -0
  109. zrb/util/ascii_art/art/panda.txt +17 -0
  110. zrb/util/ascii_art/art/rose.txt +14 -0
  111. zrb/util/ascii_art/art/unicorn.txt +15 -0
  112. zrb/util/ascii_art/banner.py +92 -0
  113. zrb/util/attr.py +54 -39
  114. zrb/util/cli/markdown.py +32 -0
  115. zrb/util/cli/text.py +30 -0
  116. zrb/util/cmd/command.py +33 -10
  117. zrb/util/file.py +61 -33
  118. zrb/util/git.py +2 -2
  119. zrb/util/{llm/prompt.py → markdown.py} +2 -3
  120. zrb/util/match.py +78 -0
  121. zrb/util/run.py +3 -3
  122. zrb/util/string/conversion.py +1 -1
  123. zrb/util/truncate.py +23 -0
  124. zrb/util/yaml.py +204 -0
  125. zrb/xcom/xcom.py +10 -0
  126. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/METADATA +41 -27
  127. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/RECORD +129 -131
  128. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/WHEEL +1 -1
  129. zrb/attr/__init__.py +0 -0
  130. zrb/builtin/llm/chat_session.py +0 -311
  131. zrb/builtin/llm/history.py +0 -71
  132. zrb/builtin/llm/input.py +0 -27
  133. zrb/builtin/llm/llm_ask.py +0 -187
  134. zrb/builtin/llm/previous-session.js +0 -21
  135. zrb/builtin/llm/tool/__init__.py +0 -0
  136. zrb/builtin/llm/tool/api.py +0 -71
  137. zrb/builtin/llm/tool/cli.py +0 -38
  138. zrb/builtin/llm/tool/code.py +0 -254
  139. zrb/builtin/llm/tool/file.py +0 -626
  140. zrb/builtin/llm/tool/sub_agent.py +0 -137
  141. zrb/builtin/llm/tool/web.py +0 -195
  142. zrb/builtin/project/__init__.py +0 -0
  143. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/__init__.py +0 -0
  144. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/service/__init__.py +0 -0
  145. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/__init__.py +0 -0
  146. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/__init__.py +0 -0
  147. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/__init__.py +0 -0
  148. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
  149. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
  150. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/__init__.py +0 -0
  151. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py +0 -0
  152. zrb/builtin/project/create/__init__.py +0 -0
  153. zrb/builtin/shell/__init__.py +0 -0
  154. zrb/builtin/shell/autocomplete/__init__.py +0 -0
  155. zrb/callback/__init__.py +0 -0
  156. zrb/cmd/__init__.py +0 -0
  157. zrb/config/default_prompt/file_extractor_system_prompt.md +0 -12
  158. zrb/config/default_prompt/interactive_system_prompt.md +0 -35
  159. zrb/config/default_prompt/persona.md +0 -1
  160. zrb/config/default_prompt/repo_extractor_system_prompt.md +0 -112
  161. zrb/config/default_prompt/repo_summarizer_system_prompt.md +0 -10
  162. zrb/config/default_prompt/summarization_prompt.md +0 -16
  163. zrb/config/default_prompt/system_prompt.md +0 -32
  164. zrb/config/llm_config.py +0 -243
  165. zrb/config/llm_context/config.py +0 -129
  166. zrb/config/llm_context/config_parser.py +0 -46
  167. zrb/config/llm_rate_limitter.py +0 -137
  168. zrb/content_transformer/__init__.py +0 -0
  169. zrb/context/__init__.py +0 -0
  170. zrb/dot_dict/__init__.py +0 -0
  171. zrb/env/__init__.py +0 -0
  172. zrb/group/__init__.py +0 -0
  173. zrb/input/__init__.py +0 -0
  174. zrb/runner/__init__.py +0 -0
  175. zrb/runner/web_route/__init__.py +0 -0
  176. zrb/runner/web_route/home_page/__init__.py +0 -0
  177. zrb/session/__init__.py +0 -0
  178. zrb/session_state_log/__init__.py +0 -0
  179. zrb/session_state_logger/__init__.py +0 -0
  180. zrb/task/__init__.py +0 -0
  181. zrb/task/base/__init__.py +0 -0
  182. zrb/task/llm/__init__.py +0 -0
  183. zrb/task/llm/agent.py +0 -243
  184. zrb/task/llm/config.py +0 -103
  185. zrb/task/llm/conversation_history.py +0 -128
  186. zrb/task/llm/conversation_history_model.py +0 -242
  187. zrb/task/llm/default_workflow/coding.md +0 -24
  188. zrb/task/llm/default_workflow/copywriting.md +0 -17
  189. zrb/task/llm/default_workflow/researching.md +0 -18
  190. zrb/task/llm/error.py +0 -95
  191. zrb/task/llm/history_summarization.py +0 -216
  192. zrb/task/llm/print_node.py +0 -101
  193. zrb/task/llm/prompt.py +0 -325
  194. zrb/task/llm/tool_wrapper.py +0 -220
  195. zrb/task/llm/typing.py +0 -3
  196. zrb/task/llm_task.py +0 -341
  197. zrb/task_status/__init__.py +0 -0
  198. zrb/util/__init__.py +0 -0
  199. zrb/util/cli/__init__.py +0 -0
  200. zrb/util/cmd/__init__.py +0 -0
  201. zrb/util/codemod/__init__.py +0 -0
  202. zrb/util/string/__init__.py +0 -0
  203. zrb/xcom/__init__.py +0 -0
  204. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/entry_points.txt +0 -0
zrb/config/config.py CHANGED
@@ -1,8 +1,15 @@
1
1
  import importlib.metadata as metadata
2
2
  import logging
3
3
  import os
4
- import platform
5
4
 
5
+ from zrb.config.helper import (
6
+ get_current_shell,
7
+ get_default_diff_edit_command,
8
+ get_env,
9
+ get_log_level,
10
+ get_max_token_threshold,
11
+ limit_token_threshold,
12
+ )
6
13
  from zrb.util.string.conversion import to_boolean
7
14
  from zrb.util.string.format import fstring_format
8
15
 
@@ -11,7 +18,7 @@ _DEFAULT_BANNER = """
11
18
  zzzzz rr rr bb
12
19
  zz rrr r bbbbbb
13
20
  zz rr bb bb
14
- zzzzz rr bbbbbb {VERSION} Janggala
21
+ zzzzz rr bbbbbb {VERSION} Pollux
15
22
  _ _ . . . _ . _ . . .
16
23
  Your Automation Powerhouse
17
24
  ☕ Donate at: https://stalchmst.com
@@ -22,23 +29,15 @@ Your Automation Powerhouse
22
29
 
23
30
  class Config:
24
31
  def __init__(self):
25
- self.__internal_default_prompt: dict[str, str] = {}
32
+ pass
26
33
 
27
34
  @property
28
35
  def ENV_PREFIX(self) -> str:
29
36
  return os.getenv("_ZRB_ENV_PREFIX", "ZRB")
30
37
 
31
- def _getenv(self, env_name: str, default: str = "") -> str:
32
- return os.getenv(f"{self.ENV_PREFIX}_{env_name}", default)
33
-
34
- def _get_internal_default_prompt(self, name: str) -> str:
35
- if name not in self.__internal_default_prompt:
36
- file_path = os.path.join(
37
- os.path.dirname(__file__), "default_prompt", f"{name}.md"
38
- )
39
- with open(file_path, "r") as f:
40
- self.__internal_default_prompt[name] = f.read().strip()
41
- return self.__internal_default_prompt[name]
38
+ @ENV_PREFIX.setter
39
+ def ENV_PREFIX(self, value: str):
40
+ os.environ["_ZRB_ENV_PREFIX"] = value
42
41
 
43
42
  @property
44
43
  def LOGGER(self) -> logging.Logger:
@@ -46,23 +45,35 @@ class Config:
46
45
 
47
46
  @property
48
47
  def DEFAULT_SHELL(self) -> str:
49
- return self._getenv("SHELL", self._get_current_shell())
48
+ return get_env("SHELL", get_current_shell(), self.ENV_PREFIX)
50
49
 
51
- def _get_current_shell(self) -> str:
52
- if platform.system() == "Windows":
53
- return "PowerShell"
54
- current_shell = os.getenv("SHELL", "")
55
- if current_shell.endswith("zsh"):
56
- return "zsh"
57
- return "bash"
50
+ @DEFAULT_SHELL.setter
51
+ def DEFAULT_SHELL(self, value: str):
52
+ os.environ[f"{self.ENV_PREFIX}_SHELL"] = value
58
53
 
59
54
  @property
60
55
  def DEFAULT_EDITOR(self) -> str:
61
- return self._getenv("EDITOR", "nano")
56
+ return get_env("EDITOR", "nano", self.ENV_PREFIX)
57
+
58
+ @DEFAULT_EDITOR.setter
59
+ def DEFAULT_EDITOR(self, value: str):
60
+ os.environ[f"{self.ENV_PREFIX}_EDITOR"] = value
61
+
62
+ @property
63
+ def DEFAULT_DIFF_EDIT_COMMAND_TPL(self) -> str:
64
+ return get_env(
65
+ "DIFF_EDIT_COMMAND",
66
+ get_default_diff_edit_command(self.DEFAULT_EDITOR),
67
+ self.ENV_PREFIX,
68
+ )
69
+
70
+ @DEFAULT_DIFF_EDIT_COMMAND_TPL.setter
71
+ def DEFAULT_DIFF_EDIT_COMMAND_TPL(self, value: str):
72
+ os.environ[f"{self.ENV_PREFIX}_DIFF_EDIT_COMMAND"] = value
62
73
 
63
74
  @property
64
75
  def INIT_MODULES(self) -> list[str]:
65
- init_modules_str = self._getenv("INIT_MODULES", "")
76
+ init_modules_str = get_env("INIT_MODULES", "", self.ENV_PREFIX)
66
77
  if init_modules_str != "":
67
78
  return [
68
79
  module.strip()
@@ -71,17 +82,31 @@ class Config:
71
82
  ]
72
83
  return []
73
84
 
85
+ @INIT_MODULES.setter
86
+ def INIT_MODULES(self, value: list[str]):
87
+ os.environ[f"{self.ENV_PREFIX}_INIT_MODULES"] = ":".join(value)
88
+
74
89
  @property
75
90
  def ROOT_GROUP_NAME(self) -> str:
76
- return self._getenv("ROOT_GROUP_NAME", "zrb")
91
+ return get_env("ROOT_GROUP_NAME", "zrb", self.ENV_PREFIX)
92
+
93
+ @ROOT_GROUP_NAME.setter
94
+ def ROOT_GROUP_NAME(self, value: str):
95
+ os.environ[f"{self.ENV_PREFIX}_ROOT_GROUP_NAME"] = value
77
96
 
78
97
  @property
79
98
  def ROOT_GROUP_DESCRIPTION(self) -> str:
80
- return self._getenv("ROOT_GROUP_DESCRIPTION", "Your Automation Powerhouse")
99
+ return get_env(
100
+ "ROOT_GROUP_DESCRIPTION", "Your Automation Powerhouse", self.ENV_PREFIX
101
+ )
102
+
103
+ @ROOT_GROUP_DESCRIPTION.setter
104
+ def ROOT_GROUP_DESCRIPTION(self, value: str):
105
+ os.environ[f"{self.ENV_PREFIX}_ROOT_GROUP_DESCRIPTION"] = value
81
106
 
82
107
  @property
83
108
  def INIT_SCRIPTS(self) -> list[str]:
84
- init_scripts_str = self._getenv("INIT_SCRIPTS", "")
109
+ init_scripts_str = get_env("INIT_SCRIPTS", "", self.ENV_PREFIX)
85
110
  if init_scripts_str != "":
86
111
  return [
87
112
  script.strip()
@@ -90,54 +115,84 @@ class Config:
90
115
  ]
91
116
  return []
92
117
 
118
+ @INIT_SCRIPTS.setter
119
+ def INIT_SCRIPTS(self, value: list[str]):
120
+ os.environ[f"{self.ENV_PREFIX}_INIT_SCRIPTS"] = ":".join(value)
121
+
93
122
  @property
94
123
  def INIT_FILE_NAME(self) -> str:
95
- return self._getenv("INIT_FILE_NAME", "zrb_init.py")
124
+ return get_env("INIT_FILE_NAME", "zrb_init.py", self.ENV_PREFIX)
125
+
126
+ @INIT_FILE_NAME.setter
127
+ def INIT_FILE_NAME(self, value: str):
128
+ os.environ[f"{self.ENV_PREFIX}_INIT_FILE_NAME"] = value
96
129
 
97
130
  @property
98
131
  def LOGGING_LEVEL(self) -> int:
99
- return self._get_log_level(self._getenv("LOGGING_LEVEL", "WARNING"))
100
-
101
- def _get_log_level(self, level: str) -> int:
102
- level = level.upper()
103
- log_levels = {
104
- "CRITICAL": logging.CRITICAL, # 50
105
- "ERROR": logging.ERROR, # 40
106
- "WARN": logging.WARNING, # 30
107
- "WARNING": logging.WARNING, # 30
108
- "INFO": logging.INFO, # 20
109
- "DEBUG": logging.DEBUG, # 10
110
- "NOTSET": logging.NOTSET, # 0
111
- }
112
- if level in log_levels:
113
- return log_levels[level]
114
- return logging.WARNING
132
+ return get_log_level(get_env("LOGGING_LEVEL", "WARNING", self.ENV_PREFIX))
133
+
134
+ @LOGGING_LEVEL.setter
135
+ def LOGGING_LEVEL(self, value: int | str):
136
+ if isinstance(value, int):
137
+ value = logging.getLevelName(value)
138
+ os.environ[f"{self.ENV_PREFIX}_LOGGING_LEVEL"] = str(value)
115
139
 
116
140
  @property
117
141
  def LOAD_BUILTIN(self) -> bool:
118
- return to_boolean(self._getenv("LOAD_BUILTIN", "1"))
142
+ return to_boolean(get_env("LOAD_BUILTIN", "1", self.ENV_PREFIX))
143
+
144
+ @LOAD_BUILTIN.setter
145
+ def LOAD_BUILTIN(self, value: bool):
146
+ os.environ[f"{self.ENV_PREFIX}_LOAD_BUILTIN"] = "1" if value else "0"
119
147
 
120
148
  @property
121
149
  def WARN_UNRECOMMENDED_COMMAND(self) -> bool:
122
- return to_boolean(self._getenv("WARN_UNRECOMMENDED_COMMAND", "1"))
150
+ return to_boolean(get_env("WARN_UNRECOMMENDED_COMMAND", "1", self.ENV_PREFIX))
151
+
152
+ @WARN_UNRECOMMENDED_COMMAND.setter
153
+ def WARN_UNRECOMMENDED_COMMAND(self, value: bool):
154
+ os.environ[f"{self.ENV_PREFIX}_WARN_UNRECOMMENDED_COMMAND"] = (
155
+ "1" if value else "0"
156
+ )
123
157
 
124
158
  @property
125
159
  def SESSION_LOG_DIR(self) -> str:
126
- return os.getenv(
127
- "ZRB_SESSION_LOG_DIR", os.path.expanduser(os.path.join("~", ".zrb-session"))
160
+ return get_env(
161
+ "SESSION_LOG_DIR",
162
+ os.path.expanduser(os.path.join("~", f".{self.ROOT_GROUP_NAME}-session")),
128
163
  )
129
164
 
165
+ @SESSION_LOG_DIR.setter
166
+ def SESSION_LOG_DIR(self, value: str):
167
+ os.environ[f"{self.ENV_PREFIX}_SESSION_LOG_DIR"] = value
168
+
130
169
  @property
131
170
  def TODO_DIR(self) -> str:
132
- return self._getenv("TODO_DIR", os.path.expanduser(os.path.join("~", "todo")))
171
+ return get_env(
172
+ "TODO_DIR",
173
+ os.path.expanduser(os.path.join("~", "todo")),
174
+ self.ENV_PREFIX,
175
+ )
176
+
177
+ @TODO_DIR.setter
178
+ def TODO_DIR(self, value: str):
179
+ os.environ[f"{self.ENV_PREFIX}_TODO_DIR"] = value
133
180
 
134
181
  @property
135
182
  def TODO_VISUAL_FILTER(self) -> str:
136
- return self._getenv("TODO_FILTER", "")
183
+ return get_env("TODO_FILTER", "", self.ENV_PREFIX)
184
+
185
+ @TODO_VISUAL_FILTER.setter
186
+ def TODO_VISUAL_FILTER(self, value: str):
187
+ os.environ[f"{self.ENV_PREFIX}_TODO_FILTER"] = value
137
188
 
138
189
  @property
139
190
  def TODO_RETENTION(self) -> str:
140
- return self._getenv("TODO_RETENTION", "2w")
191
+ return get_env("TODO_RETENTION", "2w", self.ENV_PREFIX)
192
+
193
+ @TODO_RETENTION.setter
194
+ def TODO_RETENTION(self, value: str):
195
+ os.environ[f"{self.ENV_PREFIX}_TODO_RETENTION"] = value
141
196
 
142
197
  @property
143
198
  def VERSION(self) -> str:
@@ -146,9 +201,13 @@ class Config:
146
201
  return custom_version
147
202
  return metadata.version("zrb")
148
203
 
204
+ @VERSION.setter
205
+ def VERSION(self, value: str):
206
+ os.environ["_ZRB_CUSTOM_VERSION"] = value
207
+
149
208
  @property
150
209
  def WEB_CSS_PATH(self) -> list[str]:
151
- web_css_path_str = self._getenv("WEB_CSS_PATH", "")
210
+ web_css_path_str = get_env("WEB_CSS_PATH", "", self.ENV_PREFIX)
152
211
  if web_css_path_str != "":
153
212
  return [
154
213
  path.strip()
@@ -157,9 +216,13 @@ class Config:
157
216
  ]
158
217
  return []
159
218
 
219
+ @WEB_CSS_PATH.setter
220
+ def WEB_CSS_PATH(self, value: list[str]):
221
+ os.environ[f"{self.ENV_PREFIX}_WEB_CSS_PATH"] = ":".join(value)
222
+
160
223
  @property
161
224
  def WEB_JS_PATH(self) -> list[str]:
162
- web_js_path_str = self._getenv("WEB_JS_PATH", "")
225
+ web_js_path_str = get_env("WEB_JS_PATH", "", self.ENV_PREFIX)
163
226
  if web_js_path_str != "":
164
227
  return [
165
228
  path.strip()
@@ -168,121 +231,240 @@ class Config:
168
231
  ]
169
232
  return []
170
233
 
234
+ @WEB_JS_PATH.setter
235
+ def WEB_JS_PATH(self, value: list[str]):
236
+ os.environ[f"{self.ENV_PREFIX}_WEB_JS_PATH"] = ":".join(value)
237
+
171
238
  @property
172
239
  def WEB_FAVICON_PATH(self) -> str:
173
- return self._getenv("WEB_FAVICON_PATH", "/static/favicon-32x32.png")
240
+ return get_env("WEB_FAVICON_PATH", "/static/favicon-32x32.png", self.ENV_PREFIX)
241
+
242
+ @WEB_FAVICON_PATH.setter
243
+ def WEB_FAVICON_PATH(self, value: str):
244
+ os.environ[f"{self.ENV_PREFIX}_WEB_FAVICON_PATH"] = value
174
245
 
175
246
  @property
176
247
  def WEB_COLOR(self) -> str:
177
- return self._getenv("WEB_COLOR", "")
248
+ return get_env("WEB_COLOR", "", self.ENV_PREFIX)
249
+
250
+ @WEB_COLOR.setter
251
+ def WEB_COLOR(self, value: str):
252
+ os.environ[f"{self.ENV_PREFIX}_WEB_COLOR"] = value
178
253
 
179
254
  @property
180
255
  def WEB_HTTP_PORT(self) -> int:
181
- return int(self._getenv("WEB_HTTP_PORT", "21213"))
256
+ return int(get_env("WEB_HTTP_PORT", "21213", self.ENV_PREFIX))
257
+
258
+ @WEB_HTTP_PORT.setter
259
+ def WEB_HTTP_PORT(self, value: int):
260
+ os.environ[f"{self.ENV_PREFIX}_WEB_HTTP_PORT"] = str(value)
182
261
 
183
262
  @property
184
263
  def WEB_GUEST_USERNAME(self) -> str:
185
- return self._getenv("WEB_GUEST_USERNAME", "user")
264
+ return get_env("WEB_GUEST_USERNAME", "user", self.ENV_PREFIX)
265
+
266
+ @WEB_GUEST_USERNAME.setter
267
+ def WEB_GUEST_USERNAME(self, value: str):
268
+ os.environ[f"{self.ENV_PREFIX}_WEB_GUEST_USERNAME"] = value
186
269
 
187
270
  @property
188
271
  def WEB_SUPER_ADMIN_USERNAME(self) -> str:
189
- return self._getenv("WEB_SUPER_ADMIN_USERNAME", "admin")
272
+ return get_env("WEB_SUPER_ADMIN_USERNAME", "admin", self.ENV_PREFIX)
273
+
274
+ @WEB_SUPER_ADMIN_USERNAME.setter
275
+ def WEB_SUPER_ADMIN_USERNAME(self, value: str):
276
+ os.environ[f"{self.ENV_PREFIX}_WEB_SUPER_ADMIN_USERNAME"] = value
190
277
 
191
278
  @property
192
279
  def WEB_SUPER_ADMIN_PASSWORD(self) -> str:
193
- return self._getenv("WEB_SUPER_ADMIN_PASSWORD", "admin")
280
+ return get_env("WEB_SUPER_ADMIN_PASSWORD", "admin", self.ENV_PREFIX)
281
+
282
+ @WEB_SUPER_ADMIN_PASSWORD.setter
283
+ def WEB_SUPER_ADMIN_PASSWORD(self, value: str):
284
+ os.environ[f"{self.ENV_PREFIX}_WEB_SUPER_ADMIN_PASSWORD"] = value
194
285
 
195
286
  @property
196
287
  def WEB_ACCESS_TOKEN_COOKIE_NAME(self) -> str:
197
- return self._getenv("WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token")
288
+ return get_env("WEB_ACCESS_TOKEN_COOKIE_NAME", "access_token", self.ENV_PREFIX)
289
+
290
+ @WEB_ACCESS_TOKEN_COOKIE_NAME.setter
291
+ def WEB_ACCESS_TOKEN_COOKIE_NAME(self, value: str):
292
+ os.environ[f"{self.ENV_PREFIX}_WEB_ACCESS_TOKEN_COOKIE_NAME"] = value
198
293
 
199
294
  @property
200
295
  def WEB_REFRESH_TOKEN_COOKIE_NAME(self) -> str:
201
- return self._getenv("WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token")
296
+ return get_env(
297
+ "WEB_REFRESH_TOKEN_COOKIE_NAME", "refresh_token", self.ENV_PREFIX
298
+ )
299
+
300
+ @WEB_REFRESH_TOKEN_COOKIE_NAME.setter
301
+ def WEB_REFRESH_TOKEN_COOKIE_NAME(self, value: str):
302
+ os.environ[f"{self.ENV_PREFIX}_WEB_REFRESH_TOKEN_COOKIE_NAME"] = value
202
303
 
203
304
  @property
204
305
  def WEB_SECRET_KEY(self) -> str:
205
- return self._getenv("WEB_SECRET", "zrb")
306
+ return get_env("WEB_SECRET", "zrb", self.ENV_PREFIX)
307
+
308
+ @WEB_SECRET_KEY.setter
309
+ def WEB_SECRET_KEY(self, value: str):
310
+ os.environ[f"{self.ENV_PREFIX}_WEB_SECRET"] = value
206
311
 
207
312
  @property
208
313
  def WEB_ENABLE_AUTH(self) -> bool:
209
- return to_boolean(self._getenv("WEB_ENABLE_AUTH", "0"))
314
+ return to_boolean(get_env("WEB_ENABLE_AUTH", "0", self.ENV_PREFIX))
315
+
316
+ @WEB_ENABLE_AUTH.setter
317
+ def WEB_ENABLE_AUTH(self, value: bool):
318
+ os.environ[f"{self.ENV_PREFIX}_WEB_ENABLE_AUTH"] = "1" if value else "0"
210
319
 
211
320
  @property
212
321
  def WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES(self) -> int:
213
- return int(self._getenv("WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
322
+ return int(get_env("WEB_ACCESS_TOKEN_EXPIRE_MINUTES", "30", self.ENV_PREFIX))
323
+
324
+ @WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES.setter
325
+ def WEB_AUTH_ACCESS_TOKEN_EXPIRE_MINUTES(self, value: int):
326
+ os.environ[f"{self.ENV_PREFIX}_WEB_ACCESS_TOKEN_EXPIRE_MINUTES"] = str(value)
214
327
 
215
328
  @property
216
329
  def WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES(self) -> int:
217
- return int(self._getenv("WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60"))
330
+ return int(get_env("WEB_REFRESH_TOKEN_EXPIRE_MINUTES", "60", self.ENV_PREFIX))
331
+
332
+ @WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES.setter
333
+ def WEB_AUTH_REFRESH_TOKEN_EXPIRE_MINUTES(self, value: int):
334
+ os.environ[f"{self.ENV_PREFIX}_WEB_REFRESH_TOKEN_EXPIRE_MINUTES"] = str(value)
218
335
 
219
336
  @property
220
337
  def WEB_TITLE(self) -> str:
221
- return self._getenv("WEB_TITLE", "Zrb")
338
+ return get_env("WEB_TITLE", "Zrb", self.ENV_PREFIX)
339
+
340
+ @WEB_TITLE.setter
341
+ def WEB_TITLE(self, value: str):
342
+ os.environ[f"{self.ENV_PREFIX}_WEB_TITLE"] = value
222
343
 
223
344
  @property
224
345
  def WEB_JARGON(self) -> str:
225
- return self._getenv("WEB_JARGON", "Your Automation PowerHouse")
346
+ return get_env("WEB_JARGON", "Your Automation PowerHouse", self.ENV_PREFIX)
347
+
348
+ @WEB_JARGON.setter
349
+ def WEB_JARGON(self, value: str):
350
+ os.environ[f"{self.ENV_PREFIX}_WEB_JARGON"] = value
226
351
 
227
352
  @property
228
353
  def WEB_HOMEPAGE_INTRO(self) -> str:
229
- return self._getenv("WEB_HOMEPAGE_INTRO", "Welcome to Zrb Web Interface")
354
+ return get_env(
355
+ "WEB_HOMEPAGE_INTRO", "Welcome to Zrb Web Interface", self.ENV_PREFIX
356
+ )
357
+
358
+ @WEB_HOMEPAGE_INTRO.setter
359
+ def WEB_HOMEPAGE_INTRO(self, value: str):
360
+ os.environ[f"{self.ENV_PREFIX}_WEB_HOMEPAGE_INTRO"] = value
230
361
 
231
362
  @property
232
- def LLM_MODEL(self) -> str | None:
233
- value = self._getenv("LLM_MODEL")
234
- return None if value == "" else value
363
+ def LLM_ASSISTANT_NAME(self) -> str:
364
+ return get_env("LLM_ASSISTANT_NAME", self.ROOT_GROUP_NAME)
365
+
366
+ @LLM_ASSISTANT_NAME.setter
367
+ def LLM_ASSISTANT_NAME(self, value: str):
368
+ os.environ[f"{self.ENV_PREFIX}_LLM_ASSISTANT_NAME"] = value
235
369
 
236
370
  @property
237
- def LLM_BASE_URL(self) -> str | None:
238
- value = self._getenv("LLM_BASE_URL")
239
- return None if value == "" else value
371
+ def LLM_ASSISTANT_ASCII_ART(self) -> str:
372
+ return get_env("LLM_ASSISTANT_ASCII_ART", "cat")
373
+
374
+ @LLM_ASSISTANT_ASCII_ART.setter
375
+ def LLM_ASSISTANT_ASCII_ART(self, value: str):
376
+ os.environ[f"{self.ENV_PREFIX}_LLM_ASSISTANT_ASCII_ART"] = value
240
377
 
241
378
  @property
242
- def LLM_API_KEY(self) -> str | None:
243
- value = self._getenv("LLM_API_KEY")
244
- return None if value == "" else value
379
+ def LLM_ASSISTANT_JARGON(self) -> str:
380
+ return get_env("LLM_ASSISTANT_JARGON", self.ROOT_GROUP_DESCRIPTION)
381
+
382
+ @LLM_ASSISTANT_JARGON.setter
383
+ def LLM_ASSISTANT_JARGON(self, value: str):
384
+ os.environ[f"{self.ENV_PREFIX}_LLM_ASSISTANT_JARGON"] = value
245
385
 
246
386
  @property
247
- def LLM_SYSTEM_PROMPT(self) -> str | None:
248
- value = self._getenv("LLM_SYSTEM_PROMPT")
249
- return None if value == "" else value
387
+ def LLM_HISTORY_DIR(self) -> str:
388
+ return get_env(
389
+ "LLM_HISTORY_DIR",
390
+ os.path.expanduser(
391
+ os.path.join("~", f".{self.ROOT_GROUP_NAME}", "llm-history")
392
+ ),
393
+ )
394
+
395
+ @LLM_HISTORY_DIR.setter
396
+ def LLM_HISTORY_DIR(self, value: str):
397
+ os.environ[f"{self.ENV_PREFIX}_LLM_HISTORY_DIR"] = value
250
398
 
251
399
  @property
252
- def LLM_INTERACTIVE_SYSTEM_PROMPT(self) -> str | None:
253
- value = self._getenv("LLM_INTERACTIVE_SYSTEM_PROMPT")
254
- return None if value == "" else value
400
+ def LLM_NOTE_FILE(self) -> str:
401
+ return get_env(
402
+ "LLM_NOTE_FILE",
403
+ os.path.expanduser(
404
+ os.path.join("~", f".{self.ROOT_GROUP_NAME}", "notes.json")
405
+ ),
406
+ )
407
+
408
+ @LLM_NOTE_FILE.setter
409
+ def LLM_NOTE_FILE(self, value: str):
410
+ os.environ[f"{self.ENV_PREFIX}_LLM_NOTE_FILE"] = value
255
411
 
256
412
  @property
257
- def LLM_PERSONA(self) -> str | None:
258
- value = self._getenv("LLM_PERSONA")
413
+ def LLM_MODEL(self) -> str | None:
414
+ value = get_env("LLM_MODEL", "", self.ENV_PREFIX)
259
415
  return None if value == "" else value
260
416
 
261
- @property
262
- def LLM_MODES(self) -> list[str]:
263
- return [
264
- mode.strip()
265
- for mode in self._getenv("LLM_MODES", "coding").split(",")
266
- if mode.strip() != ""
267
- ]
417
+ @LLM_MODEL.setter
418
+ def LLM_MODEL(self, value: str | None):
419
+ if value is None:
420
+ if f"{self.ENV_PREFIX}_LLM_MODEL" in os.environ:
421
+ del os.environ[f"{self.ENV_PREFIX}_LLM_MODEL"]
422
+ else:
423
+ os.environ[f"{self.ENV_PREFIX}_LLM_MODEL"] = value
268
424
 
269
425
  @property
270
- def LLM_SPECIAL_INSTRUCTION_PROMPT(self) -> str | None:
271
- value = self._getenv("LLM_SPECIAL_INSTRUCTION_PROMPT")
426
+ def LLM_BASE_URL(self) -> str | None:
427
+ value = get_env("LLM_BASE_URL", "", self.ENV_PREFIX)
272
428
  return None if value == "" else value
273
429
 
430
+ @LLM_BASE_URL.setter
431
+ def LLM_BASE_URL(self, value: str | None):
432
+ if value is None:
433
+ if f"{self.ENV_PREFIX}_LLM_BASE_URL" in os.environ:
434
+ del os.environ[f"{self.ENV_PREFIX}_LLM_BASE_URL"]
435
+ else:
436
+ os.environ[f"{self.ENV_PREFIX}_LLM_BASE_URL"] = value
437
+
274
438
  @property
275
- def LLM_SUMMARIZATION_PROMPT(self) -> str | None:
276
- value = self._getenv("LLM_SUMMARIZATION_PROMPT")
439
+ def LLM_API_KEY(self) -> str | None:
440
+ value = get_env("LLM_API_KEY", "", self.ENV_PREFIX)
277
441
  return None if value == "" else value
278
442
 
443
+ @LLM_API_KEY.setter
444
+ def LLM_API_KEY(self, value: str | None):
445
+ if value is None:
446
+ if f"{self.ENV_PREFIX}_LLM_API_KEY" in os.environ:
447
+ del os.environ[f"{self.ENV_PREFIX}_LLM_API_KEY"]
448
+ else:
449
+ os.environ[f"{self.ENV_PREFIX}_LLM_API_KEY"] = value
450
+
279
451
  @property
280
452
  def LLM_MAX_REQUESTS_PER_MINUTE(self) -> int:
281
453
  """
282
454
  Maximum number of LLM requests allowed per minute.
283
455
  Default is conservative to accommodate free-tier LLM providers.
284
456
  """
285
- return int(self._getenv("LLM_MAX_REQUESTS_PER_MINUTE", "15"))
457
+ return int(
458
+ get_env(
459
+ ["LLM_MAX_REQUEST_PER_MINUTE", "LLM_MAX_REQUESTS_PER_MINUTE"],
460
+ "60",
461
+ self.ENV_PREFIX,
462
+ )
463
+ )
464
+
465
+ @LLM_MAX_REQUESTS_PER_MINUTE.setter
466
+ def LLM_MAX_REQUESTS_PER_MINUTE(self, value: int):
467
+ os.environ[f"{self.ENV_PREFIX}_LLM_MAX_REQUESTS_PER_MINUTE"] = str(value)
286
468
 
287
469
  @property
288
470
  def LLM_MAX_TOKENS_PER_MINUTE(self) -> int:
@@ -290,150 +472,354 @@ class Config:
290
472
  Maximum number of LLM tokens allowed per minute.
291
473
  Default is conservative to accommodate free-tier LLM providers.
292
474
  """
293
- return int(self._getenv("LLM_MAX_TOKENS_PER_MINUTE", "100000"))
475
+ return int(
476
+ get_env(
477
+ ["LLM_MAX_TOKEN_PER_MINUTE", "LLM_MAX_TOKENS_PER_MINUTE"],
478
+ "120000",
479
+ self.ENV_PREFIX,
480
+ )
481
+ )
482
+
483
+ @LLM_MAX_TOKENS_PER_MINUTE.setter
484
+ def LLM_MAX_TOKENS_PER_MINUTE(self, value: int):
485
+ os.environ[f"{self.ENV_PREFIX}_LLM_MAX_TOKENS_PER_MINUTE"] = str(value)
294
486
 
295
487
  @property
296
488
  def LLM_MAX_TOKENS_PER_REQUEST(self) -> int:
297
489
  """Maximum number of tokens allowed per individual LLM request."""
298
- return int(self._getenv("LLM_MAX_TOKENS_PER_REQUEST", "50000"))
490
+ return int(
491
+ get_env(
492
+ ["LLM_MAX_TOKEN_PER_REQUEST", "LLM_MAX_TOKENS_PER_REQUEST"],
493
+ "120000",
494
+ self.ENV_PREFIX,
495
+ )
496
+ )
497
+
498
+ @LLM_MAX_TOKENS_PER_REQUEST.setter
499
+ def LLM_MAX_TOKENS_PER_REQUEST(self, value: int):
500
+ os.environ[f"{self.ENV_PREFIX}_LLM_MAX_TOKENS_PER_REQUEST"] = str(value)
299
501
 
300
502
  @property
301
503
  def LLM_THROTTLE_SLEEP(self) -> float:
302
504
  """Number of seconds to sleep when throttling is required."""
303
- return float(self._getenv("LLM_THROTTLE_SLEEP", "1.0"))
505
+ return float(get_env("LLM_THROTTLE_SLEEP", "1.0", self.ENV_PREFIX))
304
506
 
305
- @property
306
- def LLM_YOLO_MODE(self) -> bool:
307
- return to_boolean(self._getenv("LLM_YOLO_MODE", "false"))
507
+ @LLM_THROTTLE_SLEEP.setter
508
+ def LLM_THROTTLE_SLEEP(self, value: float):
509
+ os.environ[f"{self.ENV_PREFIX}_LLM_THROTTLE_SLEEP"] = str(value)
308
510
 
309
511
  @property
310
- def LLM_SUMMARIZE_HISTORY(self) -> bool:
311
- return to_boolean(self._getenv("LLM_SUMMARIZE_HISTORY", "true"))
512
+ def LLM_HISTORY_SUMMARIZATION_WINDOW(self) -> int:
513
+ return int(get_env("LLM_HISTORY_SUMMARIZATION_WINDOW", "5", self.ENV_PREFIX))
514
+
515
+ @LLM_HISTORY_SUMMARIZATION_WINDOW.setter
516
+ def LLM_HISTORY_SUMMARIZATION_WINDOW(self, value: int):
517
+ os.environ[f"{self.ENV_PREFIX}_LLM_HISTORY_SUMMARIZATION_WINDOW"] = str(value)
312
518
 
313
519
  @property
314
520
  def LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
315
- return int(self._getenv("LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD", "20000"))
521
+ threshold = int(
522
+ get_env(
523
+ "LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD",
524
+ str(self._get_max_threshold(0.6)),
525
+ self.ENV_PREFIX,
526
+ )
527
+ )
528
+ return limit_token_threshold(
529
+ threshold,
530
+ 0.6,
531
+ self.LLM_MAX_TOKENS_PER_MINUTE,
532
+ self.LLM_MAX_TOKENS_PER_REQUEST,
533
+ )
534
+
535
+ @LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD.setter
536
+ def LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD(self, value: int):
537
+ os.environ[f"{self.ENV_PREFIX}_LLM_HISTORY_SUMMARIZATION_TOKEN_THRESHOLD"] = (
538
+ str(value)
539
+ )
316
540
 
317
541
  @property
318
542
  def LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD(self) -> int:
319
- return int(self._getenv("LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_LIMIT", "35000"))
543
+ threshold = int(
544
+ get_env(
545
+ "LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD",
546
+ str(self._get_max_threshold(0.4)),
547
+ self.ENV_PREFIX,
548
+ )
549
+ )
550
+ return limit_token_threshold(
551
+ threshold,
552
+ 0.4,
553
+ self.LLM_MAX_TOKENS_PER_MINUTE,
554
+ self.LLM_MAX_TOKENS_PER_REQUEST,
555
+ )
556
+
557
+ @LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD.setter
558
+ def LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD(self, value: int):
559
+ os.environ[
560
+ f"{self.ENV_PREFIX}_LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD"
561
+ ] = str(value)
320
562
 
321
563
  @property
322
564
  def LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD(self) -> int:
323
- return int(self._getenv("LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_LIMIT", "35000"))
565
+ threshold = int(
566
+ get_env(
567
+ "LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD",
568
+ str(self._get_max_threshold(0.4)),
569
+ self.ENV_PREFIX,
570
+ )
571
+ )
572
+ return limit_token_threshold(
573
+ threshold,
574
+ 0.4,
575
+ self.LLM_MAX_TOKENS_PER_MINUTE,
576
+ self.LLM_MAX_TOKENS_PER_REQUEST,
577
+ )
324
578
 
325
- @property
326
- def LLM_FILE_ANALYSIS_TOKEN_LIMIT(self) -> int:
327
- return int(self._getenv("LLM_FILE_ANALYSIS_TOKEN_LIMIT", "35000"))
579
+ @LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD.setter
580
+ def LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD(self, value: int):
581
+ os.environ[
582
+ f"{self.ENV_PREFIX}_LLM_REPO_ANALYSIS_SUMMARIZATION_TOKEN_THRESHOLD"
583
+ ] = str(value)
328
584
 
329
585
  @property
330
- def LLM_FILE_EXTRACTOR_SYSTEM_PROMPT(self) -> str:
331
- return self._getenv(
332
- "LLM_FILE_EXTRACTOR_SYSTEM_PROMPT",
333
- self._get_internal_default_prompt("file_extractor_system_prompt"),
586
+ def LLM_FILE_ANALYSIS_TOKEN_THRESHOLD(self) -> int:
587
+ threshold = int(
588
+ get_env(
589
+ "LLM_FILE_ANALYSIS_TOKEN_THRESHOLD",
590
+ str(self._get_max_threshold(0.4)),
591
+ self.ENV_PREFIX,
592
+ )
334
593
  )
335
-
336
- @property
337
- def LLM_REPO_EXTRACTOR_SYSTEM_PROMPT(self) -> str:
338
- return self._getenv(
339
- "LLM_REPO_EXTRACTOR_SYSTEM_PROMPT",
340
- self._get_internal_default_prompt("repo_extractor_system_prompt"),
594
+ return limit_token_threshold(
595
+ threshold,
596
+ 0.4,
597
+ self.LLM_MAX_TOKENS_PER_MINUTE,
598
+ self.LLM_MAX_TOKENS_PER_REQUEST,
341
599
  )
342
600
 
601
+ @LLM_FILE_ANALYSIS_TOKEN_THRESHOLD.setter
602
+ def LLM_FILE_ANALYSIS_TOKEN_THRESHOLD(self, value: int):
603
+ os.environ[f"{self.ENV_PREFIX}_LLM_FILE_ANALYSIS_TOKEN_THRESHOLD"] = str(value)
604
+
343
605
  @property
344
- def LLM_REPO_SUMMARIZER_SYSTEM_PROMPT(self) -> str:
345
- return self._getenv(
346
- "LLM_REPO_SUMMARIZER_SYSTEM_PROMPT",
347
- self._get_internal_default_prompt("repo_summarizer_system_prompt"),
606
+ def LLM_PROMPT_DIR(self) -> str:
607
+ return get_env(
608
+ "LLM_PROMPT_DIR",
609
+ os.path.join(f".{self.ROOT_GROUP_NAME}", "llm", "prompt"),
610
+ self.ENV_PREFIX,
348
611
  )
349
612
 
350
- @property
351
- def LLM_HISTORY_DIR(self) -> str:
352
- return self._getenv(
353
- "LLM_HISTORY_DIR",
354
- os.path.expanduser(os.path.join("~", ".zrb-llm-history")),
613
+ @LLM_PROMPT_DIR.setter
614
+ def LLM_PROMPT_DIR(self, value: str):
615
+ os.environ[f"{self.ENV_PREFIX}_LLM_PROMPT_DIR"] = value
616
+
617
+ def _get_max_threshold(self, factor: float) -> int:
618
+ return get_max_token_threshold(
619
+ factor, self.LLM_MAX_TOKENS_PER_MINUTE, self.LLM_MAX_TOKENS_PER_REQUEST
355
620
  )
356
621
 
357
622
  @property
358
- def LLM_ALLOW_ACCESS_LOCAL_FILE(self) -> bool:
359
- return to_boolean(self._getenv("LLM_ALLOW_ACCESS_LOCAL_FILE", "1"))
623
+ def RAG_EMBEDDING_API_KEY(self) -> str | None:
624
+ value = get_env("RAG_EMBEDDING_API_KEY", "", self.ENV_PREFIX)
625
+ return None if value == "" else value
626
+
627
+ @RAG_EMBEDDING_API_KEY.setter
628
+ def RAG_EMBEDDING_API_KEY(self, value: str | None):
629
+ if value is None:
630
+ if f"{self.ENV_PREFIX}_RAG_EMBEDDING_API_KEY" in os.environ:
631
+ del os.environ[f"{self.ENV_PREFIX}_RAG_EMBEDDING_API_KEY"]
632
+ else:
633
+ os.environ[f"{self.ENV_PREFIX}_RAG_EMBEDDING_API_KEY"] = value
360
634
 
361
635
  @property
362
- def LLM_ALLOW_ANALYZE_FILE(self) -> bool:
363
- return to_boolean(self._getenv("LLM_ALLOW_ANALYZE_LOCAL_FILE", "1"))
636
+ def RAG_EMBEDDING_BASE_URL(self) -> str | None:
637
+ value = get_env("RAG_EMBEDDING_BASE_URL", "", self.ENV_PREFIX)
638
+ return None if value == "" else value
639
+
640
+ @RAG_EMBEDDING_BASE_URL.setter
641
+ def RAG_EMBEDDING_BASE_URL(self, value: str | None):
642
+ if value is None:
643
+ if f"{self.ENV_PREFIX}_RAG_EMBEDDING_BASE_URL" in os.environ:
644
+ del os.environ[f"{self.ENV_PREFIX}_RAG_EMBEDDING_BASE_URL"]
645
+ else:
646
+ os.environ[f"{self.ENV_PREFIX}_RAG_EMBEDDING_BASE_URL"] = value
364
647
 
365
648
  @property
366
- def LLM_ALLOW_ANALYZE_REPO(self) -> bool:
367
- return to_boolean(self._getenv("LLM_ALLOW_ANALYZE_REPO", "1"))
649
+ def RAG_EMBEDDING_MODEL(self) -> str:
650
+ return get_env("RAG_EMBEDDING_MODEL", "text-embedding-ada-002", self.ENV_PREFIX)
651
+
652
+ @RAG_EMBEDDING_MODEL.setter
653
+ def RAG_EMBEDDING_MODEL(self, value: str):
654
+ os.environ[f"{self.ENV_PREFIX}_RAG_EMBEDDING_MODEL"] = value
368
655
 
369
656
  @property
370
- def LLM_ALLOW_ACCESS_SHELL(self) -> bool:
371
- return to_boolean(self._getenv("LLM_ALLOW_ACCESS_SHELL", "1"))
657
+ def RAG_CHUNK_SIZE(self) -> int:
658
+ return int(get_env("RAG_CHUNK_SIZE", "1024", self.ENV_PREFIX))
659
+
660
+ @RAG_CHUNK_SIZE.setter
661
+ def RAG_CHUNK_SIZE(self, value: int):
662
+ os.environ[f"{self.ENV_PREFIX}_RAG_CHUNK_SIZE"] = str(value)
372
663
 
373
664
  @property
374
- def LLM_ALLOW_OPEN_WEB_PAGE(self) -> bool:
375
- return to_boolean(self._getenv("LLM_ALLOW_OPEN_WEB_PAGE", "1"))
665
+ def RAG_OVERLAP(self) -> int:
666
+ return int(get_env("RAG_OVERLAP", "128", self.ENV_PREFIX))
667
+
668
+ @RAG_OVERLAP.setter
669
+ def RAG_OVERLAP(self, value: int):
670
+ os.environ[f"{self.ENV_PREFIX}_RAG_OVERLAP"] = str(value)
376
671
 
377
672
  @property
378
- def LLM_ALLOW_SEARCH_INTERNET(self) -> bool:
379
- return to_boolean(self._getenv("LLM_ALLOW_SEARCH_INTERNET", "1"))
673
+ def RAG_MAX_RESULT_COUNT(self) -> int:
674
+ return int(get_env("RAG_MAX_RESULT_COUNT", "5", self.ENV_PREFIX))
675
+
676
+ @RAG_MAX_RESULT_COUNT.setter
677
+ def RAG_MAX_RESULT_COUNT(self, value: int):
678
+ os.environ[f"{self.ENV_PREFIX}_RAG_MAX_RESULT_COUNT"] = str(value)
380
679
 
381
680
  @property
382
- def LLM_ALLOW_SEARCH_ARXIV(self) -> bool:
383
- return to_boolean(self._getenv("LLM_ALLOW_SEARCH_ARXIV", "1"))
681
+ def SEARCH_INTERNET_METHOD(self) -> str:
682
+ """Either serpapi or searxng"""
683
+ return get_env("SEARCH_INTERNET_METHOD", "serpapi", self.ENV_PREFIX)
684
+
685
+ @SEARCH_INTERNET_METHOD.setter
686
+ def SEARCH_INTERNET_METHOD(self, value: str):
687
+ os.environ[f"{self.ENV_PREFIX}_SEARCH_INTERNET_METHOD"] = value
384
688
 
385
689
  @property
386
- def LLM_ALLOW_SEARCH_WIKIPEDIA(self) -> bool:
387
- return to_boolean(self._getenv("LLM_ALLOW_SEARCH_WIKIPEDIA", "1"))
690
+ def BRAVE_API_KEY(self) -> str:
691
+ return os.getenv("BRAVE_API_KEY", "")
692
+
693
+ @BRAVE_API_KEY.setter
694
+ def BRAVE_API_KEY(self, value: str):
695
+ os.environ["BRAVE_API_KEY"] = value
388
696
 
389
697
  @property
390
- def LLM_ALLOW_GET_CURRENT_LOCATION(self) -> bool:
391
- return to_boolean(self._getenv("LLM_ALLOW_GET_CURRENT_LOCATION", "1"))
698
+ def BRAVE_API_SAFE(self) -> str:
699
+ return get_env("BRAVE_API_SAFE", "off", self.ENV_PREFIX)
700
+
701
+ @BRAVE_API_SAFE.setter
702
+ def BRAVE_API_SAFE(self, value: str):
703
+ os.environ[f"{self.ENV_PREFIX}_BRAVE_API_SAFE"] = value
392
704
 
393
705
  @property
394
- def LLM_ALLOW_GET_CURRENT_WEATHER(self) -> bool:
395
- return to_boolean(self._getenv("LLM_ALLOW_GET_CURRENT_WEATHER", "1"))
706
+ def BRAVE_API_LANG(self) -> str:
707
+ return get_env("BRAVE_API_LANG", "en", self.ENV_PREFIX)
708
+
709
+ @BRAVE_API_LANG.setter
710
+ def BRAVE_API_LANG(self, value: str):
711
+ os.environ[f"{self.ENV_PREFIX}_BRAVE_API_LANG"] = value
396
712
 
397
713
  @property
398
- def RAG_EMBEDDING_API_KEY(self) -> str | None:
399
- value = self._getenv("RAG_EMBEDDING_API_KEY")
400
- return None if value == "" else value
714
+ def SERPAPI_KEY(self) -> str:
715
+ return os.getenv("SERPAPI_KEY", "")
716
+
717
+ @SERPAPI_KEY.setter
718
+ def SERPAPI_KEY(self, value: str):
719
+ os.environ["SERPAPI_KEY"] = value
401
720
 
402
721
  @property
403
- def RAG_EMBEDDING_BASE_URL(self) -> str | None:
404
- value = self._getenv("RAG_EMBEDDING_BASE_URL")
405
- return None if value == "" else value
722
+ def SERPAPI_SAFE(self) -> str:
723
+ return get_env("SERPAPI_SAFE", "off", self.ENV_PREFIX)
724
+
725
+ @SERPAPI_SAFE.setter
726
+ def SERPAPI_SAFE(self, value: str):
727
+ os.environ[f"{self.ENV_PREFIX}_SERPAPI_SAFE"] = value
406
728
 
407
729
  @property
408
- def RAG_EMBEDDING_MODEL(self) -> str:
409
- return self._getenv("RAG_EMBEDDING_MODEL", "text-embedding-ada-002")
730
+ def SERPAPI_LANG(self) -> str:
731
+ return get_env("SERPAPI_LANG", "en", self.ENV_PREFIX)
732
+
733
+ @SERPAPI_LANG.setter
734
+ def SERPAPI_LANG(self, value: str):
735
+ os.environ[f"{self.ENV_PREFIX}_SERPAPI_LANG"] = value
410
736
 
411
737
  @property
412
- def RAG_CHUNK_SIZE(self) -> int:
413
- return int(self._getenv("RAG_CHUNK_SIZE", "1024"))
738
+ def SEARXNG_PORT(self) -> int:
739
+ return int(get_env("SEARXNG_PORT", "8080", self.ENV_PREFIX))
740
+
741
+ @SEARXNG_PORT.setter
742
+ def SEARXNG_PORT(self, value: int):
743
+ os.environ[f"{self.ENV_PREFIX}_SEARXNG_PORT"] = str(value)
414
744
 
415
745
  @property
416
- def RAG_OVERLAP(self) -> int:
417
- return int(self._getenv("RAG_OVERLAP", "128"))
746
+ def SEARXNG_BASE_URL(self) -> str:
747
+ return get_env(
748
+ "SEARXNG_BASE_URL", f"http://localhost:{self.SEARXNG_PORT}", self.ENV_PREFIX
749
+ )
750
+
751
+ @SEARXNG_BASE_URL.setter
752
+ def SEARXNG_BASE_URL(self, value: str):
753
+ os.environ[f"{self.ENV_PREFIX}_SEARXNG_BASE_URL"] = value
418
754
 
419
755
  @property
420
- def RAG_MAX_RESULT_COUNT(self) -> int:
421
- return int(self._getenv("RAG_MAX_RESULT_COUNT", "5"))
756
+ def SEARXNG_SAFE(self) -> int:
757
+ return int(get_env("SEARXNG_SAFE", "0", self.ENV_PREFIX))
758
+
759
+ @SEARXNG_SAFE.setter
760
+ def SEARXNG_SAFE(self, value: int):
761
+ os.environ[f"{self.ENV_PREFIX}_SEARXNG_SAFE"] = str(value)
422
762
 
423
763
  @property
424
- def SERPAPI_KEY(self) -> str:
425
- return os.getenv("SERPAPI_KEY", "")
764
+ def SEARXNG_LANG(self) -> str:
765
+ return get_env("SEARXNG_LANG", "en", self.ENV_PREFIX)
766
+
767
+ @SEARXNG_LANG.setter
768
+ def SEARXNG_LANG(self, value: str):
769
+ os.environ[f"{self.ENV_PREFIX}_SEARXNG_LANG"] = value
426
770
 
427
771
  @property
428
772
  def BANNER(self) -> str:
429
773
  return fstring_format(
430
- self._getenv("BANNER", _DEFAULT_BANNER),
774
+ get_env("BANNER", _DEFAULT_BANNER, self.ENV_PREFIX),
431
775
  {"VERSION": self.VERSION},
432
776
  )
433
777
 
778
+ @BANNER.setter
779
+ def BANNER(self, value: str):
780
+ os.environ[f"{self.ENV_PREFIX}_BANNER"] = value
781
+
782
+ @property
783
+ def LLM_SHOW_TOOL_CALL_PREPARATION(self) -> bool:
784
+ return to_boolean(
785
+ get_env("LLM_SHOW_TOOL_CALL_PREPARATION", "0", self.ENV_PREFIX)
786
+ )
787
+
788
+ @LLM_SHOW_TOOL_CALL_PREPARATION.setter
789
+ def LLM_SHOW_TOOL_CALL_PREPARATION(self, value: bool):
790
+ os.environ[f"{self.ENV_PREFIX}_LLM_SHOW_TOOL_CALL_PREPARATION"] = (
791
+ "1" if value else "0"
792
+ )
793
+
434
794
  @property
435
- def LLM_CONTEXT_FILE(self) -> str:
436
- return self._getenv("LLM_CONTEXT_FILE", "ZRB.md")
795
+ def LLM_SHOW_TOOL_CALL_RESULT(self) -> bool:
796
+ return to_boolean(get_env("LLM_SHOW_TOOL_CALL_RESULT", "0", self.ENV_PREFIX))
797
+
798
+ @LLM_SHOW_TOOL_CALL_RESULT.setter
799
+ def LLM_SHOW_TOOL_CALL_RESULT(self, value: bool):
800
+ os.environ[f"{self.ENV_PREFIX}_LLM_SHOW_TOOL_CALL_RESULT"] = (
801
+ "1" if value else "0"
802
+ )
803
+
804
+ @property
805
+ def USE_TIKTOKEN(self) -> bool:
806
+ return to_boolean(get_env("USE_TIKTOKEN", "true", self.ENV_PREFIX))
807
+
808
+ @USE_TIKTOKEN.setter
809
+ def USE_TIKTOKEN(self, value: bool):
810
+ os.environ[f"{self.ENV_PREFIX}_USE_TIKTOKEN"] = "1" if value else "0"
811
+
812
+ @property
813
+ def TIKTOKEN_ENCODING_NAME(self) -> str:
814
+ return get_env(
815
+ ["TIKTOKEN_ENCODING", "TIKTOKEN_ENCODING_NAME"],
816
+ "cl100k_base",
817
+ self.ENV_PREFIX,
818
+ )
819
+
820
+ @TIKTOKEN_ENCODING_NAME.setter
821
+ def TIKTOKEN_ENCODING_NAME(self, value: str):
822
+ os.environ[f"{self.ENV_PREFIX}_TIKTOKEN_ENCODING_NAME"] = value
437
823
 
438
824
 
439
825
  CFG = Config()