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
@@ -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,36 +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
+ Analyzes a code repository or directory to answer a specific query.
60
61
 
61
- This powerful tool recursively reads all relevant files in a directory, extracts key information, and then summarizes that information in relation to a specific goal. It uses intelligent sub-agents for extraction and summarization, making it ideal for complex tasks that require a holistic understanding of a codebase.
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.
62
65
 
63
- Use this tool for:
64
- - Understanding a large or unfamiliar codebase.
65
- - Generating high-level summaries of a project's architecture.
66
- - Performing a preliminary code review.
67
- - Creating documentation or diagrams (e.g., "Generate a Mermaid C4 diagram for this service").
68
- - Answering broad questions like "How does the authentication in this project work?".
66
+ Example:
67
+ analyze_repo(
68
+ path='src/my_project',
69
+ query='Summarize the main functionalities by analyzing Python files.',
70
+ extensions=['py']
71
+ )
69
72
 
70
73
  Args:
71
- path (str): The path to the directory or repository to analyze.
72
- goal (str): A clear and specific description of what you want to achieve. A good goal is critical for getting a useful result. For example: "Understand the database schema by analyzing all the .sql files" or "Create a summary of all the API endpoints defined in the 'api' directory".
73
- extensions (list[str], optional): A list of file extensions to include in the analysis. Defaults to a comprehensive list of common code and configuration files.
74
- exclude_patterns (list[str], optional): A list of glob patterns for files and directories to exclude from the analysis. Defaults to common patterns like '.git', 'node_modules', and '.venv'.
75
- extraction_token_threshold (int, optional): The maximum token threshold for the extraction sub-agent.
76
- summarization_token_threshold (int, optional): The maximum token 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.
77
81
 
78
82
  Returns:
