zrb 1.15.3__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 (108) hide show
  1. zrb/__init__.py +2 -6
  2. zrb/attr/type.py +10 -7
  3. zrb/builtin/__init__.py +2 -0
  4. zrb/builtin/git.py +12 -1
  5. zrb/builtin/group.py +31 -15
  6. zrb/builtin/llm/attachment.py +40 -0
  7. zrb/builtin/llm/chat_completion.py +274 -0
  8. zrb/builtin/llm/chat_session.py +126 -167
  9. zrb/builtin/llm/chat_session_cmd.py +288 -0
  10. zrb/builtin/llm/chat_trigger.py +79 -0
  11. zrb/builtin/llm/history.py +4 -4
  12. zrb/builtin/llm/llm_ask.py +217 -135
  13. zrb/builtin/llm/tool/api.py +74 -70
  14. zrb/builtin/llm/tool/cli.py +35 -21
  15. zrb/builtin/llm/tool/code.py +55 -73
  16. zrb/builtin/llm/tool/file.py +278 -344
  17. zrb/builtin/llm/tool/note.py +84 -0
  18. zrb/builtin/llm/tool/rag.py +27 -34
  19. zrb/builtin/llm/tool/sub_agent.py +54 -41
  20. zrb/builtin/llm/tool/web.py +74 -98
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  23. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  24. zrb/builtin/searxng/config/settings.yml +5671 -0
  25. zrb/builtin/searxng/start.py +21 -0
  26. zrb/builtin/shell/autocomplete/bash.py +4 -3
  27. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  28. zrb/config/config.py +202 -27
  29. zrb/config/default_prompt/file_extractor_system_prompt.md +109 -9
  30. zrb/config/default_prompt/interactive_system_prompt.md +24 -30
  31. zrb/config/default_prompt/persona.md +1 -1
  32. zrb/config/default_prompt/repo_extractor_system_prompt.md +31 -31
  33. zrb/config/default_prompt/repo_summarizer_system_prompt.md +27 -8
  34. zrb/config/default_prompt/summarization_prompt.md +57 -16
  35. zrb/config/default_prompt/system_prompt.md +36 -30
  36. zrb/config/llm_config.py +119 -23
  37. zrb/config/llm_context/config.py +127 -90
  38. zrb/config/llm_context/config_parser.py +1 -7
  39. zrb/config/llm_context/workflow.py +81 -0
  40. zrb/config/llm_rate_limitter.py +100 -47
  41. zrb/context/any_shared_context.py +7 -1
  42. zrb/context/context.py +8 -2
  43. zrb/context/shared_context.py +3 -7
  44. zrb/group/any_group.py +3 -3
  45. zrb/group/group.py +3 -3
  46. zrb/input/any_input.py +5 -1
  47. zrb/input/base_input.py +18 -6
  48. zrb/input/option_input.py +13 -1
  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_util/user.py +7 -3
  54. zrb/session/any_session.py +12 -6
  55. zrb/session/session.py +39 -18
  56. zrb/task/any_task.py +24 -3
  57. zrb/task/base/context.py +17 -9
  58. zrb/task/base/execution.py +15 -8
  59. zrb/task/base/lifecycle.py +8 -4
  60. zrb/task/base/monitoring.py +12 -7
  61. zrb/task/base_task.py +69 -5
  62. zrb/task/base_trigger.py +12 -5
  63. zrb/task/llm/agent.py +128 -167
  64. zrb/task/llm/agent_runner.py +152 -0
  65. zrb/task/llm/config.py +39 -20
  66. zrb/task/llm/conversation_history.py +110 -29
  67. zrb/task/llm/conversation_history_model.py +4 -179
  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_processor.py +206 -0
  82. zrb/task/llm/history_summarization.py +2 -193
  83. zrb/task/llm/print_node.py +184 -64
  84. zrb/task/llm/prompt.py +175 -179
  85. zrb/task/llm/subagent_conversation_history.py +41 -0
  86. zrb/task/llm/tool_wrapper.py +226 -85
  87. zrb/task/llm/workflow.py +76 -0
  88. zrb/task/llm_task.py +109 -71
  89. zrb/task/make_task.py +2 -3
  90. zrb/task/rsync_task.py +25 -10
  91. zrb/task/scheduler.py +4 -4
  92. zrb/util/attr.py +54 -39
  93. zrb/util/cli/markdown.py +12 -0
  94. zrb/util/cli/text.py +30 -0
  95. zrb/util/file.py +12 -3
  96. zrb/util/git.py +2 -2
  97. zrb/util/{llm/prompt.py → markdown.py} +2 -3
  98. zrb/util/string/conversion.py +1 -1
  99. zrb/util/truncate.py +23 -0
  100. zrb/util/yaml.py +204 -0
  101. zrb/xcom/xcom.py +10 -0
  102. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/METADATA +38 -18
  103. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/RECORD +105 -79
  104. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/WHEEL +1 -1
  105. zrb/task/llm/default_workflow/coding.md +0 -24
  106. zrb/task/llm/default_workflow/copywriting.md +0 -17
  107. zrb/task/llm/default_workflow/researching.md +0 -18
  108. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/entry_points.txt +0 -0
