zrb 1.11.0__py3-none-any.whl → 1.13.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 +38 -9
- zrb/builtin/llm/llm_ask.py +11 -0
- zrb/builtin/llm/tool/sub_agent.py +5 -5
- zrb/config/config.py +4 -0
- zrb/config/default_prompt/interactive_system_prompt.md +8 -4
- zrb/config/default_prompt/summarization_prompt.md +16 -42
- zrb/config/default_prompt/system_prompt.md +8 -4
- zrb/config/llm_config.py +23 -30
- zrb/config/llm_context/config.py +100 -45
- zrb/config/llm_context/config_parser.py +46 -0
- zrb/context/shared_context.py +4 -1
- zrb/task/llm/agent.py +28 -13
- zrb/task/llm/conversation_history_model.py +18 -68
- zrb/{config/default_workflow/code.md → task/llm/default_workflow/coding.md} +0 -2
- zrb/{config/default_workflow/content.md → task/llm/default_workflow/copywriting.md} +0 -2
- zrb/{config/default_workflow/research.md → task/llm/default_workflow/researching.md} +0 -2
- zrb/task/llm/history_summarization.py +2 -4
- zrb/task/llm/print_node.py +4 -1
- zrb/task/llm/prompt.py +78 -27
- zrb/task/llm/tool_wrapper.py +30 -18
- zrb/task/llm_task.py +31 -35
- zrb/util/callable.py +23 -0
- zrb/util/llm/prompt.py +19 -10
- {zrb-1.11.0.dist-info → zrb-1.13.0.dist-info}/METADATA +3 -3
- {zrb-1.11.0.dist-info → zrb-1.13.0.dist-info}/RECORD +27 -26
- zrb/config/llm_context/config_handler.py +0 -238
- {zrb-1.11.0.dist-info → zrb-1.13.0.dist-info}/WHEEL +0 -0
- {zrb-1.11.0.dist-info → zrb-1.13.0.dist-info}/entry_points.txt +0 -0
zrb/task/llm_task.py
CHANGED
@@ -2,7 +2,7 @@ import json
|
|
2
2
|
from collections.abc import Callable
|
3
3
|
from typing import TYPE_CHECKING, Any
|
4
4
|
|
5
|
-
from zrb.attr.type import BoolAttr, IntAttr, StrAttr, fstring
|
5
|
+
from zrb.attr.type import BoolAttr, IntAttr, StrAttr, StrListAttr, fstring
|
6
6
|
from zrb.config.llm_rate_limitter import LLMRateLimiter
|
7
7
|
from zrb.context.any_context import AnyContext
|
8
8
|
from zrb.context.any_shared_context import AnySharedContext
|
@@ -16,14 +16,12 @@ from zrb.task.llm.config import (
|
|
16
16
|
get_model_settings,
|
17
17
|
)
|
18
18
|
from zrb.task.llm.conversation_history import (
|
19
|
-
ListOfDict,
|
20
19
|
read_conversation_history,
|
21
20
|
write_conversation_history,
|
22
21
|
)
|
23
22
|
from zrb.task.llm.conversation_history_model import ConversationHistory
|
24
23
|
from zrb.task.llm.history_summarization import maybe_summarize_history
|
25
24
|
from zrb.task.llm.prompt import (
|
26
|
-
get_context_enrichment_prompt,
|
27
25
|
get_summarization_system_prompt,
|
28
26
|
get_system_and_user_prompt,
|
29
27
|
get_user_message,
|
@@ -33,9 +31,9 @@ from zrb.xcom.xcom import Xcom
|
|
33
31
|
|
34
32
|
if TYPE_CHECKING:
|
35
33
|
from pydantic_ai import Agent, Tool
|
36
|
-
from pydantic_ai.mcp import MCPServer
|
37
34
|
from pydantic_ai.models import Model
|
38
35
|
from pydantic_ai.settings import ModelSettings
|
36
|
+
from pydantic_ai.toolsets import AbstractToolset
|
39
37
|
|
40
38
|
ToolOrCallable = Tool | Callable
|
41
39
|
else:
|
@@ -65,22 +63,21 @@ class LLMTask(BaseTask):
|
|
65
63
|
) = None,
|
66
64
|
agent: "Agent | Callable[[AnySharedContext], Agent] | None" = None,
|
67
65
|
persona: StrAttr | None = None,
|
66
|
+
render_persona: bool = False,
|
68
67
|
system_prompt: StrAttr | None = None,
|
68
|
+
render_system_prompt: bool = False,
|
69
69
|
special_instruction_prompt: StrAttr | None = None,
|
70
|
+
render_special_instruction_prompt: bool = False,
|
71
|
+
modes: StrListAttr | None = None,
|
72
|
+
render_modes: bool = True,
|
70
73
|
message: StrAttr | None = None,
|
71
74
|
render_message: bool = True,
|
72
|
-
enrich_context: BoolAttr | None = None,
|
73
|
-
render_enrich_context: bool = True,
|
74
|
-
context_enrichment_prompt: StrAttr | None = None,
|
75
|
-
render_context_enrichment_prompt: bool = True,
|
76
|
-
context_enrichment_token_threshold: IntAttr | None = None,
|
77
|
-
render_context_enrichment_token_threshold: bool = True,
|
78
75
|
tools: (
|
79
76
|
list["ToolOrCallable"]
|
80
77
|
| Callable[[AnySharedContext], list["ToolOrCallable"]]
|
81
78
|
) = [],
|
82
|
-
|
83
|
-
list["
|
79
|
+
toolsets: (
|
80
|
+
list["AbstractToolset[Agent]"] | Callable[[AnySharedContext], list["Tool"]]
|
84
81
|
) = [],
|
85
82
|
conversation_history: (
|
86
83
|
ConversationHistory
|
@@ -100,6 +97,7 @@ class LLMTask(BaseTask):
|
|
100
97
|
summarize_history: BoolAttr | None = None,
|
101
98
|
render_summarize_history: bool = True,
|
102
99
|
summarization_prompt: StrAttr | None = None,
|
100
|
+
render_summarization_prompt: bool = False,
|
103
101
|
history_summarization_token_threshold: IntAttr | None = None,
|
104
102
|
render_history_summarization_token_threshold: bool = True,
|
105
103
|
rate_limitter: LLMRateLimiter | None = None,
|
@@ -150,24 +148,22 @@ class LLMTask(BaseTask):
|
|
150
148
|
self._model_settings = model_settings
|
151
149
|
self._agent = agent
|
152
150
|
self._persona = persona
|
151
|
+
self._render_persona = render_persona
|
153
152
|
self._system_prompt = system_prompt
|
153
|
+
self._render_system_prompt = render_system_prompt
|
154
154
|
self._special_instruction_prompt = special_instruction_prompt
|
155
|
+
self._render_special_instruction_prompt = render_special_instruction_prompt
|
156
|
+
self._modes = modes
|
157
|
+
self._render_modes = render_modes
|
155
158
|
self._message = message
|
156
159
|
self._render_message = render_message
|
157
160
|
self._summarization_prompt = summarization_prompt
|
158
|
-
self.
|
159
|
-
self._render_enrich_context = render_enrich_context
|
160
|
-
self._context_enrichment_prompt = context_enrichment_prompt
|
161
|
-
self._render_context_enrichment_prompt = render_context_enrichment_prompt
|
162
|
-
self._context_enrichment_token_threshold = context_enrichment_token_threshold
|
163
|
-
self._render_context_enrichment_token_threshold = (
|
164
|
-
render_context_enrichment_token_threshold
|
165
|
-
)
|
161
|
+
self._render_summarization_prompt = render_summarization_prompt
|
166
162
|
self._tools = tools
|
167
163
|
self._rate_limitter = rate_limitter
|
168
164
|
self._additional_tools: list["ToolOrCallable"] = []
|
169
|
-
self.
|
170
|
-
self.
|
165
|
+
self._toolsets = toolsets
|
166
|
+
self._additional_toolsets: list["AbstractToolset[Agent]"] = []
|
171
167
|
self._conversation_history = conversation_history
|
172
168
|
self._conversation_history_reader = conversation_history_reader
|
173
169
|
self._conversation_history_writer = conversation_history_writer
|
@@ -191,18 +187,12 @@ class LLMTask(BaseTask):
|
|
191
187
|
for single_tool in tool:
|
192
188
|
self._additional_tools.append(single_tool)
|
193
189
|
|
194
|
-
def
|
195
|
-
self.
|
196
|
-
|
197
|
-
def append_mcp_server(self, *mcp_server: "MCPServer"):
|
198
|
-
for single_mcp_server in mcp_server:
|
199
|
-
self._additional_mcp_servers.append(single_mcp_server)
|
200
|
-
|
201
|
-
def set_should_enrich_context(self, enrich_context: bool):
|
202
|
-
self._should_enrich_context = enrich_context
|
190
|
+
def add_toolset(self, *toolset: "AbstractToolset[Agent]"):
|
191
|
+
self.append_toolset(*toolset)
|
203
192
|
|
204
|
-
def
|
205
|
-
|
193
|
+
def append_toolset(self, *toolset: "AbstractToolset[Agent]"):
|
194
|
+
for single_toolset in toolset:
|
195
|
+
self._additional_toolsets.append(single_toolset)
|
206
196
|
|
207
197
|
def set_should_summarize_history(self, summarize_history: bool):
|
208
198
|
self._should_summarize_history = summarize_history
|
@@ -227,6 +217,7 @@ class LLMTask(BaseTask):
|
|
227
217
|
summarization_prompt = get_summarization_system_prompt(
|
228
218
|
ctx=ctx,
|
229
219
|
summarization_prompt_attr=self._summarization_prompt,
|
220
|
+
render_summarization_prompt=self._render_summarization_prompt,
|
230
221
|
)
|
231
222
|
user_message = get_user_message(ctx, self._message, self._render_message)
|
232
223
|
# 1. Prepare initial state (read history from previous session)
|
@@ -243,8 +234,13 @@ class LLMTask(BaseTask):
|
|
243
234
|
ctx=ctx,
|
244
235
|
user_message=user_message,
|
245
236
|
persona_attr=self._persona,
|
237
|
+
render_persona=self._render_persona,
|
246
238
|
system_prompt_attr=self._system_prompt,
|
239
|
+
render_system_prompt=self._render_system_prompt,
|
247
240
|
special_instruction_prompt_attr=self._special_instruction_prompt,
|
241
|
+
render_special_instruction_prompt=self._render_special_instruction_prompt,
|
242
|
+
modes_attr=self._modes,
|
243
|
+
render_modes=self._render_modes,
|
248
244
|
conversation_history=conversation_history,
|
249
245
|
)
|
250
246
|
# 3. Get the agent instance
|
@@ -256,8 +252,8 @@ class LLMTask(BaseTask):
|
|
256
252
|
model_settings=model_settings,
|
257
253
|
tools_attr=self._tools,
|
258
254
|
additional_tools=self._additional_tools,
|
259
|
-
|
260
|
-
|
255
|
+
toolsets_attr=self._toolsets,
|
256
|
+
additional_toolsets=self._additional_toolsets,
|
261
257
|
)
|
262
258
|
# 4. Run the agent iteration and save the results/history
|
263
259
|
result = await self._execute_agent(
|
zrb/util/callable.py
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
from types import BuiltinMethodType, MethodType
|
2
|
+
|
3
|
+
|
4
|
+
def get_callable_name(obj):
|
5
|
+
import functools
|
6
|
+
import inspect
|
7
|
+
|
8
|
+
# 1. Unwrap decorated functions
|
9
|
+
obj = inspect.unwrap(obj, stop=lambda f: not hasattr(f, "__wrapped__"))
|
10
|
+
# 2. functools.partial – delegate to the wrapped function
|
11
|
+
if isinstance(obj, functools.partial):
|
12
|
+
return get_callable_name(obj.func)
|
13
|
+
# 3. Plain functions, built‑ins, methods
|
14
|
+
if hasattr(obj, "__name__"):
|
15
|
+
return obj.__name__
|
16
|
+
# 4. Bound or unbound methods of a class
|
17
|
+
if isinstance(obj, (MethodType, BuiltinMethodType)):
|
18
|
+
return obj.__func__.__name__
|
19
|
+
# 5. Instances of classes defining __call__
|
20
|
+
if callable(obj):
|
21
|
+
return type(obj).__name__
|
22
|
+
# 6. Fallback
|
23
|
+
return repr(obj)
|
zrb/util/llm/prompt.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import re
|
2
2
|
|
3
3
|
|
4
|
-
def
|
4
|
+
def _adjust_markdown_headers(md: str, level_change: int) -> str:
|
5
5
|
lines = md.split("\n")
|
6
6
|
new_lines = []
|
7
7
|
fence_stack = []
|
@@ -11,7 +11,6 @@ def _demote_markdown_headers(md: str) -> str:
|
|
11
11
|
|
12
12
|
if fence_match:
|
13
13
|
current_fence = fence_match.group(1)
|
14
|
-
# If stack is not empty and we found a closing fence
|
15
14
|
if (
|
16
15
|
fence_stack
|
17
16
|
and fence_stack[-1][0] == current_fence[0]
|
@@ -21,18 +20,28 @@ def _demote_markdown_headers(md: str) -> str:
|
|
21
20
|
else:
|
22
21
|
fence_stack.append(current_fence)
|
23
22
|
new_lines.append(line)
|
23
|
+
elif fence_stack:
|
24
|
+
new_lines.append(line)
|
24
25
|
else:
|
25
|
-
|
26
|
-
|
26
|
+
match = re.match(r"^(#{1,6})(\s)", line)
|
27
|
+
if match:
|
28
|
+
current_level = len(match.group(1))
|
29
|
+
new_level = max(1, current_level + level_change)
|
30
|
+
new_header = "#" * new_level + line[current_level:]
|
31
|
+
new_lines.append(new_header)
|
27
32
|
else:
|
28
|
-
|
29
|
-
if match:
|
30
|
-
new_lines.append("#" + line)
|
31
|
-
else:
|
32
|
-
new_lines.append(line)
|
33
|
+
new_lines.append(line)
|
33
34
|
return "\n".join(new_lines)
|
34
35
|
|
35
36
|
|
37
|
+
def demote_markdown_headers(md: str) -> str:
|
38
|
+
return _adjust_markdown_headers(md, level_change=1)
|
39
|
+
|
40
|
+
|
41
|
+
def promote_markdown_headers(md: str) -> str:
|
42
|
+
return _adjust_markdown_headers(md, level_change=-1)
|
43
|
+
|
44
|
+
|
36
45
|
def make_prompt_section(header: str, content: str, as_code: bool = False) -> str:
|
37
46
|
if content.strip() == "":
|
38
47
|
return ""
|
@@ -51,4 +60,4 @@ def make_prompt_section(header: str, content: str, as_code: bool = False) -> str
|
|
51
60
|
fence_len = longest_backtick_sequence + 1
|
52
61
|
fence = "`" * fence_len
|
53
62
|
return f"# {header}\n{fence}\n{content.strip()}\n{fence}\n"
|
54
|
-
return f"# {header}\n{
|
63
|
+
return f"# {header}\n{demote_markdown_headers(content.strip())}\n"
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: zrb
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.13.0
|
4
4
|
Summary: Your Automation Powerhouse
|
5
5
|
Home-page: https://github.com/state-alchemists/zrb
|
6
6
|
License: AGPL-3.0-or-later
|
@@ -19,7 +19,7 @@ Provides-Extra: rag
|
|
19
19
|
Requires-Dist: beautifulsoup4 (>=4.13.3,<5.0.0)
|
20
20
|
Requires-Dist: black (>=25.1.0,<25.2.0)
|
21
21
|
Requires-Dist: chromadb (>=0.6.3,<0.7.0) ; extra == "rag" or extra == "all"
|
22
|
-
Requires-Dist: fastapi[standard] (>=0.
|
22
|
+
Requires-Dist: fastapi[standard] (>=0.116.1,<0.117.0)
|
23
23
|
Requires-Dist: isort (>=6.0.1,<6.1.0)
|
24
24
|
Requires-Dist: libcst (>=1.7.0,<2.0.0)
|
25
25
|
Requires-Dist: openai (>=1.86.0,<2.0.0) ; extra == "rag" or extra == "all"
|
@@ -27,7 +27,7 @@ Requires-Dist: pdfplumber (>=0.11.6,<0.12.0) ; extra == "rag" or extra == "all"
|
|
27
27
|
Requires-Dist: playwright (>=1.53.0,<2.0.0) ; extra == "playwright" or extra == "all"
|
28
28
|
Requires-Dist: prompt-toolkit (>=3.0.51,<4.0.0)
|
29
29
|
Requires-Dist: psutil (>=7.0.0,<8.0.0)
|
30
|
-
Requires-Dist: pydantic-ai (>=0.4.
|
30
|
+
Requires-Dist: pydantic-ai (>=0.4.5,<0.5.0)
|
31
31
|
Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
|
32
32
|
Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
|
33
33
|
Requires-Dist: python-jose[cryptography] (>=3.4.0,<4.0.0)
|
@@ -9,10 +9,10 @@ zrb/builtin/git_subtree.py,sha256=7BKwOkVTWDrR0DXXQ4iJyHqeR6sV5VYRt8y_rEB0EHg,35
|
|
9
9
|
zrb/builtin/group.py,sha256=t008xLM4_fgbjfZrPoi_fQAnSHIo6MOiQSCHBO4GDYU,2379
|
10
10
|
zrb/builtin/http.py,sha256=sLqEczuSxGYXWzyJR6frGOHkPTviu4BeyroUr3-ZuAI,4322
|
11
11
|
zrb/builtin/jwt.py,sha256=3M5uaQhJZbKQLjTUft1OwPz_JxtmK-xtkjxWjciOQho,2859
|
12
|
-
zrb/builtin/llm/chat_session.py,sha256=
|
12
|
+
zrb/builtin/llm/chat_session.py,sha256=u8bW67uKCq22hVv4ZkOsKIZxBeOdKtJh4Bjyy552RM4,9424
|
13
13
|
zrb/builtin/llm/history.py,sha256=LDOrL0p7r_AHLa5L8Dp7bHNsOALugmJd7OguXRWGnm4,3087
|
14
14
|
zrb/builtin/llm/input.py,sha256=Nw-26uTWp2QhUgKJcP_IMHmtk-b542CCSQ_vCOjhvhM,877
|
15
|
-
zrb/builtin/llm/llm_ask.py,sha256=
|
15
|
+
zrb/builtin/llm/llm_ask.py,sha256=18XAxyPWF7daE0TZkRkRt8opmqLUjhpM3oMVdOP-qWY,4857
|
16
16
|
zrb/builtin/llm/previous-session.js,sha256=xMKZvJoAbrwiyHS0OoPrWuaKxWYLoyR5sguePIoCjTY,816
|
17
17
|
zrb/builtin/llm/tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
18
|
zrb/builtin/llm/tool/api.py,sha256=OhmfLc2TwWKQYIMweGelqb5s4JF4nB-YynbSO4yb_Jk,2342
|
@@ -20,7 +20,7 @@ zrb/builtin/llm/tool/cli.py,sha256=dUWZrW2X5J_lONuzR__6-SbewSdi28E3RRuksjd4mWo,1
|
|
20
20
|
zrb/builtin/llm/tool/code.py,sha256=GRP_IZAkeL6RIlUm407BQRF992ES57pdzPaQdC5UsJU,8218
|
21
21
|
zrb/builtin/llm/tool/file.py,sha256=XfTuoQOHmgiAYkfi_1ew2voxOwad5vWTe_3Ww8IeVQY,22274
|
22
22
|
zrb/builtin/llm/tool/rag.py,sha256=wB74JV7bxs0ec77b_09Z2lPjoR1WzPUvZbuXOdb9Q9g,9675
|
23
|
-
zrb/builtin/llm/tool/sub_agent.py,sha256=
|
23
|
+
zrb/builtin/llm/tool/sub_agent.py,sha256=9Su64FpNTVeE6O2qgNzo-eo4pcmv8qi_sd_QWLQBXYw,4870
|
24
24
|
zrb/builtin/llm/tool/web.py,sha256=gQlUsmYCJOFJtNjwpjK-xk13LMvrMSpSaFHXUTnIayQ,7090
|
25
25
|
zrb/builtin/md5.py,sha256=690RV2LbW7wQeTFxY-lmmqTSVEEZv3XZbjEUW1Q3XpE,1480
|
26
26
|
zrb/builtin/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -217,20 +217,17 @@ zrb/callback/callback.py,sha256=PFhCqzfxdk6IAthmXcZ13DokT62xtBzJr_ciLw6I8Zg,4030
|
|
217
217
|
zrb/cmd/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
218
218
|
zrb/cmd/cmd_result.py,sha256=L8bQJzWCpcYexIxHBNsXj2pT3BtLmWex0iJSMkvimOA,597
|
219
219
|
zrb/cmd/cmd_val.py,sha256=7Doowyg6BK3ISSGBLt-PmlhzaEkBjWWm51cED6fAUOQ,1014
|
220
|
-
zrb/config/config.py,sha256=
|
220
|
+
zrb/config/config.py,sha256=d_F-hdPLADjeVRHtnpOxtOkfUBu5huSLclyD53uxO4U,12306
|
221
221
|
zrb/config/default_prompt/file_extractor_system_prompt.md,sha256=tmeZMPzF9MGExsZZw7M2PZN6V0oFVRp1nIjiqUPvQ9M,1013
|
222
|
-
zrb/config/default_prompt/interactive_system_prompt.md,sha256=
|
222
|
+
zrb/config/default_prompt/interactive_system_prompt.md,sha256=ZFPeDEV2vlcksHiVG2o-TCehmqkFolDjtH0_Fzo1gGI,3566
|
223
223
|
zrb/config/default_prompt/persona.md,sha256=WU4JKp-p7qJePDA6NZ_CYdBggo2B3PEq8IEnNVblIHU,41
|
224
224
|
zrb/config/default_prompt/repo_extractor_system_prompt.md,sha256=EGZ-zj78RlMEg2jduRBs8WzO4VJTkXHR96IpBepZMsY,3881
|
225
225
|
zrb/config/default_prompt/repo_summarizer_system_prompt.md,sha256=fpG5B416OK3oE41bWPrh1M6pdH5SSadCPte_NJ_79z0,858
|
226
|
-
zrb/config/default_prompt/summarization_prompt.md,sha256=
|
227
|
-
zrb/config/default_prompt/system_prompt.md,sha256=
|
228
|
-
zrb/config/
|
229
|
-
zrb/config/
|
230
|
-
zrb/config/
|
231
|
-
zrb/config/llm_config.py,sha256=ET2ehVdQQv-dOTXIVx81sdvybF9rprL6VUhAxE6K-Ho,9215
|
232
|
-
zrb/config/llm_context/config.py,sha256=swc3hUaEIoL2MjKtbati13iP0MxveNG_y_6K3nszRAw,2571
|
233
|
-
zrb/config/llm_context/config_handler.py,sha256=oQesfigIM0qMw_A3jUCN0UDJujRjuJ3jr5mXHBiLgB0,8866
|
226
|
+
zrb/config/default_prompt/summarization_prompt.md,sha256=hRXH5E78TugSze_Hgp-KTbIhCeyrMcJg-pSXvXH3C9E,1629
|
227
|
+
zrb/config/default_prompt/system_prompt.md,sha256=Jkne5n9HJcBCgfeENwxvqH-kbDO2CaiUzqR4VoWMRHY,3054
|
228
|
+
zrb/config/llm_config.py,sha256=bNLxorctwtVW1F9hA-hEYpDBe7FLSZHC25Nx8NlR4-M,8597
|
229
|
+
zrb/config/llm_context/config.py,sha256=zeqSVOKK5yyApvqTbcO3ayGxtyoag22qlWWaXp1nINs,4950
|
230
|
+
zrb/config/llm_context/config_parser.py,sha256=h95FbOjvVobhrsfGtG_BY3hxS-OLzQj-9F5vGZuehkY,1473
|
234
231
|
zrb/config/llm_rate_limitter.py,sha256=P4vR7qxwiGwjlKx2kHcfdIxwGbJB98vdN-UQEH-Q2WU,4894
|
235
232
|
zrb/config/web_auth_config.py,sha256=_PXatQTYh2mX9H3HSYSQKp13zm1RlLyVIoeIr6KYMQ8,6279
|
236
233
|
zrb/content_transformer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -240,7 +237,7 @@ zrb/context/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
240
237
|
zrb/context/any_context.py,sha256=2hgVKbbDwmwrEl1h1L1FaTUjuUYaDd_b7YRGkaorW6Q,6362
|
241
238
|
zrb/context/any_shared_context.py,sha256=wJawL1jGgApcKPRcpw3js7W4-MhJRA3GMbR5zTsJmt0,1929
|
242
239
|
zrb/context/context.py,sha256=ErGhXJgjgNaAqi6iPMejWxFZ3YvWnysC6mHEU-wodKk,6884
|
243
|
-
zrb/context/shared_context.py,sha256=
|
240
|
+
zrb/context/shared_context.py,sha256=Jaa7AYCeCksOiEAwOnY3xD6Y2Yy2wJAkpehAkbKQ-Wc,3076
|
244
241
|
zrb/dot_dict/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
245
242
|
zrb/dot_dict/dot_dict.py,sha256=ubw_x8I7AOJ59xxtFVJ00VGmq_IYdZP3mUhNlO4nEK0,556
|
246
243
|
zrb/env/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -349,17 +346,20 @@ zrb/task/base_trigger.py,sha256=WSGcmBcGAZw8EzUXfmCjqJQkz8GEmi1RzogpF6A1V4s,6902
|
|
349
346
|
zrb/task/cmd_task.py,sha256=myM8WZm6NrUD-Wv0Vb5sTOrutrAVZLt5LVsSBKwX6SM,10860
|
350
347
|
zrb/task/http_check.py,sha256=Gf5rOB2Se2EdizuN9rp65HpGmfZkGc-clIAlHmPVehs,2565
|
351
348
|
zrb/task/llm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
352
|
-
zrb/task/llm/agent.py,sha256=
|
349
|
+
zrb/task/llm/agent.py,sha256=aZvtcL5HmZQvD3c79R9sDIOMawO0rUMcRiq2wZ1FNas,7457
|
353
350
|
zrb/task/llm/config.py,sha256=TlyH925_fboIlK2Ixf34tynmenqs9s9rfsnPs4jff78,3490
|
354
351
|
zrb/task/llm/conversation_history.py,sha256=B_PDWYL_q66s0xwWBzMSomqPN6u3gkXlIeXBD5A0Apg,4416
|
355
|
-
zrb/task/llm/conversation_history_model.py,sha256=
|
352
|
+
zrb/task/llm/conversation_history_model.py,sha256=DJ0KDBB0BriQuE5ugC_q0aSHhjNIBcfjUk1f0S_3I9U,9245
|
353
|
+
zrb/task/llm/default_workflow/coding.md,sha256=2uythvPsnBpYfIhiIH1cCinQXX0i0yUqsL474Zpemw0,2484
|
354
|
+
zrb/task/llm/default_workflow/copywriting.md,sha256=xSO7GeDolwGxiuz6kXsK2GKGpwp8UgtG0yRqTmill_s,1999
|
355
|
+
zrb/task/llm/default_workflow/researching.md,sha256=KD-aYHFHir6Ti-4FsBBtGwiI0seSVgleYbKJZi_POXA,2139
|
356
356
|
zrb/task/llm/error.py,sha256=QR-nIohS6pBpC_16cWR-fw7Mevo1sNYAiXMBsh_CJDE,4157
|
357
|
-
zrb/task/llm/history_summarization.py,sha256=
|
358
|
-
zrb/task/llm/print_node.py,sha256=
|
359
|
-
zrb/task/llm/prompt.py,sha256=
|
360
|
-
zrb/task/llm/tool_wrapper.py,sha256=
|
357
|
+
zrb/task/llm/history_summarization.py,sha256=_0RmzIeJdJA3KvtdTdKnd2Ga7_7x8C1J2PM0oSn-IYw,8000
|
358
|
+
zrb/task/llm/print_node.py,sha256=mwdqsO2IVf5rDz-jdH9HXz6MFGCWrZ4Pv2xbUBtoNgc,4179
|
359
|
+
zrb/task/llm/prompt.py,sha256=sMipP-NJmq4ZmCtQYEG2mcHWUD79yJRwH7nH-iw-7Z4,9661
|
360
|
+
zrb/task/llm/tool_wrapper.py,sha256=jfKMAtTzm--HnF6TppOrbkDVsuTOIFRpowQqgwqd-7s,6756
|
361
361
|
zrb/task/llm/typing.py,sha256=c8VAuPBw_4A3DxfYdydkgedaP-LU61W9_wj3m3CAX1E,58
|
362
|
-
zrb/task/llm_task.py,sha256=
|
362
|
+
zrb/task/llm_task.py,sha256=jVuVeN2ylcPkycUiaTpavkkd1tBLbvcVsjMNN5FMHnk,13536
|
363
363
|
zrb/task/make_task.py,sha256=PD3b_aYazthS8LHeJsLAhwKDEgdurQZpymJDKeN60u0,2265
|
364
364
|
zrb/task/rsync_task.py,sha256=WfqNSaicJgYWpunNU34eYxXDqHDHOftuDHyWJKjqwg0,6365
|
365
365
|
zrb/task/scaffolder.py,sha256=rME18w1HJUHXgi9eTYXx_T2G4JdqDYzBoNOkdOOo5-o,6806
|
@@ -370,6 +370,7 @@ zrb/task_status/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
370
370
|
zrb/task_status/task_status.py,sha256=blZ8dxg9g_8MuViq-t7yJRLoE7yGUf5srgHf-PCsXNc,3069
|
371
371
|
zrb/util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
372
372
|
zrb/util/attr.py,sha256=5GlYSmVAzbcSFjNDXiqqHqNMR6NWjJ6bUHZXdE35mj8,5359
|
373
|
+
zrb/util/callable.py,sha256=b6OFXbCXp2twow3wh2E_h5hNHLs2pXaLfGQz4iVyiQc,771
|
373
374
|
zrb/util/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
374
375
|
zrb/util/cli/style.py,sha256=D_548KG1gXEirQGdkAVTc81vBdCeInXtnG1gV1yabBA,6655
|
375
376
|
zrb/util/cli/subcommand.py,sha256=umTZIlrL-9g-qc_eRRgdaQgK-whvXK1roFfvnbuY7NQ,1753
|
@@ -394,7 +395,7 @@ zrb/util/git_subtree.py,sha256=AyQWCWEi2EIzEpYXRnYN55157KMUql0WHj70QNw5PHU,4612
|
|
394
395
|
zrb/util/git_subtree_model.py,sha256=P_gJ0zhOAc3gFM6sYcjc0Ack9dFBt75TI5fXdE0q320,871
|
395
396
|
zrb/util/group.py,sha256=T82yr3qg9I5k10VPXkMyrIRIqyfzadSH813bqzwKEPI,4718
|
396
397
|
zrb/util/init_path.py,sha256=9eN7CkWNGhDBpjTQs2j9YHVMzui7Y8DEb1WP4aTPzeo,659
|
397
|
-
zrb/util/llm/prompt.py,sha256=
|
398
|
+
zrb/util/llm/prompt.py,sha256=HMpKby27DE8lJWpytYKylp7Iw9ENwsYQI0nMMKCCi54,2190
|
398
399
|
zrb/util/load.py,sha256=DK0KYSlu48HCoGPqnW1IxnE3pHrZSPCstfz8Fjyqqv8,2140
|
399
400
|
zrb/util/run.py,sha256=vu-mcSWDP_WuuvIKqM_--Gk3WkABO1oTXiHmBRTvVQk,546
|
400
401
|
zrb/util/string/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -405,7 +406,7 @@ zrb/util/todo.py,sha256=r9_KYF2-hLKMNjsp6AFK9zivykMrywd-kJ4bCwfdafI,19323
|
|
405
406
|
zrb/util/todo_model.py,sha256=hhzAX-uFl5rsg7iVX1ULlJOfBtblwQ_ieNUxBWfc-Os,1670
|
406
407
|
zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
407
408
|
zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
|
408
|
-
zrb-1.
|
409
|
-
zrb-1.
|
410
|
-
zrb-1.
|
411
|
-
zrb-1.
|
409
|
+
zrb-1.13.0.dist-info/METADATA,sha256=L9X70AkHGlYTjK0tdgjlwA_Sj4U0Ao9FtPuk-g0UmJ0,9777
|
410
|
+
zrb-1.13.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
411
|
+
zrb-1.13.0.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
|
412
|
+
zrb-1.13.0.dist-info/RECORD,,
|
@@ -1,238 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
import re
|
3
|
-
from typing import Callable, Generator, NamedTuple
|
4
|
-
|
5
|
-
|
6
|
-
class Section(NamedTuple):
|
7
|
-
name: str
|
8
|
-
key: str
|
9
|
-
content: str
|
10
|
-
config_file: str
|
11
|
-
|
12
|
-
|
13
|
-
def _parse_config_file(
|
14
|
-
config_file: str, lines: list[str]
|
15
|
-
) -> Generator[Section, None, None]:
|
16
|
-
"""
|
17
|
-
Parses a config file's lines, yielding sections.
|
18
|
-
It correctly handles markdown code fences.
|
19
|
-
"""
|
20
|
-
any_header_pattern = re.compile(r"^# (\w+):\s*(.*)")
|
21
|
-
fence_pattern = re.compile(r"^([`~]{3,})")
|
22
|
-
fence_stack = []
|
23
|
-
active_section_name = None
|
24
|
-
active_section_key = None
|
25
|
-
active_section_content = []
|
26
|
-
|
27
|
-
for line in lines:
|
28
|
-
stripped_line = line.strip()
|
29
|
-
fence_match = fence_pattern.match(stripped_line)
|
30
|
-
|
31
|
-
if fence_match:
|
32
|
-
current_fence = fence_match.group(1)
|
33
|
-
if (
|
34
|
-
fence_stack
|
35
|
-
and fence_stack[-1][0] == current_fence[0]
|
36
|
-
and len(current_fence) >= len(fence_stack[-1])
|
37
|
-
):
|
38
|
-
fence_stack.pop()
|
39
|
-
else:
|
40
|
-
fence_stack.append(current_fence)
|
41
|
-
|
42
|
-
if fence_stack:
|
43
|
-
if active_section_key is not None:
|
44
|
-
active_section_content.append(line)
|
45
|
-
continue
|
46
|
-
|
47
|
-
match = any_header_pattern.match(line)
|
48
|
-
if match:
|
49
|
-
if active_section_key is not None:
|
50
|
-
content = "".join(active_section_content).strip()
|
51
|
-
if content:
|
52
|
-
yield Section(
|
53
|
-
name=active_section_name,
|
54
|
-
key=active_section_key,
|
55
|
-
content=content,
|
56
|
-
config_file=config_file,
|
57
|
-
)
|
58
|
-
|
59
|
-
active_section_name = match.group(1)
|
60
|
-
active_section_key = match.group(2).strip()
|
61
|
-
active_section_content = []
|
62
|
-
elif active_section_key is not None:
|
63
|
-
active_section_content.append(line)
|
64
|
-
|
65
|
-
if active_section_key is not None:
|
66
|
-
content = "".join(active_section_content).strip()
|
67
|
-
if content:
|
68
|
-
yield Section(
|
69
|
-
name=active_section_name,
|
70
|
-
key=active_section_key,
|
71
|
-
content=content,
|
72
|
-
config_file=config_file,
|
73
|
-
)
|
74
|
-
|
75
|
-
|
76
|
-
def _get_config_file_hierarchy(path: str, config_file_name: str) -> list[str]:
|
77
|
-
"""Finds all config files from a given path up to the home directory."""
|
78
|
-
config_files = []
|
79
|
-
home_dir = os.path.expanduser("~")
|
80
|
-
current_path = os.path.abspath(path)
|
81
|
-
while True:
|
82
|
-
config_path = os.path.join(current_path, config_file_name)
|
83
|
-
if os.path.exists(config_path):
|
84
|
-
config_files.append(config_path)
|
85
|
-
if current_path == home_dir:
|
86
|
-
break
|
87
|
-
parent = os.path.dirname(current_path)
|
88
|
-
if parent == current_path: # Reached root
|
89
|
-
break
|
90
|
-
current_path = parent
|
91
|
-
return config_files
|
92
|
-
|
93
|
-
|
94
|
-
class LLMContextConfigHandler:
|
95
|
-
"""Handles the logic for a specific section of the config."""
|
96
|
-
|
97
|
-
def __init__(
|
98
|
-
self,
|
99
|
-
section_name: str,
|
100
|
-
config_file_name: str = "ZRB.md",
|
101
|
-
filter_section_func: Callable[[str, str], bool] | None = None,
|
102
|
-
resolve_section_path: bool = True,
|
103
|
-
):
|
104
|
-
self._section_name = section_name
|
105
|
-
self._config_file_name = config_file_name
|
106
|
-
self._filter_func = filter_section_func
|
107
|
-
self._resolve_section_path = resolve_section_path
|
108
|
-
|
109
|
-
def _include_section(self, section_path: str, base_path: str) -> bool:
|
110
|
-
if self._filter_func:
|
111
|
-
return self._filter_func(section_path, base_path)
|
112
|
-
return True
|
113
|
-
|
114
|
-
def get_section(self, cwd: str) -> dict[str, str]:
|
115
|
-
"""Gathers all relevant sections for a given path."""
|
116
|
-
abs_path = os.path.abspath(cwd)
|
117
|
-
all_sections = {}
|
118
|
-
config_files = _get_config_file_hierarchy(abs_path, self._config_file_name)
|
119
|
-
|
120
|
-
for config_file in reversed(config_files):
|
121
|
-
if not os.path.exists(config_file):
|
122
|
-
continue
|
123
|
-
with open(config_file, "r") as f:
|
124
|
-
lines = f.readlines()
|
125
|
-
|
126
|
-
for section in _parse_config_file(config_file, lines):
|
127
|
-
if section.name != self._section_name:
|
128
|
-
continue
|
129
|
-
|
130
|
-
config_dir = os.path.dirname(section.config_file)
|
131
|
-
key = (
|
132
|
-
os.path.abspath(os.path.join(config_dir, section.key))
|
133
|
-
if self._resolve_section_path
|
134
|
-
else section.key
|
135
|
-
)
|
136
|
-
|
137
|
-
if self._include_section(key, abs_path):
|
138
|
-
if key in all_sections:
|
139
|
-
all_sections[key] = f"{all_sections[key]}\n{section.content}"
|
140
|
-
else:
|
141
|
-
all_sections[key] = section.content
|
142
|
-
|
143
|
-
return all_sections
|
144
|
-
|
145
|
-
def add_to_section(self, content: str, key: str, cwd: str):
|
146
|
-
"""Adds content to a section block in the nearest configuration file."""
|
147
|
-
abs_search_path = os.path.abspath(cwd)
|
148
|
-
config_files = _get_config_file_hierarchy(
|
149
|
-
abs_search_path, self._config_file_name
|
150
|
-
)
|
151
|
-
closest_config_file = (
|
152
|
-
config_files[0]
|
153
|
-
if config_files
|
154
|
-
else os.path.join(os.path.expanduser("~"), self._config_file_name)
|
155
|
-
)
|
156
|
-
|
157
|
-
config_dir = os.path.dirname(closest_config_file)
|
158
|
-
header_key = key
|
159
|
-
if self._resolve_section_path and os.path.isabs(key):
|
160
|
-
if key == config_dir:
|
161
|
-
header_key = "."
|
162
|
-
elif key.startswith(config_dir):
|
163
|
-
header_key = f"./{os.path.relpath(key, config_dir)}"
|
164
|
-
header = f"# {self._section_name}: {header_key}"
|
165
|
-
new_content = content.strip()
|
166
|
-
lines = []
|
167
|
-
if os.path.exists(closest_config_file):
|
168
|
-
with open(closest_config_file, "r") as f:
|
169
|
-
lines = f.readlines()
|
170
|
-
header_index = next(
|
171
|
-
(i for i, line in enumerate(lines) if line.strip() == header), -1
|
172
|
-
)
|
173
|
-
if header_index != -1:
|
174
|
-
insert_index = len(lines)
|
175
|
-
for i in range(header_index + 1, len(lines)):
|
176
|
-
if re.match(r"^# \w+:", lines[i].strip()):
|
177
|
-
insert_index = i
|
178
|
-
break
|
179
|
-
if insert_index > 0 and lines[insert_index - 1].strip():
|
180
|
-
lines.insert(insert_index, f"\n{new_content}\n")
|
181
|
-
else:
|
182
|
-
lines.insert(insert_index, f"{new_content}\n")
|
183
|
-
else:
|
184
|
-
if lines and lines[-1].strip():
|
185
|
-
lines.append("\n\n")
|
186
|
-
lines.append(f"{header}\n")
|
187
|
-
lines.append(f"{new_content}\n")
|
188
|
-
with open(closest_config_file, "w") as f:
|
189
|
-
f.writelines(lines)
|
190
|
-
|
191
|
-
def remove_from_section(self, content: str, key: str, cwd: str) -> bool:
|
192
|
-
"""Removes content from a section block in all relevant config files."""
|
193
|
-
abs_search_path = os.path.abspath(cwd)
|
194
|
-
config_files = _get_config_file_hierarchy(
|
195
|
-
abs_search_path, self._config_file_name
|
196
|
-
)
|
197
|
-
content_to_remove = content.strip()
|
198
|
-
was_removed = False
|
199
|
-
for config_file_path in config_files:
|
200
|
-
if not os.path.exists(config_file_path):
|
201
|
-
continue
|
202
|
-
with open(config_file_path, "r") as f:
|
203
|
-
file_content = f.read()
|
204
|
-
config_dir = os.path.dirname(config_file_path)
|
205
|
-
header_key = key
|
206
|
-
if self._resolve_section_path and os.path.isabs(key):
|
207
|
-
if key == config_dir:
|
208
|
-
header_key = "."
|
209
|
-
elif key.startswith(config_dir):
|
210
|
-
header_key = f"./{os.path.relpath(key, config_dir)}"
|
211
|
-
header = f"# {self._section_name}: {header_key}"
|
212
|
-
# Use regex to find the section content
|
213
|
-
section_pattern = re.compile(
|
214
|
-
rf"^{re.escape(header)}\n(.*?)(?=\n# \w+:|\Z)",
|
215
|
-
re.DOTALL | re.MULTILINE,
|
216
|
-
)
|
217
|
-
match = section_pattern.search(file_content)
|
218
|
-
if not match:
|
219
|
-
continue
|
220
|
-
|
221
|
-
section_content = match.group(1)
|
222
|
-
# Remove the target content and handle surrounding newlines
|
223
|
-
new_section_content = section_content.replace(content_to_remove, "")
|
224
|
-
new_section_content = "\n".join(
|
225
|
-
line for line in new_section_content.splitlines() if line.strip()
|
226
|
-
)
|
227
|
-
|
228
|
-
if new_section_content != section_content.strip():
|
229
|
-
was_removed = True
|
230
|
-
# Reconstruct the file content
|
231
|
-
start = match.start(1)
|
232
|
-
end = match.end(1)
|
233
|
-
new_file_content = (
|
234
|
-
file_content[:start] + new_section_content + file_content[end:]
|
235
|
-
)
|
236
|
-
with open(config_file_path, "w") as f:
|
237
|
-
f.write(new_file_content)
|
238
|
-
return was_removed
|
File without changes
|
File without changes
|