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

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

Potentially problematic release.


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

Files changed (108) hide show
  1. zrb/__init__.py +2 -6
  2. zrb/attr/type.py +10 -7
  3. zrb/builtin/__init__.py +2 -0
  4. zrb/builtin/git.py +12 -1
  5. zrb/builtin/group.py +31 -15
  6. zrb/builtin/llm/attachment.py +40 -0
  7. zrb/builtin/llm/chat_completion.py +274 -0
  8. zrb/builtin/llm/chat_session.py +126 -167
  9. zrb/builtin/llm/chat_session_cmd.py +288 -0
  10. zrb/builtin/llm/chat_trigger.py +79 -0
  11. zrb/builtin/llm/history.py +4 -4
  12. zrb/builtin/llm/llm_ask.py +217 -135
  13. zrb/builtin/llm/tool/api.py +74 -70
  14. zrb/builtin/llm/tool/cli.py +35 -21
  15. zrb/builtin/llm/tool/code.py +55 -73
  16. zrb/builtin/llm/tool/file.py +278 -344
  17. zrb/builtin/llm/tool/note.py +84 -0
  18. zrb/builtin/llm/tool/rag.py +27 -34
  19. zrb/builtin/llm/tool/sub_agent.py +54 -41
  20. zrb/builtin/llm/tool/web.py +74 -98
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  22. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  23. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  24. zrb/builtin/searxng/config/settings.yml +5671 -0
  25. zrb/builtin/searxng/start.py +21 -0
  26. zrb/builtin/shell/autocomplete/bash.py +4 -3
  27. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  28. zrb/config/config.py +202 -27
  29. zrb/config/default_prompt/file_extractor_system_prompt.md +109 -9
  30. zrb/config/default_prompt/interactive_system_prompt.md +24 -30
  31. zrb/config/default_prompt/persona.md +1 -1
  32. zrb/config/default_prompt/repo_extractor_system_prompt.md +31 -31
  33. zrb/config/default_prompt/repo_summarizer_system_prompt.md +27 -8
  34. zrb/config/default_prompt/summarization_prompt.md +57 -16
  35. zrb/config/default_prompt/system_prompt.md +36 -30
  36. zrb/config/llm_config.py +119 -23
  37. zrb/config/llm_context/config.py +127 -90
  38. zrb/config/llm_context/config_parser.py +1 -7
  39. zrb/config/llm_context/workflow.py +81 -0
  40. zrb/config/llm_rate_limitter.py +100 -47
  41. zrb/context/any_shared_context.py +7 -1
  42. zrb/context/context.py +8 -2
  43. zrb/context/shared_context.py +3 -7
  44. zrb/group/any_group.py +3 -3
  45. zrb/group/group.py +3 -3
  46. zrb/input/any_input.py +5 -1
  47. zrb/input/base_input.py +18 -6
  48. zrb/input/option_input.py +13 -1
  49. zrb/input/text_input.py +7 -24
  50. zrb/runner/cli.py +21 -20
  51. zrb/runner/common_util.py +24 -19
  52. zrb/runner/web_route/task_input_api_route.py +5 -5
  53. zrb/runner/web_util/user.py +7 -3
  54. zrb/session/any_session.py +12 -6
  55. zrb/session/session.py +39 -18
  56. zrb/task/any_task.py +24 -3
  57. zrb/task/base/context.py +17 -9
  58. zrb/task/base/execution.py +15 -8
  59. zrb/task/base/lifecycle.py +8 -4
  60. zrb/task/base/monitoring.py +12 -7
  61. zrb/task/base_task.py +69 -5
  62. zrb/task/base_trigger.py +12 -5
  63. zrb/task/llm/agent.py +128 -167
  64. zrb/task/llm/agent_runner.py +152 -0
  65. zrb/task/llm/config.py +39 -20
  66. zrb/task/llm/conversation_history.py +110 -29
  67. zrb/task/llm/conversation_history_model.py +4 -179
  68. zrb/task/llm/default_workflow/coding/workflow.md +41 -0
  69. zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
  70. zrb/task/llm/default_workflow/git/workflow.md +118 -0
  71. zrb/task/llm/default_workflow/golang/workflow.md +128 -0
  72. zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
  73. zrb/task/llm/default_workflow/java/workflow.md +146 -0
  74. zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
  75. zrb/task/llm/default_workflow/python/workflow.md +160 -0
  76. zrb/task/llm/default_workflow/researching/workflow.md +153 -0
  77. zrb/task/llm/default_workflow/rust/workflow.md +162 -0
  78. zrb/task/llm/default_workflow/shell/workflow.md +299 -0
  79. zrb/task/llm/file_replacement.py +206 -0
  80. zrb/task/llm/file_tool_model.py +57 -0
  81. zrb/task/llm/history_processor.py +206 -0
  82. zrb/task/llm/history_summarization.py +2 -193
  83. zrb/task/llm/print_node.py +184 -64
  84. zrb/task/llm/prompt.py +175 -179
  85. zrb/task/llm/subagent_conversation_history.py +41 -0
  86. zrb/task/llm/tool_wrapper.py +226 -85
  87. zrb/task/llm/workflow.py +76 -0
  88. zrb/task/llm_task.py +109 -71
  89. zrb/task/make_task.py +2 -3
  90. zrb/task/rsync_task.py +25 -10
  91. zrb/task/scheduler.py +4 -4
  92. zrb/util/attr.py +54 -39
  93. zrb/util/cli/markdown.py +12 -0
  94. zrb/util/cli/text.py +30 -0
  95. zrb/util/file.py +12 -3
  96. zrb/util/git.py +2 -2
  97. zrb/util/{llm/prompt.py → markdown.py} +2 -3
  98. zrb/util/string/conversion.py +1 -1
  99. zrb/util/truncate.py +23 -0
  100. zrb/util/yaml.py +204 -0
  101. zrb/xcom/xcom.py +10 -0
  102. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/METADATA +38 -18
  103. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/RECORD +105 -79
  104. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/WHEEL +1 -1
  105. zrb/task/llm/default_workflow/coding.md +0 -24
  106. zrb/task/llm/default_workflow/copywriting.md +0 -17
  107. zrb/task/llm/default_workflow/researching.md +0 -18
  108. {zrb-1.15.3.dist-info → zrb-1.21.29.dist-info}/entry_points.txt +0 -0