@@ -1,27 +1,43 @@
1
- import json
2
1
  import subprocess
2
+ import sys
3
3
 
4
+ if sys.version_info >= (3, 12):
5
+ from typing import TypedDict
6
+ else:
7
+ from typing_extensions import TypedDict
4
8
 
5
- def run_shell_command(command: str) -> str:
9
+
10
+ class ShellCommandResult(TypedDict):
11
+ """
12
+ Result of shell command execution
13
+
14
+ Attributes:
15
+ return_code: The return code, 0 indicating no error
16
+ stdout: Standard output
17
+ stderr: Standard error
18
+ """
19
+
20
+ return_code: int
21
+ stdout: str
22
+ stderr: str
23
+
24
+
25
+ def run_shell_command(command: str) -> ShellCommandResult:
6
26
  """
7
- Executes a shell command on the user's local machine and returns the output.
27
+ Executes a non-interactive shell command on the user's machine.
8
28
 
9
- This tool is powerful and should be used for tasks that require interacting
10
- with the command line, such as running scripts, managing system processes,
11
- or using command-line tools.
29
+ CRITICAL: This tool runs with user-level permissions. Explain commands that modify
30
+ the system (e.g., `git`, `pip`) and ask for confirmation.
31
+ IMPORTANT: Long-running processes should be run in the background (e.g., `command &`).
12
32
 
13
- **Security Warning:** This tool executes commands with the same permissions
14
- as the user running the assistant. Before executing any command that could
15
- modify files or system state (e.g., `git`, `npm`, `pip`, `docker`), you
16
- MUST explain what the command does and ask the user for confirmation.
33
+ Example:
34
+ run_shell_command(command='ls -l')
17
35
 
18
36
  Args:
19
- command (str): The exact shell command to execute.
37
+ command (str): The exact shell command to be executed.
20
38
 
21
39
  Returns:
22
- str: A JSON string containing return code, standard output (stdout),
23
- and standard error (stderr) from the command.
24
- Example: {"return_code": 0, "stdout": "ok", "stderr": ""}
40
+ dict: return_code, stdout, and stderr.
25
41
  """
26
42
  result = subprocess.run(
27
43
  command,
@@ -29,10 +45,8 @@ def run_shell_command(command: str) -> str:
29
45
  capture_output=True,
30
46
  text=True,
31
47
  )
32
- return json.dumps(
33
- {
34
- "return_code": result.returncode,
35
- "stdout": result.stdout,
36
- "stderr": result.stderr,
37
- }
38
- )
48
+ return {
49
+ "return_code": result.returncode,
50
+ "stdout": result.stdout,
51
+ "stderr": result.stderr,
52
+ }
@@ -6,6 +6,7 @@ from zrb.builtin.llm.tool.sub_agent import create_sub_agent_tool
6
6
  from zrb.config.config import CFG
7
7
  from zrb.config.llm_rate_limitter import llm_rate_limitter
8
8
  from zrb.context.any_context import AnyContext
9
+ from zrb.util.cli.style import stylize_faint
9
10
 
