zrb 1.8.10__py3-none-any.whl → 1.21.29__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of zrb might be problematic. Click here for more details.

Files changed (147) hide show
  1. zrb/__init__.py +126 -113
  2. zrb/__main__.py +1 -1
  3. zrb/attr/type.py +10 -7
  4. zrb/builtin/__init__.py +2 -50
  5. zrb/builtin/git.py +12 -1
  6. zrb/builtin/group.py +31 -15
  7. zrb/builtin/http.py +7 -8
  8. zrb/builtin/llm/attachment.py +40 -0
  9. zrb/builtin/llm/chat_completion.py +274 -0
  10. zrb/builtin/llm/chat_session.py +152 -85
  11. zrb/builtin/llm/chat_session_cmd.py +288 -0
  12. zrb/builtin/llm/chat_trigger.py +79 -0
  13. zrb/builtin/llm/history.py +7 -9
  14. zrb/builtin/llm/llm_ask.py +221 -98
  15. zrb/builtin/llm/tool/api.py +74 -52
  16. zrb/builtin/llm/tool/cli.py +46 -17
  17. zrb/builtin/llm/tool/code.py +71 -90
  18. zrb/builtin/llm/tool/file.py +301 -241
  19. zrb/builtin/llm/tool/note.py +84 -0
  20. zrb/builtin/llm/tool/rag.py +38 -8
  21. zrb/builtin/llm/tool/sub_agent.py +67 -50
  22. zrb/builtin/llm/tool/web.py +146 -122
  23. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  24. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  25. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  26. zrb/builtin/searxng/config/settings.yml +5671 -0
  27. zrb/builtin/searxng/start.py +21 -0
  28. zrb/builtin/setup/latex/ubuntu.py +1 -0
  29. zrb/builtin/setup/ubuntu.py +1 -1
  30. zrb/builtin/shell/autocomplete/bash.py +4 -3
  31. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  32. zrb/builtin/todo.py +13 -2
  33. zrb/config/config.py +614 -0
  34. zrb/config/default_prompt/file_extractor_system_prompt.md +112 -0
  35. zrb/config/default_prompt/interactive_system_prompt.md +29 -0
  36. zrb/config/default_prompt/persona.md +1 -0
  37. zrb/config/default_prompt/repo_extractor_system_prompt.md +112 -0
  38. zrb/config/default_prompt/repo_summarizer_system_prompt.md +29 -0
  39. zrb/config/default_prompt/summarization_prompt.md +57 -0
  40. zrb/config/default_prompt/system_prompt.md +38 -0
  41. zrb/config/llm_config.py +339 -0
  42. zrb/config/llm_context/config.py +166 -0
  43. zrb/config/llm_context/config_parser.py +40 -0
  44. zrb/config/llm_context/workflow.py +81 -0
  45. zrb/config/llm_rate_limitter.py +190 -0
  46. zrb/{runner → config}/web_auth_config.py +17 -22
  47. zrb/context/any_shared_context.py +17 -1
  48. zrb/context/context.py +16 -2
  49. zrb/context/shared_context.py +18 -8
  50. zrb/group/any_group.py +12 -5
  51. zrb/group/group.py +67 -3
  52. zrb/input/any_input.py +5 -1
  53. zrb/input/base_input.py +18 -6
  54. zrb/input/option_input.py +13 -1
  55. zrb/input/text_input.py +8 -25
  56. zrb/runner/cli.py +25 -23
  57. zrb/runner/common_util.py +24 -19
  58. zrb/runner/web_app.py +3 -3
  59. zrb/runner/web_route/docs_route.py +1 -1
  60. zrb/runner/web_route/error_page/serve_default_404.py +1 -1
  61. zrb/runner/web_route/error_page/show_error_page.py +1 -1
  62. zrb/runner/web_route/home_page/home_page_route.py +2 -2
  63. zrb/runner/web_route/login_api_route.py +1 -1
  64. zrb/runner/web_route/login_page/login_page_route.py +2 -2
  65. zrb/runner/web_route/logout_api_route.py +1 -1
  66. zrb/runner/web_route/logout_page/logout_page_route.py +2 -2
  67. zrb/runner/web_route/node_page/group/show_group_page.py +1 -1
  68. zrb/runner/web_route/node_page/node_page_route.py +1 -1
  69. zrb/runner/web_route/node_page/task/show_task_page.py +1 -1
  70. zrb/runner/web_route/refresh_token_api_route.py +1 -1
  71. zrb/runner/web_route/static/static_route.py +1 -1
  72. zrb/runner/web_route/task_input_api_route.py +6 -6
  73. zrb/runner/web_route/task_session_api_route.py +20 -12
  74. zrb/runner/web_util/cookie.py +1 -1
  75. zrb/runner/web_util/token.py +1 -1
  76. zrb/runner/web_util/user.py +8 -4
  77. zrb/session/any_session.py +24 -17
  78. zrb/session/session.py +50 -25
  79. zrb/session_state_logger/any_session_state_logger.py +9 -4
  80. zrb/session_state_logger/file_session_state_logger.py +16 -6
  81. zrb/session_state_logger/session_state_logger_factory.py +1 -1
  82. zrb/task/any_task.py +30 -9
  83. zrb/task/base/context.py +17 -9
  84. zrb/task/base/execution.py +15 -8
  85. zrb/task/base/lifecycle.py +8 -4
  86. zrb/task/base/monitoring.py +12 -7
  87. zrb/task/base_task.py +69 -5
  88. zrb/task/base_trigger.py +12 -5
  89. zrb/task/cmd_task.py +1 -1
  90. zrb/task/llm/agent.py +154 -161
  91. zrb/task/llm/agent_runner.py +152 -0
  92. zrb/task/llm/config.py +47 -18
  93. zrb/task/llm/conversation_history.py +209 -0
  94. zrb/task/llm/conversation_history_model.py +67 -0
  95. zrb/task/llm/default_workflow/coding/workflow.md +41 -0
  96. zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
  97. zrb/task/llm/default_workflow/git/workflow.md +118 -0
  98. zrb/task/llm/default_workflow/golang/workflow.md +128 -0
  99. zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
  100. zrb/task/llm/default_workflow/java/workflow.md +146 -0
  101. zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
  102. zrb/task/llm/default_workflow/python/workflow.md +160 -0
  103. zrb/task/llm/default_workflow/researching/workflow.md +153 -0
  104. zrb/task/llm/default_workflow/rust/workflow.md +162 -0
  105. zrb/task/llm/default_workflow/shell/workflow.md +299 -0
  106. zrb/task/llm/error.py +24 -10
  107. zrb/task/llm/file_replacement.py +206 -0
  108. zrb/task/llm/file_tool_model.py +57 -0
  109. zrb/task/llm/history_processor.py +206 -0
  110. zrb/task/llm/history_summarization.py +11 -166
  111. zrb/task/llm/print_node.py +193 -69
  112. zrb/task/llm/prompt.py +242 -45
  113. zrb/task/llm/subagent_conversation_history.py +41 -0
  114. zrb/task/llm/tool_wrapper.py +260 -57
  115. zrb/task/llm/workflow.py +76 -0
  116. zrb/task/llm_task.py +182 -171
  117. zrb/task/make_task.py +2 -3
  118. zrb/task/rsync_task.py +26 -11
  119. zrb/task/scheduler.py +4 -4
  120. zrb/util/attr.py +54 -39
  121. zrb/util/callable.py +23 -0
  122. zrb/util/cli/markdown.py +12 -0
  123. zrb/util/cli/text.py +30 -0
  124. zrb/util/file.py +29 -11
  125. zrb/util/git.py +8 -11
  126. zrb/util/git_diff_model.py +10 -0
  127. zrb/util/git_subtree.py +9 -14
  128. zrb/util/git_subtree_model.py +32 -0
  129. zrb/util/init_path.py +1 -1
  130. zrb/util/markdown.py +62 -0
  131. zrb/util/string/conversion.py +2 -2
  132. zrb/util/todo.py +17 -50
  133. zrb/util/todo_model.py +46 -0
  134. zrb/util/truncate.py +23 -0
  135. zrb/util/yaml.py +204 -0
  136. zrb/xcom/xcom.py +10 -0
  137. zrb-1.21.29.dist-info/METADATA +270 -0
  138. {zrb-1.8.10.dist-info → zrb-1.21.29.dist-info}/RECORD +140 -98
  139. {zrb-1.8.10.dist-info → zrb-1.21.29.dist-info}/WHEEL +1 -1
  140. zrb/config.py +0 -335
  141. zrb/llm_config.py +0 -411
  142. zrb/llm_rate_limitter.py +0 -125
  143. zrb/task/llm/context.py +0 -102
  144. zrb/task/llm/context_enrichment.py +0 -199
  145. zrb/task/llm/history.py +0 -211
  146. zrb-1.8.10.dist-info/METADATA +0 -264
  147. {zrb-1.8.10.dist-info → zrb-1.21.29.dist-info}/entry_points.txt +0 -0