79
- str: A detailed, markdown-formatted analysis and summary of the repository, tailored to the specified goal.
80
- Raises:
81
- Exception: If an error occurs during the analysis.
83
+ str: Detailed, markdown-formatted analysis and summary.
82
84
  """
83
85
  if extraction_token_threshold is None:
84
86
  extraction_token_threshold = CFG.LLM_REPO_ANALYSIS_EXTRACTION_TOKEN_THRESHOLD
@@ -88,23 +90,26 @@ async def analyze_repo(
88
90
  )
89
91
  abs_path = os.path.abspath(os.path.expanduser(path))
90
92
  file_metadatas = _get_file_metadatas(abs_path, extensions, exclude_patterns)
91
- ctx.print("Extraction")
93
+ ctx.print(stylize_faint(" 📝 Extraction"), plain=True)
92
94
  extracted_infos = await _extract_info(
93
95
  ctx,
94
96
  file_metadatas=file_metadatas,
95
- goal=goal,
97
+ query=query,
96
98
  token_limit=extraction_token_threshold,
97
99
  )
100
+ if len(extracted_infos) == 0:
101
+ raise RuntimeError(
102
+ "No info can be extracted, adjust extensions or exclude_patterns."
103
+ )
98
104
  if len(extracted_infos) == 1:
99
105
  return extracted_infos[0]
100
- ctx.print("Summarization")
101
106
  summarized_infos = extracted_infos
102
107
  while len(summarized_infos) > 1:
103
- ctx.print("Summarization")
108
+ ctx.print(stylize_faint(" 📝 Summarization"), plain=True)
104
109
  summarized_infos = await _summarize_info(
105
110
  ctx,
106
111
  extracted_infos=summarized_infos,
107
- goal=goal,
112
+ query=query,
108
113
  token_limit=summarization_token_threshold,
109
114
  )
110
115
  return summarized_infos[0]
@@ -122,11 +127,11 @@ def _get_file_metadatas(
122
127
  if not any(file.endswith(f".{ext}") for ext in extensions):
123
128
  continue
124
129
  file_path = os.path.join(root, file)
125
- if is_excluded(file_path, exclude_patterns):
126
- continue
127
130
  try:
131
+ rel_path = os.path.relpath(file_path, dir_path)
132
+ if is_excluded(rel_path, exclude_patterns):
133
+ continue
128
134
  with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
129
- rel_path = os.path.relpath(file_path, dir_path)
130
135
  metadata_list.append({"path": rel_path, "content": f.read()})
131
136
  except Exception as e:
132
137
  print(f"Error reading file {file_path}: {e}")
@@ -137,7 +142,7 @@ def _get_file_metadatas(
137
142
  async def _extract_info(
138
143
  ctx: AnyContext,
139
144
  file_metadatas: list[dict[str, str]],
140
- goal: str,
145
+ query: str,
141
146
  token_limit: int,
142
147
  ) -> list[str]:
143
148
  extract = create_sub_agent_tool(
@@ -155,7 +160,7 @@ async def _extract_info(
155
160
  file_str = json.dumps(file_obj)
156
161
  if current_token_count + llm_rate_limitter.count_token(file_str) > token_limit:
157
162
  if content_buffer:
158
- prompt = _create_extract_info_prompt(goal, content_buffer)
163
+ prompt = json.dumps(_create_extract_info_prompt(query, content_buffer))
159
164
  extracted_info = await extract(
160
165
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
161
166
  )
@@ -165,10 +170,9 @@ async def _extract_info(
165
170
  else:
166
171
  content_buffer.append(file_obj)
167
172
  current_token_count += llm_rate_limitter.count_token(file_str)
168
-
169
173
  # Process any remaining content in the buffer
170
174
  if content_buffer:
171
- prompt = _create_extract_info_prompt(goal, content_buffer)
175
+ prompt = json.dumps(_create_extract_info_prompt(query, content_buffer))
172
176
  extracted_info = await extract(
173
177
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
174
178
  )
@@ -176,19 +180,17 @@ async def _extract_info(
176
180
  return extracted_infos
177
181
 
178
182
 
179
- def _create_extract_info_prompt(goal: str, content_buffer: list[dict]) -> str:
180
- return json.dumps(
181
- {
182
- "main_assistant_goal": goal,
183
- "files": content_buffer,
184
- }
185
- )
183
+ def _create_extract_info_prompt(query: str, content_buffer: list[dict]) -> dict:
184
+ return {
185
+ "main_assistant_query": query,
186
+ "files": content_buffer,
187
+ }
186
188
 
187
189
 
188
190
  async def _summarize_info(
189
191
  ctx: AnyContext,
190
192
  extracted_infos: list[str],
191
- goal: str,
193
+ query: str,
192
194
  token_limit: int,
193
195
  ) -> list[str]:
194
196
  summarize = create_sub_agent_tool(
@@ -202,7 +204,9 @@ async def _summarize_info(
202
204
  new_prompt = content_buffer + extracted_info
203
205
  if llm_rate_limitter.count_token(new_prompt) > token_limit:
204
206
  if content_buffer:
205
- prompt = _create_summarize_info_prompt(goal, content_buffer)
207
+ prompt = json.dumps(
208
+ _create_summarize_info_prompt(query, content_buffer)
209
+ )
206
210
  summarized_info = await summarize(
207
211
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
208
212
  )
@@ -213,7 +217,7 @@ async def _summarize_info(
213
217
 
214
218
  # Process any remaining content in the buffer
215
219
  if content_buffer:
216
- prompt = _create_summarize_info_prompt(goal, content_buffer)
220
+ prompt = json.dumps(_create_summarize_info_prompt(query, content_buffer))
217
221
  summarized_info = await summarize(
218
222
  ctx, llm_rate_limitter.clip_prompt(prompt, token_limit)
219
223
  )
@@ -221,10 +225,8 @@ async def _summarize_info(
221
225
  return summarized_infos
222
226
 
223
227
 
224
- def _create_summarize_info_prompt(goal: str, content_buffer: str) -> str:
225
- return json.dumps(
226
- {
227
- "main_assistant_goal": goal,
228
- "extracted_info": content_buffer,
229
- }
230
- )
228
+ def _create_summarize_info_prompt(query: str, content_buffer: str) -> dict:
229
+ return {
230
+ "main_assistant_query": query,
231
+ "extracted_info": content_buffer,
232
+ }