zrb/task/llm_task.py CHANGED
@@ -3,40 +3,44 @@ from collections.abc import Callable
3
3
  from typing import TYPE_CHECKING, Any
4
4
 
5
5
  from zrb.attr.type import BoolAttr, IntAttr, StrAttr, StrListAttr, fstring
6
- from zrb.config.llm_rate_limitter import LLMRateLimiter
6
+ from zrb.config.llm_rate_limitter import LLMRateLimitter
7
7
  from zrb.context.any_context import AnyContext
8
- from zrb.context.any_shared_context import AnySharedContext
9
8
  from zrb.env.any_env import AnyEnv
10
9
  from zrb.input.any_input import AnyInput
11
10
  from zrb.task.any_task import AnyTask
12
11
  from zrb.task.base_task import BaseTask
13
- 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
14
14
  from zrb.task.llm.config import (
15
- get_is_yolo_mode,
16
15
  get_model,
17
16
  get_model_settings,
17
+ get_yolo_mode,
18
18
  )
19
19
  from zrb.task.llm.conversation_history import (
20
+ inject_conversation_history_notes,
20
21
  read_conversation_history,
21
22
  write_conversation_history,
22
23
  )
23
24
  from zrb.task.llm.conversation_history_model import ConversationHistory
24
- from zrb.task.llm.history_summarization import maybe_summarize_history
25
+ from zrb.task.llm.history_summarization import get_history_summarization_token_threshold
25
26
  from zrb.task.llm.prompt import (
26
27
  get_attachments,
27
28
  get_summarization_system_prompt,
28
29
  get_system_and_user_prompt,
29
30
  get_user_message,
30
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
31
37
  from zrb.util.cli.style import stylize_faint
32
38
  from zrb.xcom.xcom import Xcom
33
39
 
34
40
  if TYPE_CHECKING:
35
- from pydantic_ai import Agent, Tool
36
- from pydantic_ai.messages import UserContent
41
+ from pydantic_ai import AbstractToolset, Agent, Tool, UserContent
37
42
  from pydantic_ai.models import Model
38
43
  from pydantic_ai.settings import ModelSettings
39
- from pydantic_ai.toolsets import AbstractToolset
40
44
 
41
45
  ToolOrCallable = Tool | Callable
42
46
 
@@ -51,62 +55,74 @@ class LLMTask(BaseTask):
51
55
  cli_only: bool = False,
52
56
  input: list[AnyInput | None] | AnyInput | None = None,
53
57
  env: list[AnyEnv | None] | AnyEnv | None = None,
54
- model: (
55
- "Callable[[AnySharedContext], Model | str | fstring] | Model | None"
56
- ) = None,
58
+ model: "Callable[[AnyContext], Model | str | fstring | None] | Model | None" = None,
57
59
  render_model: bool = True,
58
- model_base_url: StrAttr | None = None,
60
+ model_base_url: "Callable[[AnyContext], str | None] | str | None" = None,
59
61
  render_model_base_url: bool = True,
60
- model_api_key: StrAttr | None = None,
62
+ model_api_key: "Callable[[AnyContext], str | None] | str | None" = None,
61
63
  render_model_api_key: bool = True,
62
64
  model_settings: (
63
- "ModelSettings | Callable[[AnySharedContext], ModelSettings] | None"
65
+ "ModelSettings | Callable[[AnyContext], ModelSettings] | None"
66
+ ) = None,
67
+ small_model: (
68
+ "Callable[[AnyContext], Model | str | fstring] | Model | None"
64
69
  ) = None,
65
- agent: "Agent | Callable[[AnySharedContext], Agent] | None" = None,
66
- persona: StrAttr | None = 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,
67
79
  render_persona: bool = False,
68
- system_prompt: StrAttr | None = None,
80
+ system_prompt: "Callable[[AnyContext], str | None] | str | None" = None,
69
81
  render_system_prompt: bool = False,
70
- special_instruction_prompt: StrAttr | None = None,
82
+ special_instruction_prompt: "Callable[[AnyContext], str | None] | str | None" = None,
71
83
  render_special_instruction_prompt: bool = False,
72
- modes: StrListAttr | None = None,
73
- render_modes: bool = True,
84
+ workflows: StrListAttr | None = None,
85
+ render_workflows: bool = True,
74
86
  message: StrAttr | None = None,
75
- attachment: "UserContent | list[UserContent] | Callable[[AnySharedContext], UserContent | list[UserContent]] | None" = None, # noqa
87
+ attachment: "UserContent | list[UserContent] | Callable[[AnyContext], UserContent | list[UserContent]] | None" = None, # noqa
76
88
  render_message: bool = True,
77
89
  tools: (
78
- list["ToolOrCallable"]
79
- | Callable[[AnySharedContext], list["ToolOrCallable"]]
90
+ list["ToolOrCallable"] | Callable[[AnyContext], list["ToolOrCallable"]]
80
91
  ) = [],
81
92
  toolsets: (
82
- list["AbstractToolset[Agent]"] | Callable[[AnySharedContext], list["Tool"]]
93
+ list["AbstractToolset[None] | str"]
94
+ | Callable[[AnyContext], list["AbstractToolset[None] | str"]]
83
95
  ) = [],
84
96
  conversation_history: (
85
97
  ConversationHistory
86
- | Callable[[AnySharedContext], ConversationHistory | dict | list]
98
+ | Callable[[AnyContext], ConversationHistory | dict | list]
87
99
  | dict
88
100
  | list
89
101
  ) = ConversationHistory(),
90
102
  conversation_history_reader: (
91
- Callable[[AnySharedContext], ConversationHistory | dict | list | None]
92
- | None
103
+ Callable[[AnyContext], ConversationHistory | dict | list | None] | None
93
104
  ) = None,
94
105
  conversation_history_writer: (
95
- Callable[[AnySharedContext, ConversationHistory], None] | None
106
+ Callable[[AnyContext, ConversationHistory], None] | None
96
107
  ) = None,
97
108
  conversation_history_file: StrAttr | None = None,
98
109
  render_history_file: bool = True,
99
110
  summarize_history: BoolAttr | None = None,
100
111
  render_summarize_history: bool = True,
101
- summarization_prompt: StrAttr | None = None,
112
+ summarization_prompt: "Callable[[AnyContext], str | None] | str | None" = None,
102
113
  render_summarization_prompt: bool = False,
103
114
  history_summarization_token_threshold: IntAttr | None = None,
104
115
  render_history_summarization_token_threshold: bool = True,
105
- rate_limitter: LLMRateLimiter | None = None,
106
- execute_condition: bool | str | Callable[[AnySharedContext], bool] = True,
116
+ rate_limitter: LLMRateLimitter | None = None,
117
+ execute_condition: bool | str | Callable[[AnyContext], bool] = True,
107
118
  retries: int = 2,
108
119
  retry_period: float = 0,
109
- is_yolo_mode: bool | None = None,
120
+ yolo_mode: (
121
+ Callable[[AnyContext], list[str] | bool | None]
122
+ | StrListAttr
123
+ | BoolAttr
124
+ | None
125
+ ) = None,
110
126
  render_yolo_mode: bool = True,
111
127
  readiness_check: list[AnyTask] | AnyTask | None = None,
112
128
  readiness_check_delay: float = 0.5,
@@ -119,7 +135,7 @@ class LLMTask(BaseTask):
119
135
  fallback: list[AnyTask] | AnyTask | None = None,
120
136
  successor: list[AnyTask] | AnyTask | None = None,
121
137
  conversation_context: (
122
- dict[str, Any] | Callable[[AnySharedContext], dict[str, Any]] | None
138
+ dict[str, Any] | Callable[[AnyContext], dict[str, Any]] | None
123
139
  ) = None,
124
140
  ):