zrb/task/llm_task.py CHANGED
@@ -2,53 +2,47 @@ import json
2
2
  from collections.abc import Callable
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
- if TYPE_CHECKING:
6
- from pydantic_ai import Agent, Tool
7
- from pydantic_ai.mcp import MCPServer
8
- from pydantic_ai.models import Model
9
- from pydantic_ai.settings import ModelSettings
10
- else:
11
- Agent = Any
12
- Tool = Any
13
- MCPServer = Any
14
- Model = Any
15
- ModelSettings = Any
16
-
17
- from zrb.attr.type import BoolAttr, IntAttr, StrAttr, fstring
5
+ from zrb.attr.type import BoolAttr, IntAttr, StrAttr, StrListAttr, fstring
6
+ from zrb.config.llm_rate_limitter import LLMRateLimitter
18
7
  from zrb.context.any_context import AnyContext
19
- from zrb.context.any_shared_context import AnySharedContext
20
8
  from zrb.env.any_env import AnyEnv
21
9
  from zrb.input.any_input import AnyInput
22
- from zrb.llm_rate_limitter import LLMRateLimiter
23
10
  from zrb.task.any_task import AnyTask
24
11
  from zrb.task.base_task import BaseTask
25
- from zrb.task.llm.agent import get_agent, run_agent_iteration
12
+ from zrb.task.llm.agent import get_agent
13
+ from zrb.task.llm.agent_runner import run_agent_iteration
26
14
  from zrb.task.llm.config import (
27
15
  get_model,
28
16
  get_model_settings,
17
+ get_yolo_mode,
29
18
  )