10
11
  _DEFAULT_EXTENSIONS = [
11
12
  "py",
@@ -49,60 +50,37 @@ _DEFAULT_EXTENSIONS = [
49
50
  async def analyze_repo(
50
51
  ctx: AnyContext,
51
52
  path: str,
52
- goal: str,
53
+ query: str,
53
54
  extensions: list[str] = _DEFAULT_EXTENSIONS,
54
55
  exclude_patterns: list[str] = DEFAULT_EXCLUDED_PATTERNS,
55
56
  extraction_token_threshold: int | None = None,
56
57
  summarization_token_threshold: int | None = None,
57
58
  ) -> str:
58
59
  """
59
- Performs a deep, goal-oriented analysis of a code repository or directory.
60
-
61
- This powerful tool recursively reads all relevant files in a directory,
62
- extracts key information, and then summarizes that information in relation
63
- to a specific goal. It uses intelligent sub-agents for extraction and
64
- summarization, making it ideal for complex tasks that require a holistic
65
- understanding of a codebase.
66
-
67
- To ensure a focused and effective analysis, it is crucial to provide a
68
- clear and specific goal. Vague goals will result in a vague analysis and
69
- may cause the tool to run for a long time.
70
-
71
- Use this tool for:
72
- - Understanding a large or unfamiliar codebase.
73
- - Generating high-level summaries of a project's architecture.
74
- - Performing a preliminary code review.
75
- - Creating documentation or diagrams (e.g., "Generate a Mermaid C4 diagram
76
- for this service").
77
- - Answering broad questions like "How does the authentication in this
78
- project work?".
60
+ Analyzes a code repository or directory to answer a specific query.
61
+
62
+ CRITICAL: The quality of analysis depends entirely on the query. Vague queries yield poor
63
+ results.
64
+ IMPORTANT: This tool can be slow and expensive on large repositories. Use judiciously.
65
+
66
+ Example:
67
+ analyze_repo(
68
+ path='src/my_project',
69
+ query='Summarize the main functionalities by analyzing Python files.',
70
+ extensions=['py']
71
+ )
79
72
 
80
73
  Args:
81
- path (str): The path to the directory or repository to analyze.
82
- goal (str): A clear and specific description of what you want to
83
- achieve. A good goal is critical for getting a useful result.
84
- - Good goal: "Understand the database schema by analyzing all the
85
- .sql files"
86
- - Good goal: "Create a summary of all the API endpoints defined in
87
- the 'api' directory"
88
- - Bad goal: "Analyze the repo"
89
- - Bad goal: "Tell me about the code"
90
- extensions (list[str], optional): A list of file extensions to include
91
- in the analysis. Defaults to a comprehensive list of common code
92
- and configuration files.
93
- exclude_patterns (list[str], optional): A list of glob patterns for
94
- files and directories to exclude from the analysis. Defaults to
95
- common patterns like '.git', 'node_modules', and '.venv'.
96
- extraction_token_threshold (int, optional): The maximum token
97
- threshold for the extraction sub-agent.
98
- summarization_token_threshold (int, optional): The maximum token
99
- threshold for the summarization sub-agent.
74
+ ctx (AnyContext): The execution context.
75
+ path (str): Path to the directory or repository.
76
+ query (str): Clear and specific analysis question or goal.
77
+ extensions (list[str], optional): File extensions to include.
78
+ exclude_patterns (list[str], optional): Glob patterns to exclude.
79
+ extraction_token_threshold (int, optional): Token limit for extraction sub-agent.
80
+ summarization_token_threshold (int, optional): Token limit for summarization sub-agent.
100
81
 
101
82
  Returns:
102
- str: A detailed, markdown-formatted analysis and summary of the
103
- repository, tailored to the specified goal.
104
- Raises:
105
- Exception: If an error occurs during the analysis.
83
+ str: Detailed, markdown-formatted analysis and summary.
106
84
  """
107
85
  if extraction_token_threshold is None:
108
86
  extraction_token_threshold = CFG.LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD
@@ -112,23 +90,26 @@ async def analyze_repo(
112
90
  )
113
91
  abs_path = os.path.abspath(os.path.expanduser(path))
114
92
  file_metadatas = _get_file_metadatas(abs_path, extensions, exclude_patterns)
115
- ctx.print("Extraction")
93
+ ctx.print(stylize_faint(" 📝 Extraction"), plain=True)
116
94
  extracted_infos = await _extract_info(
117
95
  ctx,
118
96
  file_metadatas=file_metadatas,
119
- goal=goal,
97
+ query=query,
120
98
  token_limit=extraction_token_threshold,
121
99
  )
100
+ if len(extracted_infos) == 0:
101
+ raise RuntimeError(
102
+ "No info can be extracted, adjust extensions or exclude_patterns."
103
+ )
122
104
  if len(extracted_infos) == 1:
123
105
  return extracted_infos[0]
124
- ctx.print("Summarization")
125
106
  summarized_infos = extracted_infos
126
107
  while len(summarized_infos) > 1:
127
- ctx.print("Summarization")
108
+ ctx.print(stylize_faint(" 📝 Summarization"), plain=True)
128
109
  summarized_infos = await _summarize_info(
129
110
  ctx,
130
111
  extracted_infos=summarized_infos,
131
- goal=goal,
112
+ query=query,
132
113
  token_limit=summarization_token_threshold,
133
114
  )
134
115
  return summarized_infos[0]
@@ -146,11 +127,11 @@ def _get_file_metadatas(
146
127
  if not any(file.endswith(f".{ext}") for ext in extensions):
147
128
  continue
148
129
  file_path = os.path.join(root, file)
149
- if is_excluded(file_path, exclude_patterns):
150
- continue
151
130
  try:
131
+ rel_path = os.path.relpath(file_path, dir_path)
132
+ if is_excluded(rel_path, exclude_patterns):
133
+ continue
152
134
  with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
153
- rel_path = os.path.relpath(file_path, dir_path)
154
135
  metadata_list.append({"path": rel_path, "content": f.read()})
155
136
  except Exception as e:
156
137
  print(f"Error reading file {file_path}: {e}")
@@ -161,13 +142,15 @@ def _get_file_metadatas(
161
142
  async def _extract_info(
162
143
  ctx: AnyContext,
163
144
  file_metadatas: list[dict[str, str]],
164
- goal: str,
145
+ query: str,
165
146
  token_limit: int,
166
147
  ) -> list[str]:
167
148
  extract = create_sub_agent_tool(
168
149
  tool_name="extract",
169
150
  tool_description="extract",
170
151
  system_prompt=CFG.LLM_REPO_EXTRACTOR_SYSTEM_PROMPT,
152
+ auto_summarize=False,
153
+ remember_history=False,
171
154
  )
172
155
  extracted_infos = []
173
156
  content_buffer = []
@@ -179,7 +162,7 @@ async def _extract_info(
179
162
  file_str = json.dumps(file_obj)
180
163
  if current_token_count + llm_rate_limitter.count_token(file_str) > token_limit:
181
164
  if content_buffer:
182
- prompt = _create_extract_info_prompt(goal, content_buffer)
165
+ prompt = json.dumps(_create_extract_info_prompt(query, content_buffer))
183
166
  extracted_info = await extract(
184
167
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
185
168
  )
@@ -189,10 +172,9 @@ async def _extract_info(
189
172
  else:
190
173
  content_buffer.append(file_obj)
191
174
  current_token_count += llm_rate_limitter.count_token(file_str)
192
-
193
175
  # Process any remaining content in the buffer
194
176
  if content_buffer:
195
- prompt = _create_extract_info_prompt(goal, content_buffer)
177
+ prompt = json.dumps(_create_extract_info_prompt(query, content_buffer))
196
178
  extracted_info = await extract(
197
179
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
198
180
  )
@@ -200,25 +182,25 @@ async def _extract_info(
200
182
  return extracted_infos
201
183
 
202
184
 
203
- def _create_extract_info_prompt(goal: str, content_buffer: list[dict]) -> str:
204
- return json.dumps(
205
- {
206
- "main_assistant_goal": goal,
207
- "files": content_buffer,
208
- }
209
- )
185
+ def _create_extract_info_prompt(query: str, content_buffer: list[dict]) -> dict:
186
+ return {
187
+ "main_assistant_query": query,
188
+ "files": content_buffer,
189
+ }
210
190
 
211
191
 
212
192
  async def _summarize_info(
213
193
  ctx: AnyContext,
214
194
  extracted_infos: list[str],
215
- goal: str,
195
+ query: str,
216
196
  token_limit: int,
217
197
  ) -> list[str]:
218
198
  summarize = create_sub_agent_tool(
219
199
  tool_name="extract",
220
200
  tool_description="extract",
221
201
  system_prompt=CFG.LLM_REPO_SUMMARIZER_SYSTEM_PROMPT,
202
+ auto_summarize=False,
203
+ remember_history=False,
222
204
  )
223
205
  summarized_infos = []
224
206
  content_buffer = ""
@@ -226,7 +208,9 @@ async def _summarize_info(
226
208
  new_prompt = content_buffer + extracted_info
227
209
  if llm_rate_limitter.count_token(new_prompt) > token_limit:
228
210
  if content_buffer:
229
- prompt = _create_summarize_info_prompt(goal, content_buffer)
211
+ prompt = json.dumps(
212
+ _create_summarize_info_prompt(query, content_buffer)
213
+ )
230
214
  summarized_info = await summarize(
231
215
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
232
216
  )
@@ -237,7 +221,7 @@ async def _summarize_info(
237
221
 
238
222
  # Process any remaining content in the buffer
239
223
  if content_buffer:
240
- prompt = _create_summarize_info_prompt(goal, content_buffer)
224
+ prompt = json.dumps(_create_summarize_info_prompt(query, content_buffer))
241
225
  summarized_info = await summarize(
242
226
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
243
227
  )
@@ -245,10 +229,8 @@ async def _summarize_info(
245
229
  return summarized_infos
246
230
 
247
231
 
248
- def _create_summarize_info_prompt(goal: str, content_buffer: str) -> str:
249
- return json.dumps(
250
- {
251
- "main_assistant_goal": goal,
252
- "extracted_info": content_buffer,
253
- }
254
- )
232
+ def _create_summarize_info_prompt(query: str, content_buffer: str) -> dict:
233
+ return {
234
+ "main_assistant_query": query,
235
+ "extracted_info": content_buffer,
236
+ }