125
141
  super().__init__(
@@ -150,24 +166,30 @@ class LLMTask(BaseTask):
150
166
  self._model_api_key = model_api_key
151
167
  self._render_model_api_key = render_model_api_key
152
168
  self._model_settings = model_settings
153
- 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
154
176
  self._persona = persona
155
177
  self._render_persona = render_persona
156
178
  self._system_prompt = system_prompt
157
179
  self._render_system_prompt = render_system_prompt
158
180
  self._special_instruction_prompt = special_instruction_prompt
159
181
  self._render_special_instruction_prompt = render_special_instruction_prompt
160
- self._modes = modes
161
- self._render_modes = render_modes
182
+ self._workflows = workflows
183
+ self._render_workflows = render_workflows
162
184
  self._message = message
163
185
  self._render_message = render_message
164
186
  self._summarization_prompt = summarization_prompt
165
187
  self._render_summarization_prompt = render_summarization_prompt
166
188
  self._tools = tools
167
189
  self._rate_limitter = rate_limitter
168
- self._additional_tools: list["ToolOrCallable"] = []
190
+ self._additional_tools: list["ToolOrCallable"] = [load_workflow]
169
191
  self._toolsets = toolsets
170
- self._additional_toolsets: list["AbstractToolset[Agent]"] = []
192
+ self._additional_toolsets: list["AbstractToolset[None] | str"] = []
171
193
  self._conversation_history = conversation_history
172
194
  self._conversation_history_reader = conversation_history_reader
173
195
  self._conversation_history_writer = conversation_history_writer
@@ -183,7 +205,7 @@ class LLMTask(BaseTask):
183
205
  )