30
- from zrb.task.llm.context import extract_default_context, get_conversation_context
31
- from zrb.task.llm.context_enrichment import maybe_enrich_context
32
- from zrb.task.llm.history import (
33
- ConversationHistoryData,
34
- ListOfDict,
19
+ from zrb.task.llm.conversation_history import (
20
+ inject_conversation_history_notes,
35
21
  read_conversation_history,
36
22
  write_conversation_history,
37
23
  )
38
- from zrb.task.llm.history_summarization import maybe_summarize_history
24
+ from zrb.task.llm.conversation_history_model import ConversationHistory
25
+ from zrb.task.llm.history_summarization import get_history_summarization_token_threshold
39
26
  from zrb.task.llm.prompt import (
40
- get_combined_system_prompt,
41
- get_context_enrichment_prompt,
42
- get_summarization_prompt,
27
+ get_attachments,
28
+ get_summarization_system_prompt,
29
+ get_system_and_user_prompt,
43
30
  get_user_message,
44
31
  )
32
+ from zrb.task.llm.subagent_conversation_history import (
33
+ extract_subagent_conversation_history_from_ctx,
34
+ inject_subagent_conversation_history_into_ctx,
35
+ )
36
+ from zrb.task.llm.workflow import load_workflow
45
37
  from zrb.util.cli.style import stylize_faint
46
38
  from zrb.xcom.xcom import Xcom
47
39
 
48
40
  if TYPE_CHECKING:
41
+ from pydantic_ai import AbstractToolset, Agent, Tool, UserContent
42
+ from pydantic_ai.models import Model
43
+ from pydantic_ai.settings import ModelSettings
44
+
49
45
  ToolOrCallable = Tool | Callable
50
- else:
51
- ToolOrCallable = Any
52
46
 
53
47
 
54
48
  class LLMTask(BaseTask):
@@ -61,63 +55,75 @@ class LLMTask(BaseTask):
61
55
  cli_only: bool = False,
62
56
  input: list[AnyInput | None] | AnyInput | None = None,
63
57
  env: list[AnyEnv | None] | AnyEnv | None = None,
64
- model: (
65
- Callable[[AnySharedContext], Model | str | fstring] | Model | None
66
- ) = None,
58
+ model: "Callable[[AnyContext], Model | str | fstring | None] | Model | None" = None,
67
59
  render_model: bool = True,
68
- model_base_url: StrAttr | None = None,
60
+ model_base_url: "Callable[[AnyContext], str | None] | str | None" = None,
69
61
  render_model_base_url: bool = True,
70
- model_api_key: StrAttr | None = None,
62
+ model_api_key: "Callable[[AnyContext], str | None] | str | None" = None,
71
63
  render_model_api_key: bool = True,
72
64
  model_settings: (
73
- ModelSettings | Callable[[AnySharedContext], ModelSettings] | None
65
+ "ModelSettings | Callable[[AnyContext], ModelSettings] | None"
74
66
  ) = None,
75
- agent: Agent | Callable[[AnySharedContext], Agent] | None = None,
76
- persona: StrAttr | None = None,
77
- render_persona: bool = True,
78
- system_prompt: StrAttr | None = None,
79
- render_system_prompt: bool = True,
80
- special_instruction_prompt: StrAttr | None = None,
81
- render_special_instruction_prompt: bool = True,
67
+ small_model: (
68
+ "Callable[[AnyContext], Model | str | fstring] | Model | None"
69
+ ) = None,
70
+ render_small_model: bool = True,
71
+ small_model_base_url: StrAttr | None = None,
72
+ render_small_model_base_url: bool = True,
73
+ small_model_api_key: StrAttr | None = None,
74
+ render_small_model_api_key: bool = True,
75
+ small_model_settings: (
76
+ "ModelSettings | Callable[[AnyContext], ModelSettings] | None"
77
+ ) = None,
78
+ persona: "Callable[[AnyContext], str | None] | str | None" = None,
79
+ render_persona: bool = False,
80
+ system_prompt: "Callable[[AnyContext], str | None] | str | None" = None,
81
+ render_system_prompt: bool = False,
82
+ special_instruction_prompt: "Callable[[AnyContext], str | None] | str | None" = None,
83
+ render_special_instruction_prompt: bool = False,
84
+ workflows: StrListAttr | None = None,
85
+ render_workflows: bool = True,
82
86
  message: StrAttr | None = None,
83
- summarization_prompt: StrAttr | None = None,
84
- render_summarization_prompt: bool = True,
85
- enrich_context: BoolAttr | None = None,
86
- render_enrich_context: bool = True,
87
- context_enrichment_prompt: StrAttr | None = None,
88
- render_context_enrichment_prompt: bool = True,
89
- context_enrichment_threshold: IntAttr | None = None,
90
- render_context_enrichment_threshold: bool = True,
87
+ attachment: "UserContent | list[UserContent] | Callable[[AnyContext], UserContent | list[UserContent]] | None" = None, # noqa
88
+ render_message: bool = True,
91
89
  tools: (
92
- list["ToolOrCallable"]
93
- | Callable[[AnySharedContext], list["ToolOrCallable"]]
90
+ list["ToolOrCallable"] | Callable[[AnyContext], list["ToolOrCallable"]]
94
91
  ) = [],
95
- mcp_servers: (
96
- list["MCPServer"] | Callable[[AnySharedContext], list["MCPServer"]]
92
+ toolsets: (
93
+ list["AbstractToolset[None] | str"]
94
+ | Callable[[AnyContext], list["AbstractToolset[None] | str"]]
97
95
  ) = [],
98
96
  conversation_history: (
99
- ConversationHistoryData
100
- | Callable[[AnySharedContext], ConversationHistoryData | dict | list]
97
+ ConversationHistory
98
+ | Callable[[AnyContext], ConversationHistory | dict | list]
101
99
  | dict
102
100
  | list
103
- ) = ConversationHistoryData(),
101
+ ) = ConversationHistory(),
104
102
  conversation_history_reader: (
105
- Callable[[AnySharedContext], ConversationHistoryData | dict | list | None]
106
- | None
103
+ Callable[[AnyContext], ConversationHistory | dict | list | None] | None
107
104
  ) = None,
108
105
  conversation_history_writer: (
109
- Callable[[AnySharedContext, ConversationHistoryData], None] | None
106
+ Callable[[AnyContext, ConversationHistory], None] | None
110
107
  ) = None,
111
108
  conversation_history_file: StrAttr | None = None,
112
109
  render_history_file: bool = True,
113
110
  summarize_history: BoolAttr | None = None,
114
111
  render_summarize_history: bool = True,
115
- history_summarization_threshold: IntAttr | None = None,
116
- render_history_summarization_threshold: bool = True,
117
- rate_limitter: LLMRateLimiter | None = None,
118
- execute_condition: bool | str | Callable[[AnySharedContext], bool] = True,
112
+ summarization_prompt: "Callable[[AnyContext], str | None] | str | None" = None,
113
+ render_summarization_prompt: bool = False,
114
+ history_summarization_token_threshold: IntAttr | None = None,
115
+ render_history_summarization_token_threshold: bool = True,
116
+ rate_limitter: LLMRateLimitter | None = None,
117
+ execute_condition: bool | str | Callable[[AnyContext], bool] = True,
119
118
  retries: int = 2,
120
119
  retry_period: float = 0,
120
+ yolo_mode: (
121
+ Callable[[AnyContext], list[str] | bool | None]
122
+ | StrListAttr
123
+ | BoolAttr
124
+ | None
125
+ ) = None,
126
+ render_yolo_mode: bool = True,
121
127
  readiness_check: list[AnyTask] | AnyTask | None = None,
122
128
  readiness_check_delay: float = 0.5,
123
129
  readiness_check_period: float = 5,
@@ -129,7 +135,7 @@ class LLMTask(BaseTask):
129
135
  fallback: list[AnyTask] | AnyTask | None = None,
130
136
  successor: list[AnyTask] | AnyTask | None = None,
131
137
  conversation_context: (
132
- dict[str, Any] | Callable[[AnySharedContext], dict[str, Any]] | None
138
+ dict[str, Any] | Callable[[AnyContext], dict[str, Any]] | None
133
139
  ) = None,
134
140
  ):
