zrb 1.17.3__py3-none-any.whl → 1.18.0__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.
- zrb/builtin/llm/chat_session.py +17 -17
- zrb/builtin/llm/llm_ask.py +8 -6
- zrb/builtin/llm/tool/web.py +28 -4
- zrb/config/config.py +48 -6
- zrb/config/default_prompt/interactive_system_prompt.md +1 -1
- zrb/config/default_prompt/system_prompt.md +1 -1
- zrb/config/llm_config.py +14 -14
- zrb/config/llm_context/config.py +27 -4
- zrb/task/llm/agent.py +1 -1
- zrb/task/llm/default_workflow/coding/git.md +142 -0
- zrb/task/llm/default_workflow/coding/golang.md +23 -0
- zrb/task/llm/default_workflow/coding/javascript.md +24 -0
- zrb/task/llm/default_workflow/coding/python.md +23 -0
- zrb/task/llm/default_workflow/coding/rust.md +23 -0
- zrb/task/llm/default_workflow/coding/shell.md +245 -0
- zrb/task/llm/default_workflow/coding/workflow.md +67 -0
- zrb/task/llm/prompt.py +82 -76
- zrb/task/llm/tool_wrapper.py +20 -14
- zrb/task/llm_task.py +8 -9
- zrb/task/rsync_task.py +25 -10
- zrb/util/attr.py +5 -1
- {zrb-1.17.3.dist-info → zrb-1.18.0.dist-info}/METADATA +1 -1
- {zrb-1.17.3.dist-info → zrb-1.18.0.dist-info}/RECORD +27 -21
- zrb/task/llm/default_workflow/coding.md +0 -64
- /zrb/task/llm/default_workflow/{copywriting.md → copywriting/workflow.md} +0 -0
- /zrb/task/llm/default_workflow/{researching.md → researching/workflow.md} +0 -0
- {zrb-1.17.3.dist-info → zrb-1.18.0.dist-info}/WHEEL +0 -0
- {zrb-1.17.3.dist-info → zrb-1.18.0.dist-info}/entry_points.txt +0 -0
zrb/builtin/llm/chat_session.py
CHANGED
|
@@ -32,7 +32,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
|
|
|
32
32
|
reader: PromptSession[Any] | StreamReader = await _setup_input_reader(is_tty)
|
|
33
33
|
multiline_mode = False
|
|
34
34
|
is_first_time = True
|
|
35
|
-
|
|
35
|
+
current_workflows: str = ctx.input.workflows
|
|
36
36
|
current_yolo_mode: bool | str = ctx.input.yolo
|
|
37
37
|
user_inputs: list[str] = []
|
|
38
38
|
final_result: str = ""
|
|
@@ -59,7 +59,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
|
|
|
59
59
|
result = await _trigger_ask_and_wait_for_result(
|
|
60
60
|
ctx=ctx,
|
|
61
61
|
user_prompt=user_prompt,
|
|
62
|
-
|
|
62
|
+
workflows=current_workflows,
|
|
63
63
|
yolo_mode=current_yolo_mode,
|
|
64
64
|
previous_session_name=previous_session_name,
|
|
65
65
|
start_new=start_new,
|
|
@@ -77,7 +77,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
|
|
|
77
77
|
result = await _trigger_ask_and_wait_for_result(
|
|
78
78
|
ctx=ctx,
|
|
79
79
|
user_prompt=user_prompt,
|
|
80
|
-
|
|
80
|
+
workflows=current_workflows,
|
|
81
81
|
yolo_mode=current_yolo_mode,
|
|
82
82
|
previous_session_name=previous_session_name,
|
|
83
83
|
start_new=start_new,
|
|
@@ -86,18 +86,18 @@ async def read_user_prompt(ctx: AnyContext) -> str:
|
|
|
86
86
|
final_result = result
|
|
87
87
|
if ctx.is_web_mode or not is_tty:
|
|
88
88
|
return final_result
|
|
89
|
-
elif user_input.strip().lower().startswith("/
|
|
90
|
-
|
|
91
|
-
if len(
|
|
92
|
-
|
|
93
|
-
ctx.print(f"Current
|
|
89
|
+
elif user_input.strip().lower().startswith("/workflow"):
|
|
90
|
+
workflow_parts = user_input.split(" ", maxsplit=2)
|
|
91
|
+
if len(workflow_parts) > 1:
|
|
92
|
+
current_workflows = workflow_parts[1]
|
|
93
|
+
ctx.print(f"Current workflows: {current_workflows}", plain=True)
|
|
94
94
|
ctx.print("", plain=True)
|
|
95
95
|
continue
|
|
96
96
|
elif user_input.strip().lower().startswith("/yolo"):
|
|
97
97
|
yolo_mode_parts = user_input.split(" ", maxsplit=2)
|
|
98
98
|
if len(yolo_mode_parts) > 1:
|
|
99
99
|
current_yolo_mode = to_boolean(yolo_mode_parts[1])
|
|
100
|
-
ctx.print(f"
|
|
100
|
+
ctx.print(f"Current YOLO mode: {current_yolo_mode}", plain=True)
|
|
101
101
|
ctx.print("", plain=True)
|
|
102
102
|
continue
|
|
103
103
|
elif user_input.strip().lower() in ("/help", "/info"):
|
|
@@ -112,7 +112,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
|
|
|
112
112
|
result = await _trigger_ask_and_wait_for_result(
|
|
113
113
|
ctx=ctx,
|
|
114
114
|
user_prompt=user_prompt,
|
|
115
|
-
|
|
115
|
+
workflows=current_workflows,
|
|
116
116
|
yolo_mode=current_yolo_mode,
|
|
117
117
|
previous_session_name=previous_session_name,
|
|
118
118
|
start_new=start_new,
|
|
@@ -136,8 +136,8 @@ def _show_info(ctx: AnyContext):
|
|
|
136
136
|
_show_command("/bye", "Quit from chat session"),
|
|
137
137
|
_show_command("/multi", "Start multiline input"),
|
|
138
138
|
_show_command("/end", "End multiline input"),
|
|
139
|
-
_show_command("/
|
|
140
|
-
_show_subcommand("<
|
|
139
|
+
_show_command("/workflows", "Show current workflows"),
|
|
140
|
+
_show_subcommand("<wf1,wf2,..>", "Set current workflows"),
|
|
141
141
|
_show_command("/yolo", "Get current YOLO mode"),
|
|
142
142
|
_show_subcommand("<true|false|list-of-tools>", "Set YOLO mode"),
|
|
143
143
|
_show_command("/help", "Show this message"),
|
|
@@ -179,7 +179,7 @@ async def _setup_input_reader(
|
|
|
179
179
|
async def _trigger_ask_and_wait_for_result(
|
|
180
180
|
ctx: AnyContext,
|
|
181
181
|
user_prompt: str,
|
|
182
|
-
|
|
182
|
+
workflows: str,
|
|
183
183
|
yolo_mode: bool | str,
|
|
184
184
|
previous_session_name: str | None = None,
|
|
185
185
|
start_new: bool = False,
|
|
@@ -199,7 +199,7 @@ async def _trigger_ask_and_wait_for_result(
|
|
|
199
199
|
if user_prompt.strip() == "":
|
|
200
200
|
return None
|
|
201
201
|
await _trigger_ask(
|
|
202
|
-
ctx, user_prompt,
|
|
202
|
+
ctx, user_prompt, workflows, yolo_mode, previous_session_name, start_new
|
|
203
203
|
)
|
|
204
204
|
result = await _wait_ask_result(ctx)
|
|
205
205
|
md_result = render_markdown(result) if result is not None else ""
|
|
@@ -231,7 +231,7 @@ def get_llm_ask_input_mapping(callback_ctx: AnyContext):
|
|
|
231
231
|
"start-new": data.get("start_new"),
|
|
232
232
|
"previous-session": data.get("previous_session_name"),
|
|
233
233
|
"message": data.get("message"),
|
|
234
|
-
"
|
|
234
|
+
"workflows": data.get("workflows"),
|
|
235
235
|
"yolo": data.get("yolo"),
|
|
236
236
|
}
|
|
237
237
|
|
|
@@ -239,7 +239,7 @@ def get_llm_ask_input_mapping(callback_ctx: AnyContext):
|
|
|
239
239
|
async def _trigger_ask(
|
|
240
240
|
ctx: AnyContext,
|
|
241
241
|
user_prompt: str,
|
|
242
|
-
|
|
242
|
+
workflows: str,
|
|
243
243
|
yolo_mode: bool | str,
|
|
244
244
|
previous_session_name: str | None = None,
|
|
245
245
|
start_new: bool = False,
|
|
@@ -260,7 +260,7 @@ async def _trigger_ask(
|
|
|
260
260
|
"previous_session_name": previous_session_name,
|
|
261
261
|
"start_new": start_new,
|
|
262
262
|
"message": user_prompt,
|
|
263
|
-
"
|
|
263
|
+
"workflows": workflows,
|
|
264
264
|
"yolo": yolo_mode,
|
|
265
265
|
}
|
|
266
266
|
)
|
zrb/builtin/llm/llm_ask.py
CHANGED
|
@@ -152,10 +152,10 @@ def _get_inputs(require_message: bool = True) -> list[AnyInput | None]:
|
|
|
152
152
|
always_prompt=False,
|
|
153
153
|
),
|
|
154
154
|
TextInput(
|
|
155
|
-
"
|
|
156
|
-
description="
|
|
157
|
-
prompt="
|
|
158
|
-
default=lambda ctx: ",".join(llm_config.
|
|
155
|
+
"workflows",
|
|
156
|
+
description="Workflows",
|
|
157
|
+
prompt="Workflows",
|
|
158
|
+
default=lambda ctx: ",".join(llm_config.default_workflows),
|
|
159
159
|
allow_positional_parsing=False,
|
|
160
160
|
always_prompt=False,
|
|
161
161
|
),
|
|
@@ -210,8 +210,10 @@ llm_ask: LLMTask = llm_group.add_task(
|
|
|
210
210
|
system_prompt=lambda ctx: (
|
|
211
211
|
None if ctx.input.system_prompt.strip() == "" else ctx.input.system_prompt
|
|
212
212
|
),
|
|
213
|
-
|
|
214
|
-
None
|
|
213
|
+
workflows=lambda ctx: (
|
|
214
|
+
None
|
|
215
|
+
if ctx.input.workflows.strip() == ""
|
|
216
|
+
else ctx.input.workflows.split(",")
|
|
215
217
|
),
|
|
216
218
|
message="{ctx.input.message}",
|
|
217
219
|
tools=_get_tool,
|
zrb/builtin/llm/tool/web.py
CHANGED
|
@@ -52,18 +52,41 @@ def create_search_internet_tool() -> Callable:
|
|
|
52
52
|
"""
|
|
53
53
|
import requests
|
|
54
54
|
|
|
55
|
-
if
|
|
55
|
+
if (
|
|
56
|
+
CFG.SEARCH_INTERNET_METHOD.strip().lower() == "serpapi"
|
|
57
|
+
and CFG.SERPAPI_KEY != ""
|
|
58
|
+
):
|
|
56
59
|
response = requests.get(
|
|
57
60
|
"https://serpapi.com/search",
|
|
58
61
|
headers={"User-Agent": _DEFAULT_USER_AGENT},
|
|
59
62
|
params={
|
|
60
63
|
"q": query,
|
|
61
64
|
"start": (page - 1) * 10,
|
|
62
|
-
"hl":
|
|
63
|
-
"safe":
|
|
65
|
+
"hl": CFG.SERPAPI_LANG,
|
|
66
|
+
"safe": CFG.SERPAPI_SAFE,
|
|
64
67
|
"api_key": CFG.SERPAPI_KEY,
|
|
65
68
|
},
|
|
66
69
|
)
|
|
70
|
+
elif (
|
|
71
|
+
CFG.SEARCH_INTERNET_METHOD.strip().lower() == "brave"
|
|
72
|
+
and CFG.BRAVE_API_KEY != ""
|
|
73
|
+
):
|
|
74
|
+
response = requests.get(
|
|
75
|
+
"https://api.search.brave.com/res/v1/web/search",
|
|
76
|
+
headers={
|
|
77
|
+
"User-Agent": _DEFAULT_USER_AGENT,
|
|
78
|
+
"Accept": "application/json",
|
|
79
|
+
"x-subscription-token": CFG.BRAVE_API_KEY,
|
|
80
|
+
},
|
|
81
|
+
params={
|
|
82
|
+
"q": query,
|
|
83
|
+
"count": "10",
|
|
84
|
+
"offset": (page - 1) * 10,
|
|
85
|
+
"safesearch": CFG.BRAVE_API_SAFE,
|
|
86
|
+
"search_lang": CFG.BRAVE_API_LANG,
|
|
87
|
+
"summary": "true",
|
|
88
|
+
},
|
|
89
|
+
)
|
|
67
90
|
else:
|
|
68
91
|
response = requests.get(
|
|
69
92
|
url=f"{CFG.SEARXNG_BASE_URL}/search",
|
|
@@ -72,7 +95,8 @@ def create_search_internet_tool() -> Callable:
|
|
|
72
95
|
"q": query,
|
|
73
96
|
"format": "json",
|
|
74
97
|
"pageno": page,
|
|
75
|
-
"safesearch":
|
|
98
|
+
"safesearch": CFG.SEARXNG_SAFE,
|
|
99
|
+
"language": CFG.SEARXNG_LANG,
|
|
76
100
|
},
|
|
77
101
|
)
|
|
78
102
|
if response.status_code != 200:
|
zrb/config/config.py
CHANGED
|
@@ -275,12 +275,26 @@ class Config:
|
|
|
275
275
|
return None if value == "" else value
|
|
276
276
|
|
|
277
277
|
@property
|
|
278
|
-
def
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
278
|
+
def LLM_WORKFLOWS(self) -> list[str]:
|
|
279
|
+
"""Get a list of LLM workflows from environment variables."""
|
|
280
|
+
workflows = []
|
|
281
|
+
for workflow in self._getenv("LLM_WORKFLOWS", "coding").split(","):
|
|
282
|
+
workflow = workflow.strip()
|
|
283
|
+
if workflow != "":
|
|
284
|
+
workflows.append(workflow)
|
|
285
|
+
return workflows
|
|
286
|
+
|
|
287
|
+
@property
|
|
288
|
+
def LLM_BUILTIN_WORKFLOW_PATHS(self) -> list[str]:
|
|
289
|
+
"""Get a list of additional builtin workflow paths from environment variables."""
|
|
290
|
+
builtin_workflow_paths_str = self._getenv("LLM_BUILTIN_WORKFLOW_PATHS", "")
|
|
291
|
+
if builtin_workflow_paths_str != "":
|
|
292
|
+
return [
|
|
293
|
+
path.strip()
|
|
294
|
+
for path in builtin_workflow_paths_str.split(":")
|
|
295
|
+
if path.strip() != ""
|
|
296
|
+
]
|
|
297
|
+
return []
|
|
284
298
|
|
|
285
299
|
@property
|
|
286
300
|
def LLM_SPECIAL_INSTRUCTION_PROMPT(self) -> str | None:
|
|
@@ -442,10 +456,30 @@ class Config:
|
|
|
442
456
|
"""Either serpapi or searxng"""
|
|
443
457
|
return self._getenv("SEARCH_INTERNET_METHOD", "serpapi")
|
|
444
458
|
|
|
459
|
+
@property
|
|
460
|
+
def BRAVE_API_KEY(self) -> str:
|
|
461
|
+
return os.getenv("BRAVE_API_KEY", "")
|
|
462
|
+
|
|
463
|
+
@property
|
|
464
|
+
def BRAVE_API_SAFE(self) -> str:
|
|
465
|
+
return self._getenv("BRAVE_API_SAFE", "off")
|
|
466
|
+
|
|
467
|
+
@property
|
|
468
|
+
def BRAVE_API_LANG(self) -> str:
|
|
469
|
+
return self._getenv("BRAVE_API_LANG", "en")
|
|
470
|
+
|
|
445
471
|
@property
|
|
446
472
|
def SERPAPI_KEY(self) -> str:
|
|
447
473
|
return os.getenv("SERPAPI_KEY", "")
|
|
448
474
|
|
|
475
|
+
@property
|
|
476
|
+
def SERPAPI_SAFE(self) -> str:
|
|
477
|
+
return self._getenv("SERPAPI_SAFE", "off")
|
|
478
|
+
|
|
479
|
+
@property
|
|
480
|
+
def SERPAPI_LANG(self) -> str:
|
|
481
|
+
return self._getenv("SERPAPI_LANG", "en")
|
|
482
|
+
|
|
449
483
|
@property
|
|
450
484
|
def SEARXNG_PORT(self) -> int:
|
|
451
485
|
return int(self._getenv("SEARXNG_PORT", "8080"))
|
|
@@ -454,6 +488,14 @@ class Config:
|
|
|
454
488
|
def SEARXNG_BASE_URL(self) -> str:
|
|
455
489
|
return self._getenv("SEARXNG_BASE_URL", f"http://localhost:{self.SEARXNG_PORT}")
|
|
456
490
|
|
|
491
|
+
@property
|
|
492
|
+
def SEARXNG_SAFE(self) -> int:
|
|
493
|
+
return int(self._getenv("SEARXNG_SAFE", "0"))
|
|
494
|
+
|
|
495
|
+
@property
|
|
496
|
+
def SEARXNG_LANG(self) -> str:
|
|
497
|
+
return self._getenv("SEARXNG_LANG", "en")
|
|
498
|
+
|
|
457
499
|
@property
|
|
458
500
|
def BANNER(self) -> str:
|
|
459
501
|
return fstring_format(
|
|
@@ -20,7 +20,7 @@ You are an expert interactive AI agent. You MUST follow this workflow for this i
|
|
|
20
20
|
|
|
21
21
|
3. **Execute and Verify (The E+V Loop):**
|
|
22
22
|
* Execute the action.
|
|
23
|
-
* **CRITICAL:** After each step, you MUST use a tool to verify the outcome (e.g., check command exit codes,
|
|
23
|
+
* **CRITICAL:** After each step, you MUST use a tool to verify the outcome (e.g., check command exit codes, verify changes has been applied, or new files has been created).
|
|
24
24
|
|
|
25
25
|
4. **Handle Errors (The Debugging Loop):**
|
|
26
26
|
* If an action fails, you MUST NOT give up. You MUST enter a persistent debugging loop until the error is resolved.
|
|
@@ -16,7 +16,7 @@ You are an expert AI agent fulfilling a single request. You must provide a compl
|
|
|
16
16
|
|
|
17
17
|
3. **Execute and Verify (The E+V Loop):**
|
|
18
18
|
* Execute each step of your plan.
|
|
19
|
-
* **CRITICAL:** After each step, you MUST use a tool to verify the outcome (e.g., check command exit codes,
|
|
19
|
+
* **CRITICAL:** After each step, you MUST use a tool to verify the outcome (e.g., check command exit codes, verify changes has been applied, or new files has been created).
|
|
20
20
|
|
|
21
21
|
4. **Handle Errors (The Debugging Loop):**
|
|
22
22
|
* If an action fails, you MUST NOT give up. You MUST enter a persistent debugging loop until the error is resolved.
|
zrb/config/llm_config.py
CHANGED
|
@@ -25,7 +25,7 @@ class LLMConfig:
|
|
|
25
25
|
default_summarization_prompt: str | None = None,
|
|
26
26
|
default_summarize_history: bool | None = None,
|
|
27
27
|
default_history_summarization_token_threshold: int | None = None,
|
|
28
|
-
|
|
28
|
+
default_workflows: list[str] | None = None,
|
|
29
29
|
default_model: "Model | None" = None,
|
|
30
30
|
default_model_settings: "ModelSettings | None" = None,
|
|
31
31
|
default_model_provider: "Provider | None" = None,
|
|
@@ -53,7 +53,7 @@ class LLMConfig:
|
|
|
53
53
|
self._default_history_summarization_token_threshold = (
|
|
54
54
|
default_history_summarization_token_threshold
|
|
55
55
|
)
|
|
56
|
-
self.
|
|
56
|
+
self._default_workflows = default_workflows
|
|
57
57
|
self._default_model = default_model
|
|
58
58
|
self._default_model_settings = default_model_settings
|
|
59
59
|
self._default_model_provider = default_model_provider
|
|
@@ -191,9 +191,9 @@ class LLMConfig:
|
|
|
191
191
|
)
|
|
192
192
|
|
|
193
193
|
@property
|
|
194
|
-
def
|
|
194
|
+
def default_workflows(self) -> list[str]:
|
|
195
195
|
return self._get_property(
|
|
196
|
-
self.
|
|
196
|
+
self._default_workflows, CFG.LLM_WORKFLOWS, lambda: ["coding"]
|
|
197
197
|
)
|
|
198
198
|
|
|
199
199
|
@property
|
|
@@ -279,18 +279,18 @@ class LLMConfig:
|
|
|
279
279
|
def set_default_special_instruction_prompt(self, special_instruction_prompt: str):
|
|
280
280
|
self._default_special_instruction_prompt = special_instruction_prompt
|
|
281
281
|
|
|
282
|
-
def
|
|
283
|
-
self.
|
|
282
|
+
def set_default_workflows(self, workflows: list[str]):
|
|
283
|
+
self._default_workflows = workflows
|
|
284
284
|
|
|
285
|
-
def
|
|
286
|
-
if self.
|
|
287
|
-
self.
|
|
288
|
-
self.
|
|
285
|
+
def add_default_workflow(self, workflow: str):
|
|
286
|
+
if self._default_workflows is None:
|
|
287
|
+
self._default_workflows = []
|
|
288
|
+
self._default_workflows.append(workflow)
|
|
289
289
|
|
|
290
|
-
def
|
|
291
|
-
if self.
|
|
292
|
-
self.
|
|
293
|
-
self.
|
|
290
|
+
def remove_default_workflow(self, workflow: str):
|
|
291
|
+
if self._default_workflows is None:
|
|
292
|
+
self._default_workflows = []
|
|
293
|
+
self._default_workflows.remove(workflow)
|
|
294
294
|
|
|
295
295
|
def set_default_summarization_prompt(self, summarization_prompt: str):
|
|
296
296
|
self._default_summarization_prompt = summarization_prompt
|
zrb/config/llm_context/config.py
CHANGED
|
@@ -5,6 +5,25 @@ from zrb.config.llm_context.config_parser import markdown_to_dict
|
|
|
5
5
|
from zrb.util.llm.prompt import demote_markdown_headers
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
class LLMWorkflow:
|
|
9
|
+
def __init__(self, name: str, path: str, content: str):
|
|
10
|
+
self._name = name
|
|
11
|
+
self._path = path
|
|
12
|
+
self._content = content
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def name(self) -> str:
|
|
16
|
+
return self._name
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def path(self) -> str:
|
|
20
|
+
return self._path
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def content(self) -> str:
|
|
24
|
+
return self._content
|
|
25
|
+
|
|
26
|
+
|
|
8
27
|
class LLMContextConfig:
|
|
9
28
|
"""High-level API for interacting with cascaded configurations."""
|
|
10
29
|
|
|
@@ -75,20 +94,24 @@ class LLMContextConfig:
|
|
|
75
94
|
notes[abs_context_path] = value
|
|
76
95
|
return notes
|
|
77
96
|
|
|
78
|
-
def get_workflows(self, cwd: str | None = None) -> dict[str,
|
|
97
|
+
def get_workflows(self, cwd: str | None = None) -> dict[str, LLMWorkflow]:
|
|
79
98
|
"""Gathers all relevant workflows for a given path."""
|
|
80
99
|
if cwd is None:
|
|
81
100
|
cwd = os.getcwd()
|
|
82
101
|
all_sections = self._get_all_sections(cwd)
|
|
83
|
-
workflows: dict[str,
|
|
102
|
+
workflows: dict[str, LLMWorkflow] = {}
|
|
84
103
|
# Iterate from closest to farthest
|
|
85
|
-
for
|
|
104
|
+
for config_dir, sections in all_sections:
|
|
86
105
|
for key, value in sections.items():
|
|
87
106
|
if key.lower().startswith("workflow:"):
|
|
88
107
|
workflow_name = key[len("workflow:") :].strip().lower()
|
|
89
108
|
# First one found wins
|
|
90
109
|
if workflow_name not in workflows:
|
|
91
|
-
workflows[workflow_name] =
|
|
110
|
+
workflows[workflow_name] = LLMWorkflow(
|
|
111
|
+
name=workflow_name,
|
|
112
|
+
content=value,
|
|
113
|
+
path=config_dir,
|
|
114
|
+
)
|
|
92
115
|
return workflows
|
|
93
116
|
|
|
94
117
|
def get_contexts(self, cwd: str | None = None) -> dict[str, str]:
|
zrb/task/llm/agent.py
CHANGED
|
@@ -106,7 +106,7 @@ def create_agent_instance(
|
|
|
106
106
|
return Agent[None, Any](
|
|
107
107
|
model=model,
|
|
108
108
|
output_type=output_type,
|
|
109
|
-
|
|
109
|
+
instructions=system_prompt,
|
|
110
110
|
tools=tool_list,
|
|
111
111
|
toolsets=wrapped_toolsets,
|
|
112
112
|
model_settings=model_settings,
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Git Command Guidelines
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
|
|
5
|
+
- **Safety First:** Always verify current branch and status before destructive operations
|
|
6
|
+
- **Atomic Commits:** Each commit should represent a single logical change
|
|
7
|
+
- **Descriptive Messages:** Write clear, concise commit messages that explain "why" not just "what"
|
|
8
|
+
- **Interactive Mode:** Use interactive rebase and staging for precise control
|
|
9
|
+
|
|
10
|
+
## Essential Commands
|
|
11
|
+
|
|
12
|
+
### Repository Status
|
|
13
|
+
```bash
|
|
14
|
+
# Check current status and branch
|
|
15
|
+
git status
|
|
16
|
+
git branch -v
|
|
17
|
+
|
|
18
|
+
# See uncommitted changes
|
|
19
|
+
git diff
|
|
20
|
+
git diff --staged
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Safe Branch Operations
|
|
24
|
+
```bash
|
|
25
|
+
# Create and switch to new branch
|
|
26
|
+
git checkout -b feature/new-feature
|
|
27
|
+
|
|
28
|
+
# Switch branches safely
|
|
29
|
+
git switch main
|
|
30
|
+
git switch feature/branch-name
|
|
31
|
+
|
|
32
|
+
# List all branches
|
|
33
|
+
git branch -a
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Staging and Committing
|
|
37
|
+
```bash
|
|
38
|
+
# Stage specific files
|
|
39
|
+
git add path/to/file.py
|
|
40
|
+
git add src/
|
|
41
|
+
|
|
42
|
+
# Stage interactively
|
|
43
|
+
git add -p
|
|
44
|
+
|
|
45
|
+
# Commit with descriptive message
|
|
46
|
+
git commit -m "feat: add user authentication
|
|
47
|
+
|
|
48
|
+
- Implement JWT token generation
|
|
49
|
+
- Add login/logout endpoints
|
|
50
|
+
- Add password hashing"
|
|
51
|
+
|
|
52
|
+
# Amend last commit (use carefully)
|
|
53
|
+
git commit --amend
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### History and Logs
|
|
57
|
+
```bash
|
|
58
|
+
# View commit history
|
|
59
|
+
git log --oneline --graph -10
|
|
60
|
+
git log --stat
|
|
61
|
+
|
|
62
|
+
# See who changed what
|
|
63
|
+
git blame file.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Advanced Operations
|
|
67
|
+
|
|
68
|
+
### Rebasing and Merging
|
|
69
|
+
```bash
|
|
70
|
+
# Update feature branch from main
|
|
71
|
+
git switch feature/branch
|
|
72
|
+
git rebase main
|
|
73
|
+
|
|
74
|
+
# Interactive rebase for cleanup
|
|
75
|
+
git rebase -i HEAD~5
|
|
76
|
+
|
|
77
|
+
# Safe merge
|
|
78
|
+
git merge --no-ff feature/branch
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Stashing
|
|
82
|
+
```bash
|
|
83
|
+
# Save uncommitted changes temporarily
|
|
84
|
+
git stash push -m "WIP: feature implementation"
|
|
85
|
+
|
|
86
|
+
# List stashes
|
|
87
|
+
git stash list
|
|
88
|
+
|
|
89
|
+
# Apply and keep stash
|
|
90
|
+
git stash apply stash@{0}
|
|
91
|
+
|
|
92
|
+
# Apply and drop stash
|
|
93
|
+
git stash pop
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Remote Operations
|
|
97
|
+
```bash
|
|
98
|
+
# Fetch and check before pulling
|
|
99
|
+
git fetch origin
|
|
100
|
+
git log origin/main..main
|
|
101
|
+
|
|
102
|
+
# Push safely
|
|
103
|
+
git push origin feature/branch
|
|
104
|
+
git push --force-with-lease # Safer than --force
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Safety Checklist
|
|
108
|
+
|
|
109
|
+
1. **Before destructive operations:** Always run `git status` and `git branch -v`
|
|
110
|
+
2. **Before force push:** Use `--force-with-lease` instead of `--force`
|
|
111
|
+
3. **Before rebase:** Ensure working directory is clean
|
|
112
|
+
4. **Before merge:** Resolve conflicts immediately
|
|
113
|
+
5. **Regularly:** Fetch and integrate upstream changes
|
|
114
|
+
|
|
115
|
+
## Common Patterns
|
|
116
|
+
|
|
117
|
+
### Feature Development
|
|
118
|
+
```bash
|
|
119
|
+
git checkout -b feature/new-feature
|
|
120
|
+
# ... make changes ...
|
|
121
|
+
git add .
|
|
122
|
+
git commit -m "feat: implement new feature"
|
|
123
|
+
git push origin feature/new-feature
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Hotfix Workflow
|
|
127
|
+
```bash
|
|
128
|
+
git checkout -b hotfix/critical-bug main
|
|
129
|
+
# ... fix the bug ...
|
|
130
|
+
git add .
|
|
131
|
+
git commit -m "fix: resolve critical issue"
|
|
132
|
+
git push origin hotfix/critical-bug
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Cleanup
|
|
136
|
+
```bash
|
|
137
|
+
# Delete merged branches locally
|
|
138
|
+
git branch --merged main | grep -v "main" | xargs git branch -d
|
|
139
|
+
|
|
140
|
+
# Delete remote branches
|
|
141
|
+
git push origin --delete old-branch
|
|
142
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Go Development Guide
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
- **Follow Go conventions** and effective Go patterns
|
|
5
|
+
- **Use `go fmt`** for consistent formatting
|
|
6
|
+
- **Follow project's package structure** and naming
|
|
7
|
+
|
|
8
|
+
## Project Analysis
|
|
9
|
+
- Check for: `go.mod`, `go.sum`, `Makefile`
|
|
10
|
+
- Look for project-specific patterns in existing code
|
|
11
|
+
- Identify testing approach: table tests, integration tests
|
|
12
|
+
|
|
13
|
+
## Implementation Patterns
|
|
14
|
+
- **Error Handling:** Follow project's error wrapping and handling style
|
|
15
|
+
- **Package Organization:** Match existing package boundaries and dependencies
|
|
16
|
+
- **Naming:** Follow Go conventions (camelCase, short names)
|
|
17
|
+
- **Testing:** Use same test organization and helper patterns
|
|
18
|
+
|
|
19
|
+
## Common Commands
|
|
20
|
+
- Formatting: `go fmt`
|
|
21
|
+
- Testing: `go test`
|
|
22
|
+
- Linting: `golangci-lint`, `staticcheck`
|
|
23
|
+
- Building: `go build`
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# JavaScript/TypeScript Development Guide
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
- **Follow project's style guide** (ESLint, Prettier, etc.)
|
|
5
|
+
- **Use TypeScript** if the project uses it
|
|
6
|
+
- **Match module system** (CommonJS, ES modules)
|
|
7
|
+
|
|
8
|
+
## Project Analysis
|
|
9
|
+
- Check for: `package.json`, `tsconfig.json`, `jsconfig.json`
|
|
10
|
+
- Look for style guides: `.eslintrc`, `.prettierrc`, `.editorconfig`
|
|
11
|
+
- Identify testing framework: `jest`, `mocha`, `vitest`
|
|
12
|
+
- Check build tools: `webpack`, `vite`, `rollup`
|
|
13
|
+
|
|
14
|
+
## Implementation Patterns
|
|
15
|
+
- **Module System:** Follow project's import/export patterns
|
|
16
|
+
- **Error Handling:** Match promise/async patterns and error types
|
|
17
|
+
- **TypeScript:** Use same strictness level and type patterns
|
|
18
|
+
- **Testing:** Use project's test utilities and mocking patterns
|
|
19
|
+
|
|
20
|
+
## Common Commands
|
|
21
|
+
- Package management: `npm`, `yarn`, `pnpm`
|
|
22
|
+
- Testing: `npm test`, `npm run test`
|
|
23
|
+
- Linting: `npm run lint`, `eslint`
|
|
24
|
+
- Building: `npm run build`, `tsc`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Python Development Guide
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
- **Follow PEP 8** unless project has specific style guides
|
|
5
|
+
- **Use type hints** if the project uses them
|
|
6
|
+
- **Match existing patterns** for imports, docstrings, and error handling
|
|
7
|
+
|
|
8
|
+
## Project Analysis
|
|
9
|
+
- Check for: `pyproject.toml`, `requirements.txt`, `setup.py`, `.python-version`
|
|
10
|
+
- Look for style guides: `.flake8`, `.pylintrc`, `ruff.toml`, `mypy.ini`
|
|
11
|
+
- Identify testing framework: `pytest`, `unittest`, `nose`
|
|
12
|
+
|
|
13
|
+
## Implementation Patterns
|
|
14
|
+
- **Imports:** Follow project's import organization (stdlib, third-party, local)
|
|
15
|
+
- **Error Handling:** Match existing exception patterns and logging
|
|
16
|
+
- **Documentation:** Use same docstring format (Google, NumPy, reStructuredText)
|
|
17
|
+
- **Testing:** Use project's test organization and fixtures
|
|
18
|
+
|
|
19
|
+
## Common Commands
|
|
20
|
+
- Formatting: `black`, `autopep8`, `yapf`
|
|
21
|
+
- Linting: `flake8`, `pylint`, `ruff`
|
|
22
|
+
- Testing: `pytest`, `python -m unittest`
|
|
23
|
+
- Type checking: `mypy`, `pyright`
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Rust Development Guide
|
|
2
|
+
|
|
3
|
+
## Core Principles
|
|
4
|
+
- **Follow Rust conventions** and idiomatic patterns
|
|
5
|
+
- **Use `rustfmt`** for consistent formatting
|
|
6
|
+
- **Follow ownership and borrowing** patterns in existing code
|
|
7
|
+
|
|
8
|
+
## Project Analysis
|
|
9
|
+
- Check for: `Cargo.toml`, `Cargo.lock`
|
|
10
|
+
- Look for: `rustfmt.toml`, `clippy.toml`
|
|
11
|
+
- Identify testing approach: unit tests, integration tests
|
|
12
|
+
|
|
13
|
+
## Implementation Patterns
|
|
14
|
+
- **Error Handling:** Follow project's `Result` and `Option` patterns
|
|
15
|
+
- **Crate Organization:** Match existing module structure
|
|
16
|
+
- **Ownership:** Follow existing borrowing and lifetime patterns
|
|
17
|
+
- **Testing:** Use same test organization and attribute patterns
|
|
18
|
+
|
|
19
|
+
## Common Commands
|
|
20
|
+
- Formatting: `cargo fmt`
|
|
21
|
+
- Testing: `cargo test`
|
|
22
|
+
- Linting: `cargo clippy`
|
|
23
|
+
- Building: `cargo build`
|