184
206
  self._max_call_iteration = max_call_iteration
185
207
  self._conversation_context = conversation_context
186
- self._is_yolo_mode = is_yolo_mode
208
+ self._yolo_mode = yolo_mode
187
209
  self._render_yolo_mode = render_yolo_mode
188
210
  self._attachment = attachment
189
211
 
@@ -194,10 +216,10 @@ class LLMTask(BaseTask):
194
216
  for single_tool in tool:
195
217
  self._additional_tools.append(single_tool)
196
218
 
197
- def add_toolset(self, *toolset: "AbstractToolset[Agent]"):
219
+ def add_toolset(self, *toolset: "AbstractToolset[None] | str"):
198
220
  self.append_toolset(*toolset)
199
221
 
200
- def append_toolset(self, *toolset: "AbstractToolset[Agent]"):
222
+ def append_toolset(self, *toolset: "AbstractToolset[None] | str"):
201
223
  for single_toolset in toolset:
202
224
  self._additional_toolsets.append(single_toolset)
203
225
 
@@ -209,6 +231,12 @@ class LLMTask(BaseTask):
209
231
  ):
210
232
  self._history_summarization_token_threshold = summarization_token_threshold
211
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
239
+
212
240
  async def _exec_action(self, ctx: AnyContext) -> Any:
213
241
  # Get dependent configurations first
214
242
  model_settings = get_model_settings(ctx, self._model_settings)
@@ -221,9 +249,9 @@ class LLMTask(BaseTask):
221
249
  model_api_key_attr=self._model_api_key,
222
250
  render_model_api_key=self._render_model_api_key,
223
251
  )