135
141
  super().__init__(
@@ -160,27 +166,30 @@ class LLMTask(BaseTask):
160
166
  self._model_api_key = model_api_key
161
167
  self._render_model_api_key = render_model_api_key
162
168
  self._model_settings = model_settings
163
- self._agent = agent
169
+ self._small_model = small_model
170
+ self._render_small_model = render_small_model
171
+ self._small_model_base_url = small_model_base_url
172
+ self._render_small_model_base_url = render_small_model_base_url
173
+ self._small_model_api_key = small_model_api_key
174
+ self._render_small_model_api_key = render_small_model_api_key
175
+ self._small_model_settings = small_model_settings
164
176
  self._persona = persona
165
177
  self._render_persona = render_persona
166
178
  self._system_prompt = system_prompt
167
179
  self._render_system_prompt = render_system_prompt
168
180
  self._special_instruction_prompt = special_instruction_prompt
169
181
  self._render_special_instruction_prompt = render_special_instruction_prompt
182
+ self._workflows = workflows
183
+ self._render_workflows = render_workflows
170
184
  self._message = message
185
+ self._render_message = render_message
171
186
  self._summarization_prompt = summarization_prompt
172
187
  self._render_summarization_prompt = render_summarization_prompt
173
- self._should_enrich_context = enrich_context
174
- self._render_enrich_context = render_enrich_context
175
- self._context_enrichment_prompt = context_enrichment_prompt
176
- self._render_context_enrichment_prompt = render_context_enrichment_prompt
177
- self._context_enrichment_threshold = context_enrichment_threshold
178
- self._render_context_enrichment_threshold = render_context_enrichment_threshold
179
188
  self._tools = tools
180
189
  self._rate_limitter = rate_limitter
181
- self._additional_tools: list["ToolOrCallable"] = []
182
- self._mcp_servers = mcp_servers
183
- self._additional_mcp_servers: list["MCPServer"] = []
190
+ self._additional_tools: list["ToolOrCallable"] = [load_workflow]
191
+ self._toolsets = toolsets
192
+ self._additional_toolsets: list["AbstractToolset[None] | str"] = []
184
193
  self._conversation_history = conversation_history
185
194
  self._conversation_history_reader = conversation_history_reader
186
195
  self._conversation_history_writer = conversation_history_writer
@@ -188,38 +197,45 @@ class LLMTask(BaseTask):
188
197
  self._render_history_file = render_history_file
189
198
  self._should_summarize_history = summarize_history
190
199
  self._render_summarize_history = render_summarize_history
191
- self._history_summarization_threshold = history_summarization_threshold
192
- self._render_history_summarization_threshold = (
193
- render_history_summarization_threshold
200
+ self._history_summarization_token_threshold = (
201
+ history_summarization_token_threshold
202
+ )
203
+ self._render_history_summarization_token_threshold = (
204
+ render_history_summarization_token_threshold
194
205
  )
195
206
  self._max_call_iteration = max_call_iteration
196
207
  self._conversation_context = conversation_context
208
+ self._yolo_mode = yolo_mode
209
+ self._render_yolo_mode = render_yolo_mode
210
+ self._attachment = attachment
197
211
 
198
- def add_tool(self, *tool: ToolOrCallable):
212
+ def add_tool(self, *tool: "ToolOrCallable"):
199
213
  self.append_tool(*tool)
200
214
 
201
- def append_tool(self, *tool: ToolOrCallable):
215
+ def append_tool(self, *tool: "ToolOrCallable"):
202
216
  for single_tool in tool:
203
217
  self._additional_tools.append(single_tool)
204
218
 
205
- def add_mcp_server(self, *mcp_server: MCPServer):
206
- self.append_mcp_server(*mcp_server)
219
+ def add_toolset(self, *toolset: "AbstractToolset[None] | str"):
220
+ self.append_toolset(*toolset)
207
221
 
208
- def append_mcp_server(self, *mcp_server: MCPServer):
209
- for single_mcp_server in mcp_server:
210
- self._additional_mcp_servers.append(single_mcp_server)
211
-
212
- def set_should_enrich_context(self, enrich_context: bool):
213
- self._should_enrich_context = enrich_context
214
-
215
- def set_context_enrichment_threshold(self, enrichment_threshold: int):
216
- self._context_enrichment_threshold = enrichment_threshold
222
+ def append_toolset(self, *toolset: "AbstractToolset[None] | str"):
223
+ for single_toolset in toolset:
224
+ self._additional_toolsets.append(single_toolset)
217
225
 
218
226
  def set_should_summarize_history(self, summarize_history: bool):
219
227
  self._should_summarize_history = summarize_history
220
228
 
221
- def set_history_summarization_threshold(self, summarization_threshold: int):
222
- self._history_summarization_threshold = summarization_threshold
229
+ def set_history_summarization_token_threshold(
230
+ self, summarization_token_threshold: int
231
+ ):
232
+ self._history_summarization_token_threshold = summarization_token_threshold
233
+
234
+ def set_workflows(self, workflows: StrListAttr):
235
+ self._workflows = workflows
236
+
237
+ def set_yolo_mode(self, yolo_mode: StrListAttr | BoolAttr):
238
+ self._yolo_mode = yolo_mode
223
239
 
224
240
  async def _exec_action(self, ctx: AnyContext) -> Any:
225
241
  # Get dependent configurations first
@@ -233,27 +249,18 @@ class LLMTask(BaseTask):
233
249
  model_api_key_attr=self._model_api_key,
234
250
  render_model_api_key=self._render_model_api_key,
235
251
  )
236
- context_enrichment_prompt = get_context_enrichment_prompt(
252
+ yolo_mode = get_yolo_mode(
237
253
  ctx=ctx,
238
- context_enrichment_prompt_attr=self._context_enrichment_prompt,
239
- render_context_enrichment_prompt=self._render_context_enrichment_prompt,
254
+ yolo_mode_attr=self._yolo_mode,
255
+ render_yolo_mode=self._render_yolo_mode,
240
256
  )
241
- summarization_prompt = get_summarization_prompt(
257
+ summarization_prompt = get_summarization_system_prompt(
242
258
  ctx=ctx,
243
259
  summarization_prompt_attr=self._summarization_prompt,
244
260
  render_summarization_prompt=self._render_summarization_prompt,
245
261
  )
246
- user_message = get_user_message(ctx, self._message)
247
- # Get the combined system prompt using the new getter
248
- system_prompt = get_combined_system_prompt(
249
- ctx=ctx,
250
- persona_attr=self._persona,
251
- render_persona=self._render_persona,
252
- system_prompt_attr=self._system_prompt,
253
- render_system_prompt=self._render_system_prompt,
254
- special_instruction_prompt_attr=self._special_instruction_prompt,
255
- render_special_instruction_prompt=self._render_special_instruction_prompt,
256
- )
262
+ user_message = get_user_message(ctx, self._message, self._render_message)
263
+ attachments = get_attachments(ctx, self._attachment)
257
264
  # 1. Prepare initial state (read history from previous session)
258
265
  conversation_history = await read_conversation_history(
259
266
  ctx=ctx,
@@ -262,74 +269,87 @@ class LLMTask(BaseTask):
262
269
  render_history_file=self._render_history_file,
263
270
  conversation_history_attr=self._conversation_history,
264
271
  )
265
- history_list = conversation_history.history
266
- conversation_context = {
267
- **conversation_history.context,
268
- **get_conversation_context(ctx, self._conversation_context),
269
- }
270
- # 2. Enrich context (optional)
271
- conversation_context = await maybe_enrich_context(
272
+ inject_conversation_history_notes(conversation_history)
273
+ inject_subagent_conversation_history_into_ctx(ctx, conversation_history)
274
+ # 2. Get system prompt and user prompt
275
+ system_prompt, user_prompt = get_system_and_user_prompt(
272
276
  ctx=ctx,
273
- history_list=history_list,
274
- conversation_context=conversation_context,
275
- should_enrich_context_attr=self._should_enrich_context,
276
- render_enrich_context=self._render_enrich_context,
277
- context_enrichment_threshold_attr=self._context_enrichment_threshold,
278
- render_context_enrichment_threshold=self._render_context_enrichment_threshold,
279
- model=model,
280
- model_settings=model_settings,
281
- context_enrichment_prompt=context_enrichment_prompt,
282
- rate_limitter=self._rate_limitter,
277
+ user_message=user_message,
278
+ persona_attr=self._persona,
279
+ render_persona=self._render_persona,
280
+ system_prompt_attr=self._system_prompt,
281
+ render_system_prompt=self._render_system_prompt,
282
+ special_instruction_prompt_attr=self._special_instruction_prompt,
283
+ render_special_instruction_prompt=self._render_special_instruction_prompt,
284
+ workflows_attr=self._workflows,
285
+ render_workflows=self._render_workflows,
286
+ conversation_history=conversation_history,
283
287
  )
284
- # 3. Summarize history (optional, modifies history_list and context)
285
- history_list, conversation_context = await maybe_summarize_history(
288
+ # 3. Summarization
289
+ small_model = get_model(
286
290
  ctx=ctx,
287
- history_list=history_list,
288
- conversation_context=conversation_context,
289
- should_summarize_history_attr=self._should_summarize_history,
290
- render_summarize_history=self._render_summarize_history,
291
- history_summarization_threshold_attr=self._history_summarization_threshold,
292
- render_history_summarization_threshold=(
293
- self._render_history_summarization_threshold
294
- ),
295
- model=model,
296
- model_settings=model_settings,
297
- summarization_prompt=summarization_prompt,
298
- rate_limitter=self._rate_limitter,
291
+ model_attr=self._small_model,
292
+ render_model=self._render_small_model,
293
+ model_base_url_attr=self._small_model_base_url,
294
+ render_model_base_url=self._render_small_model_base_url,
295
+ model_api_key_attr=self._small_model_api_key,
296
+ render_model_api_key=self._render_small_model_api_key,
299
297
  )
300
- # 4. Build the final user prompt and system prompt
301
- final_user_prompt, default_context = extract_default_context(user_message)
302
- final_system_prompt = "\n".join(
303
- [
304
- system_prompt,
305
- "# Context",
306
- json.dumps({**default_context, **conversation_context}),
307
- ]
298
+ small_model_settings = get_model_settings(ctx, self._small_model_settings)
299
+ summarization_token_threshold = get_history_summarization_token_threshold(
300
+ ctx,
301
+ self._history_summarization_token_threshold,
302
+ self._render_history_summarization_token_threshold,
308
303
  )
309
- # 5. Get the agent instance
304
+ # 4. Get the agent instance
305
+ ctx.log_info(f"SYSTEM PROMPT:\n{system_prompt}")
306
+ ctx.log_info(f"USER PROMPT:\n{user_prompt}")
310
307
  agent = get_agent(
311
308
  ctx=ctx,
312
- agent_attr=self._agent,
313
309
  model=model,
314
- system_prompt=final_system_prompt,
310
+ rate_limitter=self._rate_limitter,
311
+ system_prompt=system_prompt,
315
312
  model_settings=model_settings,
316
313
  tools_attr=self._tools,
317
314
  additional_tools=self._additional_tools,
318
- mcp_servers_attr=self._mcp_servers,
319
- additional_mcp_servers=self._additional_mcp_servers,
315
+ toolsets_attr=self._toolsets,
316
+ additional_toolsets=self._additional_toolsets,
317
+ yolo_mode=yolo_mode,
318
+ summarization_model=small_model,
319
+ summarization_model_settings=small_model_settings,
320
+ summarization_system_prompt=summarization_prompt,
321
+ summarization_retries=2, # TODO: make this a property
322
+ summarization_token_threshold=summarization_token_threshold,
323
+ history_processors=[], # TODO: make this a property
320
324
  )
321
- # 6. Run the agent iteration and save the results/history
322
- return await self._run_agent_and_save_history(
323
- ctx, agent, final_user_prompt, history_list, conversation_context
325
+ # 5. Run the agent iteration and save the results/history
326
+ result = await self._execute_agent(
327
+ ctx=ctx,
328
+ agent=agent,
329
+ user_prompt=user_prompt,
330
+ attachments=attachments,
331
+ conversation_history=conversation_history,
332
+ )
333
+ # 6. Write conversation history
334
+ conversation_history.subagent_history = (
335
+ extract_subagent_conversation_history_from_ctx(ctx)
336
+ )
337
+ await write_conversation_history(
338
+ ctx=ctx,
339
+ history_data=conversation_history,
340
+ conversation_history_writer=self._conversation_history_writer,
341
+ conversation_history_file_attr=self._conversation_history_file,
342
+ render_history_file=self._render_history_file,
324
343
  )
344
+ return result
325
345
 
326
- async def _run_agent_and_save_history(
346
+ async def _execute_agent(
327
347
  self,
328
348
  ctx: AnyContext,
329
- agent: Agent,
349
+ agent: "Agent",
330
350
  user_prompt: str,
331
- history_list: ListOfDict,
332
- conversation_context: dict[str, Any],
351
+ attachments: "list[UserContent]",
352
+ conversation_history: ConversationHistory,
333
353
  ) -> Any:
334
354
  """Executes the agent, processes results, and saves history."""
335
355
  try:
@@ -337,28 +357,19 @@ class LLMTask(BaseTask):
337
357
  ctx=ctx,
338
358
  agent=agent,
339
359
  user_prompt=user_prompt,
340
- history_list=history_list,
360
+ attachments=attachments,
361
+ history_list=conversation_history.history,
341
362
  rate_limitter=self._rate_limitter,
342
363
  )
343
364
  if agent_run and agent_run.result:
344
365
  new_history_list = json.loads(agent_run.result.all_messages_json())
345
- data_to_write = ConversationHistoryData(
346
- context=conversation_context, # Save the final context state
347
- history=new_history_list,
348
- )
349
- await write_conversation_history(
350
- ctx=ctx,
351
- history_data=data_to_write,
352
- conversation_history_writer=self._conversation_history_writer,
353
- conversation_history_file_attr=self._conversation_history_file,
354
- render_history_file=self._render_history_file,
355
- )
366
+ conversation_history.history = new_history_list
356
367
  xcom_usage_key = f"{self.name}-usage"
357
368
  if xcom_usage_key not in ctx.xcom:
358
369
  ctx.xcom[xcom_usage_key] = Xcom([])
359
370
  usage = agent_run.result.usage()
360
- ctx.xcom.get(xcom_usage_key).push(usage)
361
- ctx.print(stylize_faint(f"[Token Usage] {usage}"), plain=True)
371
+ ctx.xcom[xcom_usage_key].push(usage)
372
+ ctx.print(stylize_faint(f" 💸 Token: {usage}"), plain=True)
362
373
  return agent_run.result.output
363
374
  else:
364
375
  ctx.log_warning("Agent run did not produce a result.")
zrb/task/make_task.py CHANGED
@@ -2,7 +2,6 @@ from collections.abc import Callable
2
2
  from typing import Any
3
3
 
4
4
  from zrb.context.any_context import AnyContext
5
- from zrb.context.any_shared_context import AnySharedContext
6
5
  from zrb.env.any_env import AnyEnv
7
6
  from zrb.group.any_group import AnyGroup
8
7
  from zrb.input.any_input import AnyInput
@@ -18,7 +17,7 @@ def make_task(
18
17
  cli_only: bool = False,
19
18
  input: list[AnyInput | None] | AnyInput | None = None,
20
19
  env: list[AnyEnv | None] | AnyEnv | None = None,
21
- execute_condition: bool | str | Callable[[AnySharedContext], bool] = True,
20
+ execute_condition: bool | str | Callable[[AnyContext], bool] = True,
22
21
  retries: int = 2,
23
22
  retry_period: float = 0,
24
23
  readiness_check: list[AnyTask] | AnyTask | None = None,
@@ -33,7 +32,7 @@ def make_task(
33
32
  group: AnyGroup | None = None,
34
33
  alias: str | None = None,
35
34
  ) -> Callable[[Callable[[AnyContext], Any]], AnyTask]:
36
- def _make_task(fn: Callable[[AnyContext], Any]) -> BaseTask:
35
+ def _make_task(fn: Callable[[AnyContext], Any]) -> AnyTask:
37
36
  task = BaseTask(
38
37
  name=name,
39
38
  color=color,
zrb/task/rsync_task.py CHANGED
@@ -1,6 +1,4 @@
1
- from collections.abc import Callable
2
-
3
- from zrb.attr.type import IntAttr, StrAttr
1
+ from zrb.attr.type import BoolAttr, IntAttr, StrAttr
4
2
  from zrb.context.any_context import AnyContext
5
3
  from zrb.env.any_env import AnyEnv
6
4
  from zrb.input.any_input import AnyInput
@@ -17,8 +15,8 @@ class RsyncTask(CmdTask):
17
15
  icon: str | None = None,
18
16
  description: str | None = None,
19
17
  cli_only: bool = False,
20
- input: list[AnyInput] | AnyInput | None = None,
21
- env: list[AnyEnv] | AnyEnv | None = None,
18
+ input: list[AnyInput | None] | AnyInput | None = None,
19
+ env: list[AnyEnv | None] | AnyEnv | None = None,
22
20
  shell: StrAttr | None = None,
23
21
  auto_render_shell: bool = True,
24
22
  remote_host: StrAttr | None = None,
@@ -39,12 +37,14 @@ class RsyncTask(CmdTask):
39
37
  render_local_source_path: bool = True,
40
38
  local_destination_path: StrAttr | None = None,
41
39
  render_local_destination_path: bool = True,
40
+ exclude_from: StrAttr | None = None,
41
+ render_exclude_from: bool = True,
42
42
  cwd: str | None = None,
43
43
  render_cwd: bool = True,
44
44
  plain_print: bool = False,
45
45
  max_output_line: int = 1000,
46
46
  max_error_line: int = 1000,
47
- execute_condition: bool | str | Callable[[AnyContext], bool] = True,
47
+ execute_condition: BoolAttr = True,
48
48
  retries: int = 2,
49
49
  retry_period: float = 0,
50
50
  readiness_check: list[AnyTask] | AnyTask | None = None,
@@ -65,7 +65,7 @@ class RsyncTask(CmdTask):
65
65
  remote_host=remote_host,
66
66
  render_remote_host=render_remote_host,
67
67
  remote_port=remote_port,
68
- auto_render_remote_port=render_remote_port,
68
+ render_remote_port=render_remote_port,
69
69
  remote_user=remote_user,
70
70
  render_remote_user=render_remote_user,
71
71
  remote_password=remote_password,
@@ -93,6 +93,8 @@ class RsyncTask(CmdTask):
93
93
  self._render_local_source_path = render_local_source_path
94
94
  self._local_destination_path = local_destination_path
95
95
  self._render_local_destination_path = render_local_destination_path
96
+ self._exclude_from = exclude_from
97
+ self._render_exclude_from = render_exclude_from
96
98
 
97
99
  def _get_source_path(self, ctx: AnyContext) -> str:
98
100
  local_source_path = self._get_local_source_path(ctx)
@@ -144,16 +146,29 @@ class RsyncTask(CmdTask):
144
146
  auto_render=self._render_local_destination_path,
145
147
  )
146
148
 
149
+ def _get_exclude_from_param(self, ctx: AnyContext) -> str:
150
+ exclude_from = get_str_attr(
151
+ ctx,
152
+ self._exclude_from,
153
+ "",
154
+ auto_render=self._render_exclude_from,
155
+ ).strip()
156
+ if exclude_from == "":
157
+ return ""
158
+ return f"--exclude-from='{exclude_from}'"
159
+
147
160
  def _get_cmd_script(self, ctx: AnyContext) -> str:
148
161
  port = self._get_remote_port(ctx)
149
162
  password = self._get_remote_password(ctx)
150
163
  key = self._get_remote_ssh_key(ctx)
151
164
  src = self._get_source_path(ctx)
152
165
  dst = self._get_destination_path(ctx)
166
+ exclude_from = self._get_exclude_from_param(ctx)
167
+ exclude_from_with_space = f"{exclude_from} " if exclude_from != "" else ""
153
168
  if key != "" and password != "":
154
- return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -i {key} -p {port}" {src} {dst}' # noqa
169
+ return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -i {key} -p {port}" {exclude_from_with_space}{src} {dst}' # noqa
155
170
  if key != "":
156
- return f'rsync --mkpath -avz -e "ssh -i {key} -p {port}" {src} {dst}'
171
+ return f'rsync --mkpath -avz -e "ssh -i {key} -p {port}" {exclude_from_with_space}{src} {dst}' # noqa
157
172
  if password != "":
158
- return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -p {port}" {src} {dst}' # noqa
159
- return f'rsync --mkpath -avz -e "ssh -p {port}" {src} {dst}'
173
+ return f'sshpass -p "$_ZRB_SSH_PASSWORD" rsync --mkpath -avz -e "ssh -p {port}" {exclude_from_with_space}{src} {dst}' # noqa
174
+ return f'rsync --mkpath -avz -e "ssh -p {port}" {exclude_from_with_space}{src} {dst}'
zrb/task/scheduler.py CHANGED
@@ -24,8 +24,8 @@ class Scheduler(BaseTrigger):
24
24
  cli_only: bool = False,
25
25
  input: list[AnyInput | None] | AnyInput | None = None,
26
26
  env: list[AnyEnv | None] | AnyEnv | None = None,
27
- schedule: StrAttr = None,
28
- execute_condition: bool | str | Callable[[AnySharedContext], bool] = True,
27
+ schedule: StrAttr | None = None,
28
+ execute_condition: bool | str | Callable[[AnyContext], bool] = True,
29
29
  queue_name: fstring | None = None,
30
30
  callback: list[AnyCallback] | AnyCallback = [],
31
31
  retries: int = 2,
@@ -76,6 +76,6 @@ class Scheduler(BaseTrigger):
76
76
  ctx.print(f"Current time: {now}")
77
77
  if match_cron(cron_pattern, now):
78
78
  ctx.print(f"Matching {now} with pattern: {cron_pattern}")
79
- xcom = self.get_exchange_xcom(ctx.session)
80
- xcom.push(now)
79
+ if ctx.session is not None:
80
+ self.push_exchange_xcom(ctx.session, now)
81
81
  await asyncio.sleep(60)