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.
- zrb/__init__.py +2 -6
- zrb/attr/type.py +10 -7
- zrb/builtin/__init__.py +2 -0
- zrb/builtin/git.py +12 -1
- zrb/builtin/group.py +31 -15
- zrb/builtin/llm/attachment.py +40 -0
- zrb/builtin/llm/chat_completion.py +274 -0
- zrb/builtin/llm/chat_session.py +126 -167
- zrb/builtin/llm/chat_session_cmd.py +288 -0
- zrb/builtin/llm/chat_trigger.py +79 -0
- zrb/builtin/llm/history.py +4 -4
- zrb/builtin/llm/llm_ask.py +217 -135
- zrb/builtin/llm/tool/api.py +74 -70
- zrb/builtin/llm/tool/cli.py +35 -21
- zrb/builtin/llm/tool/code.py +55 -73
- zrb/builtin/llm/tool/file.py +278 -344
- zrb/builtin/llm/tool/note.py +84 -0
- zrb/builtin/llm/tool/rag.py +27 -34
- zrb/builtin/llm/tool/sub_agent.py +54 -41
- zrb/builtin/llm/tool/web.py +74 -98
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
- zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
- zrb/builtin/searxng/config/settings.yml +5671 -0
- zrb/builtin/searxng/start.py +21 -0
- zrb/builtin/shell/autocomplete/bash.py +4 -3
- zrb/builtin/shell/autocomplete/zsh.py +4 -3
- zrb/config/config.py +202 -27
- zrb/config/default_prompt/file_extractor_system_prompt.md +109 -9
- zrb/config/default_prompt/interactive_system_prompt.md +24 -30
- zrb/config/default_prompt/persona.md +1 -1
- zrb/config/default_prompt/repo_extractor_system_prompt.md +31 -31
- zrb/config/default_prompt/repo_summarizer_system_prompt.md +27 -8
- zrb/config/default_prompt/summarization_prompt.md +57 -16
- zrb/config/default_prompt/system_prompt.md +36 -30
- zrb/config/llm_config.py +119 -23
- zrb/config/llm_context/config.py +127 -90
- zrb/config/llm_context/config_parser.py +1 -7
- zrb/config/llm_context/workflow.py +81 -0
- zrb/config/llm_rate_limitter.py +100 -47
- zrb/context/any_shared_context.py +7 -1
- zrb/context/context.py +8 -2
- zrb/context/shared_context.py +3 -7
- zrb/group/any_group.py +3 -3
- zrb/group/group.py +3 -3
- zrb/input/any_input.py +5 -1
- zrb/input/base_input.py +18 -6
- zrb/input/option_input.py +13 -1
- zrb/input/text_input.py +7 -24
- zrb/runner/cli.py +21 -20
- zrb/runner/common_util.py +24 -19
- zrb/runner/web_route/task_input_api_route.py +5 -5
- zrb/runner/web_util/user.py +7 -3
- zrb/session/any_session.py +12 -6
- zrb/session/session.py +39 -18
- zrb/task/any_task.py +24 -3
- zrb/task/base/context.py +17 -9
- zrb/task/base/execution.py +15 -8
- zrb/task/base/lifecycle.py +8 -4
- zrb/task/base/monitoring.py +12 -7
- zrb/task/base_task.py +69 -5
- zrb/task/base_trigger.py +12 -5
- zrb/task/llm/agent.py +128 -167
- zrb/task/llm/agent_runner.py +152 -0
- zrb/task/llm/config.py +39 -20
- zrb/task/llm/conversation_history.py +110 -29
- zrb/task/llm/conversation_history_model.py +4 -179
- zrb/task/llm/default_workflow/coding/workflow.md +41 -0
- zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
- zrb/task/llm/default_workflow/git/workflow.md +118 -0
- zrb/task/llm/default_workflow/golang/workflow.md +128 -0
- zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
- zrb/task/llm/default_workflow/java/workflow.md +146 -0
- zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
- zrb/task/llm/default_workflow/python/workflow.md +160 -0
- zrb/task/llm/default_workflow/researching/workflow.md +153 -0
- zrb/task/llm/default_workflow/rust/workflow.md +162 -0
- zrb/task/llm/default_workflow/shell/workflow.md +299 -0
- zrb/task/llm/file_replacement.py +206 -0
- zrb/task/llm/file_tool_model.py +57 -0
- zrb/task/llm/history_processor.py +206 -0
- zrb/task/llm/history_summarization.py +2 -193
- zrb/task/llm/print_node.py +184 -64
- zrb/task/llm/prompt.py +175 -179
- zrb/task/llm/subagent_conversation_history.py +41 -0
- zrb/task/llm/tool_wrapper.py +226 -85
- zrb/task/llm/workflow.py +76 -0
- zrb/task/llm_task.py +109 -71
- zrb/task/make_task.py +2 -3
- zrb/task/rsync_task.py +25 -10
- zrb/task/scheduler.py +4 -4
- zrb/util/attr.py +54 -39
- zrb/util/cli/markdown.py +12 -0
- zrb/util/cli/text.py +30 -0
- zrb/util/file.py +12 -3
- zrb/util/git.py +2 -2
- zrb/util/{llm/prompt.py → markdown.py} +2 -3
- zrb/util/string/conversion.py +1 -1
- zrb/util/truncate.py +23 -0
- zrb/util/yaml.py +204 -0
- zrb/xcom/xcom.py +10 -0
- {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/METADATA +38 -18
- {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/RECORD +105 -79
- {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/WHEEL +1 -1
- zrb/task/llm/default_workflow/coding.md +0 -24
- zrb/task/llm/default_workflow/copywriting.md +0 -17
- zrb/task/llm/default_workflow/researching.md +0 -18
- {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/entry_points.txt +0 -0
zrb/builtin/llm/tool/cli.py
CHANGED
|
@@ -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
|
-
|
|
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
|
|
27
|
+
Executes a non-interactive shell command on the user's machine.
|
|
8
28
|
|
|
9
|
-
This tool
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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
|
|
37
|
+
command (str): The exact shell command to be executed.
|
|
20
38
|
|
|
21
39
|
Returns:
|
|
22
|
-
|
|
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
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
)
|
|
48
|
+
return {
|
|
49
|
+
"return_code": result.returncode,
|
|
50
|
+
"stdout": result.stdout,
|
|
51
|
+
"stderr": result.stderr,
|
|
52
|
+
}
|
zrb/builtin/llm/tool/code.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
204
|
-
return
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
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 =
|
|
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(
|
|
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(
|
|
249
|
-
return
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
+
}
|