224
- is_yolo_mode = get_is_yolo_mode(
252
+ yolo_mode = get_yolo_mode(
225
253
  ctx=ctx,
226
- is_yolo_mode_attr=self._is_yolo_mode,
254
+ yolo_mode_attr=self._yolo_mode,
227
255
  render_yolo_mode=self._render_yolo_mode,
228
256
  )
229
257
  summarization_prompt = get_summarization_system_prompt(
@@ -241,9 +269,10 @@ class LLMTask(BaseTask):
241
269
  render_history_file=self._render_history_file,
242
270
  conversation_history_attr=self._conversation_history,
243
271
  )
244
- conversation_history.fetch_newest_notes()
272
+ inject_conversation_history_notes(conversation_history)
273
+ inject_subagent_conversation_history_into_ctx(ctx, conversation_history)
245
274
  # 2. Get system prompt and user prompt
246
- system_prompt, user_message = get_system_and_user_prompt(
275
+ system_prompt, user_prompt = get_system_and_user_prompt(
247
276
  ctx=ctx,
248
277
  user_message=user_message,
249
278
  persona_attr=self._persona,
@@ -252,50 +281,59 @@ class LLMTask(BaseTask):
252
281
  render_system_prompt=self._render_system_prompt,
253
282
  special_instruction_prompt_attr=self._special_instruction_prompt,
254
283
  render_special_instruction_prompt=self._render_special_instruction_prompt,
255
- modes_attr=self._modes,
256
- render_modes=self._render_modes,
284
+ workflows_attr=self._workflows,
285
+ render_workflows=self._render_workflows,
257
286
  conversation_history=conversation_history,
258
287
  )
259
- ctx.log_debug(f"SYSTEM PROMPT: {system_prompt}")
260
- # 3. Get the agent instance
288
+ # 3. Summarization
289
+ small_model = get_model(
290
+ ctx=ctx,
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,
297
+ )
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,
303
+ )
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}")
261
307
  agent = get_agent(
262
308
  ctx=ctx,
263
- agent_attr=self._agent,
264
309
  model=model,
310
+ rate_limitter=self._rate_limitter,
265
311
  system_prompt=system_prompt,
266
312
  model_settings=model_settings,
267
313
  tools_attr=self._tools,
268
314
  additional_tools=self._additional_tools,
269
315
  toolsets_attr=self._toolsets,
270
316
  additional_toolsets=self._additional_toolsets,
271
- is_yolo_mode=is_yolo_mode,
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
272
324
  )
273
- # 4. Run the agent iteration and save the results/history
325
+ # 5. Run the agent iteration and save the results/history
274
326
  result = await self._execute_agent(
275
327
  ctx=ctx,
276
328
  agent=agent,
277
- user_prompt=user_message,
329
+ user_prompt=user_prompt,
278
330
  attachments=attachments,
279
331
  conversation_history=conversation_history,
280
332
  )
281
- # 5. Summarize
282
- conversation_history = await maybe_summarize_history(
283
- ctx=ctx,
284
- conversation_history=conversation_history,
285
- should_summarize_history_attr=self._should_summarize_history,
286
- render_summarize_history=self._render_summarize_history,
287
- history_summarization_token_threshold_attr=(
288
- self._history_summarization_token_threshold
289
- ),
290
- render_history_summarization_token_threshold=(
291
- self._render_history_summarization_token_threshold
292
- ),
293
- model=model,
294
- model_settings=model_settings,
295
- summarization_prompt=summarization_prompt,
296
- rate_limitter=self._rate_limitter,
297
- )
298
333
  # 6. Write conversation history
334
+ conversation_history.subagent_history = (
335
+ extract_subagent_conversation_history_from_ctx(ctx)
336
+ )
299
337
  await write_conversation_history(
300
338
  ctx=ctx,
301
339
  history_data=conversation_history,
@@ -331,7 +369,7 @@ class LLMTask(BaseTask):
331
369
  ctx.xcom[xcom_usage_key] = Xcom([])
332
370
  usage = agent_run.result.usage()
333
371
  ctx.xcom[xcom_usage_key].push(usage)
334
- ctx.print(stylize_faint(f" 💸 Token: {usage}"), plain=True)
372
+ ctx.print(stylize_faint(f" 💸 Token: {usage}"), plain=True)
335
373
  return agent_run.result.output
336
374
  else:
337
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,
@@ -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)