zrb 1.8.13__py3-none-any.whl → 1.8.14__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.
@@ -25,6 +25,8 @@ async def read_user_prompt(ctx: AnyContext) -> str:
25
25
  Returns:
26
26
  The final result from the LLM session.
27
27
  """
28
+ from prompt_toolkit import PromptSession
29
+
28
30
  _show_info(ctx)
29
31
  final_result = ""
30
32
  ctx.print(stylize_faint("🧑 >> ") + f"{ctx.input.message}", plain=True)
@@ -41,10 +43,12 @@ async def read_user_prompt(ctx: AnyContext) -> str:
41
43
  return final_result
42
44
  multiline_mode = False
43
45
  user_inputs = []
46
+ user_input_session = PromptSession()
44
47
  while True:
45
48
  await asyncio.sleep(0.01)
46
49
  ctx.print(stylize_faint("🧑 >> "), end="", plain=True)
47
- user_input = input()
50
+ user_input = await user_input_session.prompt_async()
51
+ # user_input = input()
48
52
  # Handle special input
49
53
  if user_input.strip().lower() in ("/bye", "/quit"):
50
54
  user_prompt = "\n".join(user_inputs)
@@ -3,23 +3,17 @@ from collections.abc import Callable
3
3
  from textwrap import dedent
4
4
  from typing import TYPE_CHECKING, Any, Coroutine
5
5
 
6
- if TYPE_CHECKING:
7
- from pydantic_ai import Tool
8
- from pydantic_ai.mcp import MCPServer
9
- from pydantic_ai.models import Model
10
- from pydantic_ai.settings import ModelSettings
11
- else:
12
- Tool = Any
13
- MCPServer = Any
14
- Model = Any
15
- ModelSettings = Any
16
-
17
6
  from zrb.context.any_context import AnyContext
18
7
  from zrb.task.llm.agent import create_agent_instance, run_agent_iteration
19
8
  from zrb.task.llm.config import get_model, get_model_settings
20
9
  from zrb.task.llm.prompt import get_combined_system_prompt
21
10
 
22
11
  if TYPE_CHECKING:
12
+ from pydantic_ai import Tool
13
+ from pydantic_ai.mcp import MCPServer
14
+ from pydantic_ai.models import Model
15
+ from pydantic_ai.settings import ModelSettings
16
+
23
17
  ToolOrCallable = Tool | Callable
24
18
  else:
25
19
  ToolOrCallable = Any
@@ -29,10 +23,10 @@ def create_sub_agent_tool(
29
23
  tool_name: str,
30
24
  tool_description: str,
31
25
  system_prompt: str | None = None,
32
- model: str | Model | None = None,
33
- model_settings: ModelSettings | None = None,
26
+ model: "str | Model | None" = None,
27
+ model_settings: "ModelSettings | None" = None,
34
28
  tools: list[ToolOrCallable] = [],
35
- mcp_servers: list[MCPServer] = [],
29
+ mcp_servers: list["MCPServer"] = [],
36
30
  ) -> Callable[[AnyContext, str], Coroutine[Any, Any, str]]:
37
31
  """
38
32
  Create an LLM "sub-agent" tool function for use by a main LLM agent.
zrb/builtin/todo.py CHANGED
@@ -11,7 +11,6 @@ from zrb.input.text_input import TextInput
11
11
  from zrb.task.make_task import make_task
12
12
  from zrb.util.file import read_file, write_file
13
13
  from zrb.util.todo import (
14
- TodoTaskModel,
15
14
  add_duration,
16
15
  cascade_todo_task,
17
16
  get_visual_todo_card,
@@ -72,6 +71,8 @@ def _get_filter_input(
72
71
  alias="add",
73
72
  )
74
73
  def add_todo(ctx: AnyContext):
74
+ from zrb.util.todo_model import TodoTaskModel
75
+
75
76
  todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
76
77
  todo_list: list[TodoTaskModel] = []
77
78
  if os.path.isfile(todo_file_path):
@@ -108,6 +109,8 @@ def add_todo(ctx: AnyContext):
108
109
  alias="list",
109
110
  )
110
111
  def list_todo(ctx: AnyContext):
112
+ from zrb.util.todo_model import TodoTaskModel
113
+
111
114
  todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
112
115
  todo_list: list[TodoTaskModel] = []
113
116
  if os.path.isfile(todo_file_path):
@@ -123,6 +126,8 @@ def list_todo(ctx: AnyContext):
123
126
  alias="show",
124
127
  )
125
128
  def show_todo(ctx: AnyContext):
129
+ from zrb.util.todo_model import TodoTaskModel
130
+
126
131
  todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
127
132
  todo_list: list[TodoTaskModel] = []
128
133
  todo_list: list[TodoTaskModel] = []
@@ -157,6 +162,8 @@ def show_todo(ctx: AnyContext):
157
162
  alias="complete",
158
163
  )
159
164
  def complete_todo(ctx: AnyContext):
165
+ from zrb.util.todo_model import TodoTaskModel
166
+
160
167
  todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
161
168
  todo_list: list[TodoTaskModel] = []
162
169
  if os.path.isfile(todo_file_path):
@@ -187,6 +194,8 @@ def complete_todo(ctx: AnyContext):
187
194
  alias="archive",
188
195
  )
189
196
  def archive_todo(ctx: AnyContext):
197
+ from zrb.util.todo_model import TodoTaskModel
198
+
190
199
  todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
191
200
  todo_list: list[TodoTaskModel] = []
192
201
  if os.path.isfile(todo_file_path):
@@ -248,6 +257,8 @@ def archive_todo(ctx: AnyContext):
248
257
  alias="log",
249
258
  )
250
259
  def log_todo(ctx: AnyContext):
260
+ from zrb.util.todo_model import TodoTaskModel
261
+
251
262
  todo_file_path = os.path.join(CFG.TODO_DIR, "todo.txt")
252
263
  todo_list: list[TodoTaskModel] = []
253
264
  if os.path.isfile(todo_file_path):
zrb/llm_config.py CHANGED
@@ -1,15 +1,12 @@
1
- from typing import TYPE_CHECKING, Any
1
+ from typing import TYPE_CHECKING
2
+
3
+ from zrb.config import CFG
2
4
 
3
5
  if TYPE_CHECKING:
4
6
  from pydantic_ai.models import Model
5
7
  from pydantic_ai.providers import Provider
6
8
  from pydantic_ai.settings import ModelSettings
7
- else:
8
- Model = Any
9
- ModelSettings = Any
10
- Provider = Any
11
9
 
12
- from zrb.config import CFG
13
10
 
14
11
  DEFAULT_PERSONA = (
15
12
  "You are a helpful and precise expert assistant. Your goal is to follow "
@@ -217,9 +214,9 @@ class LLMConfig:
217
214
  default_history_summarization_threshold: int | None = None,
218
215
  default_enrich_context: bool | None = None,
219
216
  default_context_enrichment_threshold: int | None = None,
220
- default_model: Model | None = None,
221
- default_model_settings: ModelSettings | None = None,
222
- default_model_provider: Provider | None = None,
217
+ default_model: "Model | None" = None,
218
+ default_model_settings: "ModelSettings | None" = None,
219
+ default_model_provider: "Provider | None" = None,
223
220
  ):
224
221
  self._default_model_name = default_model_name
225
222
  self._default_model_base_url = default_base_url
@@ -266,13 +263,13 @@ class LLMConfig:
266
263
  return CFG.LLM_API_KEY
267
264
 
268
265
  @property
269
- def default_model_settings(self) -> ModelSettings | None:
266
+ def default_model_settings(self) -> "ModelSettings | None":
270
267
  if self._default_model_settings is not None:
271
268
  return self._default_model_settings
272
269
  return None
273
270
 
274
271
  @property
275
- def default_model_provider(self) -> Provider | str:
272
+ def default_model_provider(self) -> "Provider | str":
276
273
  if self._default_model_provider is not None:
277
274
  return self._default_model_provider
278
275
  if self.default_model_base_url is None and self.default_model_api_key is None:
@@ -332,7 +329,7 @@ class LLMConfig:
332
329
  return DEFAULT_CONTEXT_ENRICHMENT_PROMPT
333
330
 
334
331
  @property
335
- def default_model(self) -> Model | str | None:
332
+ def default_model(self) -> "Model | str | None":
336
333
  if self._default_model is not None:
337
334
  return self._default_model
338
335
  model_name = self.default_model_name
@@ -396,10 +393,10 @@ class LLMConfig:
396
393
  def set_default_model_base_url(self, model_base_url: str):
397
394
  self._default_model_base_url = model_base_url
398
395
 
399
- def set_default_model_provider(self, provider: Provider | str):
396
+ def set_default_model_provider(self, provider: "Provider | str"):
400
397
  self._default_model_provider = provider
401
398
 
402
- def set_default_model(self, model: Model | str):
399
+ def set_default_model(self, model: "Model | str"):
403
400
  self._default_model = model
404
401
 
405
402
  def set_default_summarize_history(self, summarize_history: bool):
@@ -418,7 +415,7 @@ class LLMConfig:
418
415
  ):
419
416
  self._default_context_enrichment_threshold = context_enrichment_threshold
420
417
 
421
- def set_default_model_settings(self, model_settings: ModelSettings):
418
+ def set_default_model_settings(self, model_settings: "ModelSettings"):
422
419
  self._default_model_settings = model_settings
423
420
 
424
421
 
zrb/runner/cli.py CHANGED
@@ -7,7 +7,6 @@ from zrb.context.shared_context import SharedContext
7
7
  from zrb.group.any_group import AnyGroup
8
8
  from zrb.group.group import Group
9
9
  from zrb.runner.common_util import get_run_kwargs
10
- from zrb.runner.web_app import create_web_app
11
10
  from zrb.runner.web_auth_config import web_auth_config
12
11
  from zrb.session.session import Session
13
12
  from zrb.session_state_logger.session_state_logger_factory import session_state_logger
@@ -187,6 +186,8 @@ server_group = cli.add_group(
187
186
  async def start_server(_: AnyContext):
188
187
  from uvicorn import Config, Server
189
188
 
189
+ from zrb.runner.web_app import create_web_app
190
+
190
191
  app = create_web_app(cli, web_auth_config, session_state_logger)
191
192
  server = Server(
192
193
  Config(
@@ -1,9 +1,11 @@
1
- from typing import Callable
1
+ from typing import TYPE_CHECKING, Callable
2
2
 
3
3
  from zrb.config import CFG
4
- from zrb.runner.web_schema.user import User
5
4
  from zrb.task.any_task import AnyTask
6
5
 
6
+ if TYPE_CHECKING:
7
+ from zrb.runner.web_schema.user import User
8
+
7
9
 
8
10
  class WebAuthConfig:
9
11
  def __init__(
@@ -18,7 +20,7 @@ class WebAuthConfig:
18
20
  super_admin_password: str | None = None,
19
21
  guest_username: str | None = None,
20
22
  guest_accessible_tasks: list[AnyTask | str] = [],
21
- find_user_by_username: Callable[[str], User | None] | None = None,
23
+ find_user_by_username: Callable[[str], "User | None"] | None = None,
22
24
  ):
23
25
  self._secret_key = secret_key
24
26
  self._access_token_expire_minutes = access_token_expire_minutes
@@ -29,7 +31,7 @@ class WebAuthConfig:
29
31
  self._super_admin_username = super_admin_username
30
32
  self._super_admin_password = super_admin_password
31
33
  self._guest_username = guest_username
32
- self._user_list = []
34
+ self._user_list: list["User"] = []
33
35
  self._guest_accessible_tasks = guest_accessible_tasks
34
36
  self._find_user_by_username = find_user_by_username
35
37
 
@@ -92,7 +94,9 @@ class WebAuthConfig:
92
94
  return self._guest_accessible_tasks
93
95
 
94
96
  @property
95
- def default_user(self) -> User:
97
+ def default_user(self) -> "User":
98
+ from zrb.runner.web_schema.user import User
99
+
96
100
  if self.enable_auth:
97
101
  return User(
98
102
  username=self.guest_username,
@@ -108,7 +112,9 @@ class WebAuthConfig:
108
112
  )
109
113
 
110
114
  @property
111
- def super_admin(self) -> User:
115
+ def super_admin(self) -> "User":
116
+ from zrb.runner.web_schema.user import User
117
+
112
118
  return User(
113
119
  username=self.super_admin_username,
114
120
  password=self.super_admin_password,
@@ -116,7 +122,7 @@ class WebAuthConfig:
116
122
  )
117
123
 
118
124
  @property
119
- def user_list(self) -> list[User]:
125
+ def user_list(self) -> list["User"]:
120
126
  if not self.enable_auth:
121
127
  return [self.default_user]
122
128
  return self._user_list + [self.super_admin, self.default_user]
@@ -152,11 +158,11 @@ class WebAuthConfig:
152
158
  self._guest_accessible_tasks = tasks
153
159
 
154
160
  def set_find_user_by_username(
155
- self, find_user_by_username: Callable[[str], User | None]
161
+ self, find_user_by_username: Callable[[str], "User | None"]
156
162
  ):
157
163
  self._find_user_by_username = find_user_by_username
158
164
 
159
- def append_user(self, user: User):
165
+ def append_user(self, user: "User"):
160
166
  duplicates = [
161
167
  existing_user
162
168
  for existing_user in self.user_list
@@ -166,7 +172,7 @@ class WebAuthConfig:
166
172
  raise ValueError(f"User already exists {user.username}")
167
173
  self._user_list.append(user)
168
174
 
169
- def find_user_by_username(self, username: str) -> User | None:
175
+ def find_user_by_username(self, username: str) -> "User | None":
170
176
  user = None
171
177
  if self._find_user_by_username is not None:
172
178
  user = self._find_user_by_username(username)
@@ -9,16 +9,18 @@ from zrb.runner.web_auth_config import WebAuthConfig
9
9
  from zrb.runner.web_schema.session import NewSessionResponse
10
10
  from zrb.runner.web_util.user import get_user_from_request
11
11
  from zrb.session.session import Session
12
- from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
13
12
  from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
14
13
  from zrb.task.any_task import AnyTask
15
14
  from zrb.util.group import NodeNotFoundError, extract_node_from_args, get_node_path
16
15
 
17
16
  if TYPE_CHECKING:
18
- # We want fastapi to only be loaded when necessary to decrease footprint
19
-
20
17
  from fastapi import FastAPI
21
18
 
19
+ from zrb.session_state_log.session_state_log import (
20
+ SessionStateLog,
21
+ SessionStateLogList,
22
+ )
23
+
22
24
 
23
25
  def serve_task_session_api(
24
26
  app: "FastAPI",
@@ -30,6 +32,11 @@ def serve_task_session_api(
30
32
  from fastapi import Query, Request
31
33
  from fastapi.responses import JSONResponse
32
34
 
35
+ from zrb.session_state_log.session_state_log import (
36
+ SessionStateLog,
37
+ SessionStateLogList,
38
+ )
39
+
33
40
  @app.post("/api/v1/task-sessions/{path:path}")
34
41
  async def create_new_task_session_api(
35
42
  path: str,
@@ -110,8 +117,10 @@ def serve_task_session_api(
110
117
 
111
118
 
112
119
  def sanitize_session_state_log_list(
113
- task: AnyTask, session_state_log_list: SessionStateLogList
114
- ) -> SessionStateLogList:
120
+ task: AnyTask, session_state_log_list: "SessionStateLogList"
121
+ ) -> "SessionStateLogList":
122
+ from zrb.session_state_log.session_state_log import SessionStateLogList
123
+
115
124
  return SessionStateLogList(
116
125
  total=session_state_log_list.total,
117
126
  data=[
@@ -122,8 +131,8 @@ def sanitize_session_state_log_list(
122
131
 
123
132
 
124
133
  def sanitize_session_state_log(
125
- task: AnyTask, session_state_log: SessionStateLog
126
- ) -> SessionStateLog:
134
+ task: AnyTask, session_state_log: "SessionStateLog"
135
+ ) -> "SessionStateLog":
127
136
  """
128
137
  In session, we create snake_case aliases of inputs.
129
138
  The purpose was to increase ergonomics, so that user can use `input.system_prompt`
@@ -131,6 +140,8 @@ def sanitize_session_state_log(
131
140
  However, when we serve the session through HTTP API,
132
141
  we only want to show the original input names.
133
142
  """
143
+ from zrb.session_state_log.session_state_log import SessionStateLog
144
+
134
145
  enhanced_inputs = session_state_log.input
135
146
  real_inputs = {}
136
147
  for real_input in task.inputs:
@@ -5,13 +5,14 @@ from typing import TYPE_CHECKING, Any, Coroutine, TypeVar
5
5
 
6
6
  from zrb.context.any_context import AnyContext
7
7
  from zrb.group.any_group import AnyGroup
8
- from zrb.session_state_log.session_state_log import SessionStateLog
9
8
  from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
10
9
  from zrb.task_status.task_status import TaskStatus
11
10
 
12
11
  if TYPE_CHECKING:
13
- from zrb.context import any_shared_context
14
- from zrb.task import any_task
12
+ from zrb.context.any_shared_context import AnySharedContext
13
+ from zrb.session_state_log.session_state_log import SessionStateLog
14
+ from zrb.task.any_task import AnyTask
15
+
15
16
 
16
17
  TAnySession = TypeVar("TAnySession", bound="AnySession")
17
18
 
@@ -44,7 +45,7 @@ class AnySession(ABC):
44
45
 
45
46
  @property
46
47
  @abstractmethod
47
- def shared_ctx(self) -> any_shared_context.AnySharedContext:
48
+ def shared_ctx(self) -> "AnySharedContext":
48
49
  """Shared context for this session"""
49
50
  pass
50
51
 
@@ -83,16 +84,16 @@ class AnySession(ABC):
83
84
  pass
84
85
 
85
86
  @abstractmethod
86
- def set_main_task(self, main_task: any_task.AnyTask):
87
+ def set_main_task(self, main_task: "AnyTask"):
87
88
  """Set main task"""
88
89
  pass
89
90
 
90
91
  @abstractmethod
91
- def as_state_log(self) -> SessionStateLog:
92
+ def as_state_log(self) -> "SessionStateLog":
92
93
  pass
93
94
 
94
95
  @abstractmethod
95
- def get_ctx(self, task: any_task.AnyTask) -> AnyContext:
96
+ def get_ctx(self, task: "AnyTask") -> AnyContext:
96
97
  """Retrieves the context for a specific task.
97
98
 
98
99
  Args:
@@ -104,7 +105,7 @@ class AnySession(ABC):
104
105
  pass
105
106
 
106
107
  @abstractmethod
107
- def defer_monitoring(self, task: any_task.AnyTask, coro: Coroutine):
108
+ def defer_monitoring(self, task: "AnyTask", coro: Coroutine):
108
109
  """Defers the execution of a task's monitoring coroutine for later processing.
109
110
 
110
111
  Args:
@@ -114,7 +115,7 @@ class AnySession(ABC):
114
115
  pass
115
116
 
116
117
  @abstractmethod
117
- def defer_action(self, task: any_task.AnyTask, coro: Coroutine):
118
+ def defer_action(self, task: "AnyTask", coro: Coroutine):
118
119
  """Defers the execution of a task's coroutine for later processing.
119
120
 
120
121
  Args:
@@ -138,7 +139,7 @@ class AnySession(ABC):
138
139
  pass
139
140
 
140
141
  @abstractmethod
141
- def register_task(self, task: any_task.AnyTask):
142
+ def register_task(self, task: "AnyTask"):
142
143
  """Registers a new task in the session.
143
144
 
144
145
  Args:
@@ -147,7 +148,7 @@ class AnySession(ABC):
147
148
  pass
148
149
 
149
150
  @abstractmethod
150
- def get_root_tasks(self, task: any_task.AnyTask) -> list[any_task.AnyTask]:
151
+ def get_root_tasks(self, task: "AnyTask") -> list["AnyTask"]:
151
152
  """Retrieves the list of root tasks that should be executed first
152
153
  to run the given task.
153
154
 
@@ -160,7 +161,7 @@ class AnySession(ABC):
160
161
  pass
161
162
 
162
163
  @abstractmethod
163
- def get_next_tasks(self, task: any_task.AnyTask) -> list[any_task.AnyTask]:
164
+ def get_next_tasks(self, task: "AnyTask") -> list["AnyTask"]:
164
165
  """Retrieves the list of tasks that should be executed after the given task.
165
166
 
166
167
  Args:
@@ -172,7 +173,7 @@ class AnySession(ABC):
172
173
  pass
173
174
 
174
175
  @abstractmethod
175
- def get_task_status(self, task: any_task.AnyTask) -> TaskStatus:
176
+ def get_task_status(self, task: "AnyTask") -> TaskStatus:
176
177
  """Get tasks' status.
177
178
 
178
179
  Args:
@@ -184,7 +185,7 @@ class AnySession(ABC):
184
185
  pass
185
186
 
186
187
  @abstractmethod
187
- def is_allowed_to_run(self, task: any_task.AnyTask):
188
+ def is_allowed_to_run(self, task: "AnyTask"):
188
189
  """Determines if the specified task is allowed to run based on its current state.
189
190
 
190
191
  Args:
zrb/session/session.py CHANGED
@@ -1,15 +1,10 @@
1
1
  import asyncio
2
- from typing import Any, Coroutine
2
+ from typing import TYPE_CHECKING, Any, Coroutine
3
3
 
4
4
  from zrb.context.any_shared_context import AnySharedContext
5
5
  from zrb.context.context import AnyContext, Context
6
6
  from zrb.group.any_group import AnyGroup
7
7
  from zrb.session.any_session import AnySession
8
- from zrb.session_state_log.session_state_log import (
9
- SessionStateLog,
10
- TaskStatusHistoryStateLog,
11
- TaskStatusStateLog,
12
- )
13
8
  from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
14
9
  from zrb.session_state_logger.session_state_logger_factory import session_state_logger
15
10
  from zrb.task.any_task import AnyTask
@@ -32,6 +27,9 @@ from zrb.util.group import get_node_path
32
27
  from zrb.util.string.name import get_random_name
33
28
  from zrb.xcom.xcom import Xcom
34
29
 
30
+ if TYPE_CHECKING:
31
+ from zrb.session_state_log.session_state_log import SessionStateLog
32
+
35
33
 
36
34
  class Session(AnySession):
37
35
  def __init__(
@@ -139,7 +137,13 @@ class Session(AnySession):
139
137
  main_task_path = get_node_path(self._root_group, main_task)
140
138
  self._main_task_path = [] if main_task_path is None else main_task_path
141
139
 
142
- def as_state_log(self) -> SessionStateLog:
140
+ def as_state_log(self) -> "SessionStateLog":
141
+ from zrb.session_state_log.session_state_log import (
142
+ SessionStateLog,
143
+ TaskStatusHistoryStateLog,
144
+ TaskStatusStateLog,
145
+ )
146
+
143
147
  task_status_log: dict[str, TaskStatusStateLog] = {}
144
148
  log_start_time = ""
145
149
  for task, task_status in self._task_status.items():
@@ -1,16 +1,21 @@
1
1
  import datetime
2
2
  from abc import ABC, abstractmethod
3
+ from typing import TYPE_CHECKING
3
4
 
4
- from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
5
+ if TYPE_CHECKING:
6
+ from zrb.session_state_log.session_state_log import (
7
+ SessionStateLog,
8
+ SessionStateLogList,
9
+ )
5
10
 
6
11
 
7
12
  class AnySessionStateLogger(ABC):
8
13
  @abstractmethod
9
- def write(self, session_log: SessionStateLog):
14
+ def write(self, session_log: "SessionStateLog"):
10
15
  pass
11
16
 
12
17
  @abstractmethod
13
- def read(self, session_name: str) -> SessionStateLog:
18
+ def read(self, session_name: str) -> "SessionStateLog":
14
19
  pass
15
20
 
16
21
  @abstractmethod
@@ -21,5 +26,5 @@ class AnySessionStateLogger(ABC):
21
26
  max_start_time: datetime.datetime,
22
27
  page: int = 0,
23
28
  limit: int = 10,
24
- ) -> SessionStateLogList:
29
+ ) -> "SessionStateLogList":
25
30
  pass
@@ -1,16 +1,22 @@
1
1
  import datetime
2
2
  import os
3
+ from typing import TYPE_CHECKING
3
4
 
4
- from zrb.session_state_log.session_state_log import SessionStateLog, SessionStateLogList
5
5
  from zrb.session_state_logger.any_session_state_logger import AnySessionStateLogger
6
6
  from zrb.util.file import read_file, write_file
7
7
 
8
+ if TYPE_CHECKING:
9
+ from zrb.session_state_log.session_state_log import (
10
+ SessionStateLog,
11
+ SessionStateLogList,
12
+ )
13
+
8
14
 
9
15
  class FileSessionStateLogger(AnySessionStateLogger):
10
16
  def __init__(self, session_log_dir: str):
11
17
  self._session_log_dir = session_log_dir
12
18
 
13
- def write(self, session_log: SessionStateLog):
19
+ def write(self, session_log: "SessionStateLog"):
14
20
  session_file_path = self._get_session_file_path(session_log.name)
15
21
  session_dir_path = os.path.dirname(session_file_path)
16
22
  if not os.path.isdir(session_dir_path):
@@ -22,7 +28,9 @@ class FileSessionStateLogger(AnySessionStateLogger):
22
28
  timeline_dir_path = self._get_timeline_dir_path(session_log)
23
29
  write_file(os.path.join(timeline_dir_path, session_log.name), "")
24
30
 
25
- def read(self, session_name: str) -> SessionStateLog:
31
+ def read(self, session_name: str) -> "SessionStateLog":
32
+ from zrb.session_state_log.session_state_log import SessionStateLog
33
+
26
34
  session_file_path = self._get_session_file_path(session_name)
27
35
  return SessionStateLog.model_validate_json(read_file(session_file_path))
28
36
 
@@ -33,7 +41,9 @@ class FileSessionStateLogger(AnySessionStateLogger):
33
41
  max_start_time: datetime.datetime,
34
42
  page: int = 0,
35
43
  limit: int = 10,
36
- ) -> SessionStateLogList:
44
+ ) -> "SessionStateLogList":
45
+ from zrb.session_state_log.session_state_log import SessionStateLogList
46
+
37
47
  matching_sessions = []
38
48
  # Traverse the timeline directory and filter sessions
39
49
  timeline_dir = os.path.join(self._session_log_dir, "_timeline", *task_path)
@@ -62,7 +72,7 @@ class FileSessionStateLogger(AnySessionStateLogger):
62
72
  def _get_session_file_path(self, session_name: str) -> str:
63
73
  return os.path.join(self._session_log_dir, f"{session_name}.json")
64
74
 
65
- def _get_timeline_dir_path(self, session_log: SessionStateLog) -> str:
75
+ def _get_timeline_dir_path(self, session_log: "SessionStateLog") -> str:
66
76
  start_time = self._get_start_time(session_log)
67
77
  year = start_time.year
68
78
  month = start_time.month
@@ -80,7 +90,7 @@ class FileSessionStateLogger(AnySessionStateLogger):
80
90
  ]
81
91
  return os.path.join(self._session_log_dir, "_timeline", *paths)
82
92
 
83
- def _get_start_time(self, session_log: SessionStateLog) -> datetime.datetime:
93
+ def _get_start_time(self, session_log: "SessionStateLog") -> datetime.datetime:
84
94
  return datetime.datetime.strptime(
85
95
  session_log.start_time, "%Y-%m-%d %H:%M:%S.%f"
86
96
  )
zrb/task/any_task.py CHANGED
@@ -7,8 +7,11 @@ from zrb.env.any_env import AnyEnv
7
7
  from zrb.input.any_input import AnyInput
8
8
 
9
9
  if TYPE_CHECKING:
10
- from zrb.context import any_context
11
- from zrb.session import session
10
+ from zrb.context.any_context import AnyContext
11
+ from zrb.session.any_session import AnySession
12
+ else:
13
+ AnyContext = Any
14
+ AnySession = Any
12
15
 
13
16
 
14
17
  class AnyTask(ABC):
@@ -143,12 +146,12 @@ class AnyTask(ABC):
143
146
  pass
144
147
 
145
148
  @abstractmethod
146
- def get_ctx(self, session: session.AnySession) -> any_context.AnyContext:
149
+ def get_ctx(self, session: AnySession) -> AnyContext:
147
150
  pass
148
151
 
149
152
  @abstractmethod
150
153
  def run(
151
- self, session: session.AnySession | None = None, str_kwargs: dict[str, str] = {}
154
+ self, session: AnySession | None = None, str_kwargs: dict[str, str] = {}
152
155
  ) -> Any:
153
156
  """Runs the task synchronously.
154
157
 
@@ -163,7 +166,7 @@ class AnyTask(ABC):
163
166
 
164
167
  @abstractmethod
165
168
  async def async_run(
166
- self, session: session.AnySession | None = None, str_kwargs: dict[str, str] = {}
169
+ self, session: AnySession | None = None, str_kwargs: dict[str, str] = {}
167
170
  ) -> Any:
168
171
  """Runs the task asynchronously.
169
172
 
@@ -177,7 +180,7 @@ class AnyTask(ABC):
177
180
  pass
178
181
 
179
182
  @abstractmethod
180
- async def exec_root_tasks(self, session: session.AnySession):
183
+ async def exec_root_tasks(self, session: AnySession):
181
184
  """Execute the root tasks along with the downstreams until the current task
182
185
  is ready.
183
186
 
@@ -187,7 +190,7 @@ class AnyTask(ABC):
187
190
  pass
188
191
 
189
192
  @abstractmethod
190
- async def exec_chain(self, session: session.AnySession):
193
+ async def exec_chain(self, session: AnySession):
191
194
  """Execute the task along with the downstreams.
192
195
 
193
196
  Args:
@@ -196,7 +199,7 @@ class AnyTask(ABC):
196
199
  pass
197
200
 
198
201
  @abstractmethod
199
- async def exec(self, session: session.AnySession):
202
+ async def exec(self, session: AnySession):
200
203
  """Execute the task (without upstream or downstream).
201
204
 
202
205
  Args:
zrb/util/file.py CHANGED
@@ -31,9 +31,10 @@ def _read_text_file_content(file_path: str) -> str:
31
31
 
32
32
 
33
33
  def _read_pdf_file_content(file_path: str) -> str:
34
- import pdfplumber
34
+ from pdfplumber.pdf import PDF, open
35
35
 
36
- with pdfplumber.open(file_path) as pdf:
36
+ with open(file_path) as pdf:
37
+ pdf: PDF
37
38
  return "\n".join(
38
39
  page.extract_text() for page in pdf.pages if page.extract_text()
39
40
  )
zrb/util/todo.py CHANGED
@@ -1,8 +1,7 @@
1
1
  import datetime
2
2
  import re
3
3
  import shutil
4
-
5
- from pydantic import BaseModel, Field, model_validator
4
+ from typing import TYPE_CHECKING
6
5
 
7
6
  from zrb.util.cli.style import (
8
7
  stylize_bold_yellow,
@@ -14,6 +13,9 @@ from zrb.util.cli.style import (
14
13
  from zrb.util.file import read_file, write_file
15
14
  from zrb.util.string.name import get_random_name
16
15
 
16
+ if TYPE_CHECKING:
17
+ from zrb.util.todo_model import TodoTaskModel
18
+
17
19
  _DATE_TIME_STR_WIDTH = 14
18
20
  _MAX_DESCRIPTION_WIDTH = 70
19
21
  _PRIORITY_WIDTH = 3
@@ -23,43 +25,6 @@ _CREATED_AT_WIDTH = _DATE_TIME_STR_WIDTH
23
25
  _GAP_WIDTH = 2
24
26
 
25
27
 
26
- class TodoTaskModel(BaseModel):
27
- priority: str | None = Field("D", pattern=r"^[A-Z]$") # Priority like A, B, ...
28
- completed: bool = False # True if completed, False otherwise
29
- description: str # Main task description
30
- projects: list[str] = [] # List of projects (e.g., +Project)
31
- contexts: list[str] = [] # List of contexts (e.g., @Context)
32
- keyval: dict[str, str] = {} # Special key (e.g., due:2016-05-30)
33
- creation_date: datetime.date | None = None # Creation date
34
- completion_date: datetime.date | None = None # Completion date
35
-
36
- @model_validator(mode="before")
37
- def validate_dates(cls, values):
38
- completion_date = values.get("completion_date")
39
- creation_date = values.get("creation_date")
40
- if completion_date and not creation_date:
41
- raise ValueError(
42
- "creation_date must be specified if completion_date is set."
43
- )
44
- return values
45
-
46
- def get_additional_info_length(self):
47
- """
48
- Calculate the length of the additional information string (projects, contexts, keyval).
49
-
50
- Returns:
51
- int: The length of the combined additional information string.
52
- """
53
- results = []
54
- for project in self.projects:
55
- results.append(f"@{project}")
56
- for context in self.contexts:
57
- results.append(f"+{context}")
58
- for key, val in self.keyval.items():
59
- results.append(f"{key}:{val}")
60
- return len(", ".join(results))
61
-
62
-
63
28
  TODO_TXT_PATTERN = re.compile(
64
29
  r"^(?P<status>x)?\s*" # Optional completion mark ('x')
65
30
  r"(?:\((?P<priority>[A-Z])\)\s+)?" # Optional priority (e.g., '(A)')
@@ -69,7 +34,7 @@ TODO_TXT_PATTERN = re.compile(
69
34
  )
70
35
 
71
36
 
72
- def cascade_todo_task(todo_task: TodoTaskModel):
37
+ def cascade_todo_task(todo_task: "TodoTaskModel"):
73
38
  """
74
39
  Populate default values for a TodoTaskModel if they are missing.
75
40
 
@@ -87,8 +52,8 @@ def cascade_todo_task(todo_task: TodoTaskModel):
87
52
 
88
53
 
89
54
  def select_todo_task(
90
- todo_list: list[TodoTaskModel], keyword: str
91
- ) -> TodoTaskModel | None:
55
+ todo_list: list["TodoTaskModel"], keyword: str
56
+ ) -> "TodoTaskModel | None":
92
57
  """
93
58
  Select a todo task from a list based on a keyword matching ID or description.
94
59
 
@@ -118,7 +83,7 @@ def select_todo_task(
118
83
  return None
119
84
 
120
85
 
121
- def load_todo_list(todo_file_path: str) -> list[TodoTaskModel]:
86
+ def load_todo_list(todo_file_path: str) -> list["TodoTaskModel"]:
122
87
  """
123
88
  Load a list of todo tasks from a todo.txt file.
124
89
 
@@ -129,7 +94,7 @@ def load_todo_list(todo_file_path: str) -> list[TodoTaskModel]:
129
94
  list[TodoTaskModel]: A sorted list of todo tasks.
130
95
  """
131
96
  todo_lines = read_file(todo_file_path).strip().split("\n")
132
- todo_list: list[TodoTaskModel] = []
97
+ todo_list: list["TodoTaskModel"] = []
133
98
  for todo_line in todo_lines:
134
99
  todo_line = todo_line.strip()
135
100
  if todo_line == "":
@@ -147,7 +112,7 @@ def load_todo_list(todo_file_path: str) -> list[TodoTaskModel]:
147
112
  return todo_list
148
113
 
149
114
 
150
- def save_todo_list(todo_file_path: str, todo_list: list[TodoTaskModel]):
115
+ def save_todo_list(todo_file_path: str, todo_list: list["TodoTaskModel"]):
151
116
  """
152
117
  Save a list of todo tasks to a todo.txt file.
153
118
 
@@ -160,8 +125,10 @@ def save_todo_list(todo_file_path: str, todo_list: list[TodoTaskModel]):
160
125
  )
161
126
 
162
127
 
163
- def line_to_todo_task(line: str) -> TodoTaskModel:
128
+ def line_to_todo_task(line: str) -> "TodoTaskModel":
164
129
  """Parses a single todo.txt line into a TodoTask model."""
130
+ from zrb.util.todo_model import TodoTaskModel
131
+
165
132
  match = TODO_TXT_PATTERN.match(line)
166
133
  if not match:
167
134
  raise ValueError(f"Invalid todo.txt line: {line}")
@@ -214,7 +181,7 @@ def _parse_date(date_str: str | None) -> datetime.date | None:
214
181
  return None
215
182
 
216
183
 
217
- def todo_task_to_line(task: TodoTaskModel) -> str:
184
+ def todo_task_to_line(task: "TodoTaskModel") -> str:
218
185
  """
219
186
  Converts a TodoTask instance back into a todo.txt formatted line.
220
187
 
@@ -251,7 +218,7 @@ def todo_task_to_line(task: TodoTaskModel) -> str:
251
218
  return " ".join(parts)
252
219
 
253
220
 
254
- def get_visual_todo_list(todo_list: list[TodoTaskModel], filter: str) -> str:
221
+ def get_visual_todo_list(todo_list: list["TodoTaskModel"], filter: str) -> str:
255
222
  """
256
223
  Generate a visual representation of a filtered todo list.
257
224
 
@@ -352,7 +319,7 @@ def get_visual_todo_line(
352
319
  terminal_width: int,
353
320
  max_desc_length: int,
354
321
  max_additional_info_length: int,
355
- todo_task: TodoTaskModel,
322
+ todo_task: "TodoTaskModel",
356
323
  ) -> str:
357
324
  """
358
325
  Generate a single line string for a todo task in the visual todo list.
@@ -489,7 +456,7 @@ def _get_minimum_width(field_widths: list[int]) -> int:
489
456
 
490
457
 
491
458
  def get_visual_todo_card(
492
- todo_task: TodoTaskModel, log_work_list: list[dict[str, str]]
459
+ todo_task: "TodoTaskModel", log_work_list: list[dict[str, str]]
493
460
  ) -> str:
494
461
  """
495
462
  Generate a visual card representation of a todo task with log work.
zrb/util/todo_model.py ADDED
@@ -0,0 +1,40 @@
1
+ import datetime
2
+
3
+ from pydantic import BaseModel, Field, model_validator
4
+
5
+
6
+ class TodoTaskModel(BaseModel):
7
+ priority: str | None = Field("D", pattern=r"^[A-Z]$") # Priority like A, B, ...
8
+ completed: bool = False # True if completed, False otherwise
9
+ description: str # Main task description
10
+ projects: list[str] = [] # List of projects (e.g., +Project)
11
+ contexts: list[str] = [] # List of contexts (e.g., @Context)
12
+ keyval: dict[str, str] = {} # Special key (e.g., due:2016-05-30)
13
+ creation_date: datetime.date | None = None # Creation date
14
+ completion_date: datetime.date | None = None # Completion date
15
+
16
+ @model_validator(mode="before")
17
+ def validate_dates(cls, values):
18
+ completion_date = values.get("completion_date")
19
+ creation_date = values.get("creation_date")
20
+ if completion_date and not creation_date:
21
+ raise ValueError(
22
+ "creation_date must be specified if completion_date is set."
23
+ )
24
+ return values
25
+
26
+ def get_additional_info_length(self):
27
+ """
28
+ Calculate the length of the additional information string (projects, contexts, keyval).
29
+
30
+ Returns:
31
+ int: The length of the combined additional information string.
32
+ """
33
+ results = []
34
+ for project in self.projects:
35
+ results.append(f"@{project}")
36
+ for context in self.contexts:
37
+ results.append(f"+{context}")
38
+ for key, val in self.keyval.items():
39
+ results.append(f"{key}:{val}")
40
+ return len(", ".join(results))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zrb
3
- Version: 1.8.13
3
+ Version: 1.8.14
4
4
  Summary: Your Automation Powerhouse
5
5
  Home-page: https://github.com/state-alchemists/zrb
6
6
  License: AGPL-3.0-or-later
@@ -25,6 +25,7 @@ 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"
26
26
  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
+ Requires-Dist: prompt-toolkit (>=3.0.51,<4.0.0)
28
29
  Requires-Dist: psutil (>=7.0.0,<8.0.0)
29
30
  Requires-Dist: pydantic-ai (>=0.3.4,<0.4.0)
30
31
  Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
@@ -9,7 +9,7 @@ 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=Nfn_HXAKjKeIKWQt4nfS9k0VWmrg0JhexlJKVw58WLQ,6841
12
+ zrb/builtin/llm/chat_session.py,sha256=Nc7DDwxuKblwjtA9rCt82Gc2XSHsx3dxvxTGZyGXgtE,6991
13
13
  zrb/builtin/llm/history.py,sha256=cnkOyO43uiMQ9cEvmqk-pPoCk1zCAH_fwAqSgBtsjzY,3079
14
14
  zrb/builtin/llm/input.py,sha256=Nw-26uTWp2QhUgKJcP_IMHmtk-b542CCSQ_vCOjhvhM,877
15
15
  zrb/builtin/llm/llm_ask.py,sha256=QUV29gOAFKiMfJlAKbY9YfGPoxYv-4RPv6p7cWogK4U,4438
@@ -20,7 +20,7 @@ zrb/builtin/llm/tool/cli.py,sha256=_CNEmEc6K2Z0i9ppYeM7jGpqaEdT3uxaWQatmxP3jKE,8
20
20
  zrb/builtin/llm/tool/code.py,sha256=q6YrVJkRJg4AQpnK2KHE6AEMo8nMbRN4XUZ3QtMI_Og,8090
21
21
  zrb/builtin/llm/tool/file.py,sha256=ufLCAaHB0JkEAqQS4fbM9OaTfLluqlCuSyMmnYhI0rY,18491
22
22
  zrb/builtin/llm/tool/rag.py,sha256=yqx7vXXyrOCJjhQJl4s0TnLL-2uQUTuKRnkWlSQBW0M,7883
23
- zrb/builtin/llm/tool/sub_agent.py,sha256=GPHD8hLlIfme0h1Q0zzMUuAc2HiKl8CRqWGNcgE_H1Q,4764
23
+ zrb/builtin/llm/tool/sub_agent.py,sha256=Xz_nwNA8hW52gCeNdNBT7TXDUU3x7Ube-t17FYxx0-E,4671
24
24
  zrb/builtin/llm/tool/web.py,sha256=GYp6e_eaw-dj7MDpB4CP1fplUbfguuJawem9lPJM9TY,5481
25
25
  zrb/builtin/md5.py,sha256=690RV2LbW7wQeTFxY-lmmqTSVEEZv3XZbjEUW1Q3XpE,1480
26
26
  zrb/builtin/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -209,7 +209,7 @@ zrb/builtin/shell/autocomplete/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
209
209
  zrb/builtin/shell/autocomplete/bash.py,sha256=-7YDVV7txgJH9mAYSYN0jmvUEeDIzWFvVNY-cY0myF8,1181
210
210
  zrb/builtin/shell/autocomplete/subcmd.py,sha256=WZI6cGWJcn80zSyxOHG7sCMO3Ucix3mZf4xm_xyB_Y0,606
211
211
  zrb/builtin/shell/autocomplete/zsh.py,sha256=9hlq0Wt3fhRz326mAQTypEd4_4lZdrbBx_3A-Ti3mvw,1022
212
- zrb/builtin/todo.py,sha256=pDbDKp94VHy-JsOr1sFtY8K4nIpNr1v6siqs5ptypsg,11568
212
+ zrb/builtin/todo.py,sha256=1d_gKqGdgjbKDdMbFkehaGcm6cPDO89hOc3BjXund_E,11855
213
213
  zrb/builtin/uuid.py,sha256=lIdhSGzPQ1rixRzMXxQDcgFgV7W-gUduHIudZXlzZzg,5393
214
214
  zrb/callback/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
215
215
  zrb/callback/any_callback.py,sha256=PqEJYX_RigXEmoPniSeZusZBZSLWEoVIHvHk8MZ0Mvg,253
@@ -246,13 +246,13 @@ zrb/input/option_input.py,sha256=TQB82ko5odgzkULEizBZi0e9TIHEbIgvdP0AR3RhA74,213
246
246
  zrb/input/password_input.py,sha256=szBojWxSP9QJecgsgA87OIYwQrY2AQ3USIKdDZY6snU,1465
247
247
  zrb/input/str_input.py,sha256=NevZHX9rf1g8eMatPyy-kUX3DglrVAQpzvVpKAzf7bA,81
248
248
  zrb/input/text_input.py,sha256=6T3MngWdUs0u0ZVs5Dl11w5KS7nN1RkgrIR_zKumzPM,3695
249
- zrb/llm_config.py,sha256=PaOsd9i5rwq_Ry68T6tpgQ2sWdjq-SeCuw7XMaHxw7Q,17577
249
+ zrb/llm_config.py,sha256=dA6EucZCGuh6fq-JT1KVDLIs4ZQmqiv5Vl-auxjUd0U,17526
250
250
  zrb/llm_rate_limitter.py,sha256=uM9zmSgV10fQq1dlaDGLDrv72uLj6ldBxMoGjO2Az14,4429
251
251
  zrb/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
252
- zrb/runner/cli.py,sha256=AbLTNqFy5FuyGQOWOjHZGaBC8e2yuE_Dx1sBdnisR18,6984
252
+ zrb/runner/cli.py,sha256=y_n7O4kQKXpiLAsBsf1WnHNfWgKlrxE9TU0MU1ICUMg,6989
253
253
  zrb/runner/common_util.py,sha256=JDMcwvQ8cxnv9kQrAoKVLA40Q1omfv-u5_d5MvvwHeE,1373
254
254
  zrb/runner/web_app.py,sha256=L61fwHBKbG1BuoC8JASCUwoPYjBt2h90HtPQBpZALLs,2789
255
- zrb/runner/web_auth_config.py,sha256=g9C5ZFrYKlhJ4MqsA1uKsd9s3kN5sJiAN9QmGkRwBfc,6100
255
+ zrb/runner/web_auth_config.py,sha256=XAznxFk-CThhAJJIWAHhXFJC2ZH1aVIlrgYg2yjUAv4,6272
256
256
  zrb/runner/web_route/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
257
257
  zrb/runner/web_route/docs_route.py,sha256=Ftv4BbxnF_GZs2cJwen4hV7Z_UKQassFugB_bePdrPw,543
258
258
  zrb/runner/web_route/error_page/serve_default_404.py,sha256=srQSyOHoTZLScSvSUQnzUAVFOFSO_NQ2XEQZSvPd05c,1072
@@ -307,7 +307,7 @@ zrb/runner/web_route/static/resources/session/event.js,sha256=X5OlSHefK0SDB9VkFC
307
307
  zrb/runner/web_route/static/resources/session/past-session.js,sha256=RwGJYKSp75K8NZ-iZP58XppWgdzkiKFaiC5wgcMLxDo,5470
308
308
  zrb/runner/web_route/static/static_route.py,sha256=YRGKD7qiFuvciSRNewvo6oK0JLHQ_cK74eXWjffoQ70,1555
309
309
  zrb/runner/web_route/task_input_api_route.py,sha256=k5nQiJCL2ud6BhxaPGSbpK86XvMbsFliqTQ1FpEd-8Q,1767
310
- zrb/runner/web_route/task_session_api_route.py,sha256=YGMT8pN28XNVQ8StYm5xIiLH770XJhmKORHsqsfjnFY,6029
310
+ zrb/runner/web_route/task_session_api_route.py,sha256=CHbmcN-57FHixS-tVaxye5McMM3toHm8XcKFVmn1x6Y,6258
311
311
  zrb/runner/web_schema/session.py,sha256=NwbuS2Sv-CXO52nU-EZv8OMlD4vgCQWNeLC_dT0FK7I,92
312
312
  zrb/runner/web_schema/token.py,sha256=Y7XCPS4WzrxslTDtHeLcPTTUpmWhPOkRcl4b99zrC7c,185
313
313
  zrb/runner/web_schema/user.py,sha256=Kp10amg4i-f8Y-4czogv1YN7rwy0HdbePFiuovYu1ts,1018
@@ -316,16 +316,16 @@ zrb/runner/web_util/html.py,sha256=TuUHjX3eKCBzoa7TYdMt8dfWWy06idauyCaG66X4Ygc,1
316
316
  zrb/runner/web_util/token.py,sha256=6Yqp6mQJJMAOsSkAN-6dvtdiQbAv5xtll9jOmNYzbUY,2687
317
317
  zrb/runner/web_util/user.py,sha256=vE61pDjHoaHw9K0YAv1Gu2zWX2WkM2aWG-8776_aAiM,2061
318
318
  zrb/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
319
- zrb/session/any_session.py,sha256=x57mS15E-AfUjdVxwOWEzCBjW32zjer7WoeBw0guoDc,5266
320
- zrb/session/session.py,sha256=1COMZ1JDCpkiAHxSFcaFE71GmatZ4cCHmHbpUPvt8k0,10189
319
+ zrb/session/any_session.py,sha256=Z_R6lvg4exwAeDPH9nKRMwWJJTpgLCr8DVLs4MP53Rc,5204
320
+ zrb/session/session.py,sha256=kkaddqyRhT_7qXeGAjHT8cfrAu_1gS8g1DQdp8UmEsE,10338
321
321
  zrb/session_state_log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
322
322
  zrb/session_state_log/session_state_log.py,sha256=VVghDMU72PbrvnzQ7MJuc-KTJ5P5fX0FYuCh3Rlwd9M,709
323
323
  zrb/session_state_logger/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
324
- zrb/session_state_logger/any_session_state_logger.py,sha256=OEP7RQD6sPSJP0OY8oDKRZcoqQ9oKMOjBswanMj6OaE,610
325
- zrb/session_state_logger/file_session_state_logger.py,sha256=1ue7-Bcwg4wlLn2G_7ARR4Rij2zUISj_Y56VBQsCaMQ,3666
324
+ zrb/session_state_logger/any_session_state_logger.py,sha256=T_-aJv63HwoTeiDOmXKHp--eGl9MqAwgcLbiEPLhmDI,696
325
+ zrb/session_state_logger/file_session_state_logger.py,sha256=NMyj_g2ImQc6ZRM9f35EpA-CM1UO-ZgoDnPkN1DSi9U,3915
326
326
  zrb/session_state_logger/session_state_logger_factory.py,sha256=2Jvvp2zqK3qD0Gw-pm84LJ3d5uvkoBRh9MNHvw3r_DA,181
327
327
  zrb/task/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
328
- zrb/task/any_task.py,sha256=zklUjkLRQ62TEvfnOUUYfXChj8Zk4igee3w8V3_rN08,5846
328
+ zrb/task/any_task.py,sha256=J8mWytcoSw1RzMV2fkshOSc4bj2eiU6qXlv9wC0apjs,5860
329
329
  zrb/task/base/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
330
330
  zrb/task/base/context.py,sha256=73k3fKwup0AJwTTLpay0f_-axJextaxgbTem4w4Bmas,3670
331
331
  zrb/task/base/execution.py,sha256=scDLfNYBe8Bc8Ct1LCIKmFtjpPxm7FjqZ2bJXIQAzv8,11042
@@ -376,7 +376,7 @@ zrb/util/codemod/modify_function_call.py,sha256=wbyoRRsM4V9fPYkT5kHN0zpBetpRDq2S
376
376
  zrb/util/codemod/modify_method.py,sha256=5fioXjqNQmrf4CV2qlTZHpViF9PMnNer4FvuKam7byo,6344
377
377
  zrb/util/codemod/modify_module.py,sha256=2mzi_NxJ-kNFo5G0U_Rqb3JoYQl1s6Izt7b_wAl10F0,715
378
378
  zrb/util/cron.py,sha256=UWqqhhM7DDTPx6wjCIdBndnVh3NRu-sdKazp8aZkXh8,3833
379
- zrb/util/file.py,sha256=jygiPSXx2DqaUH5o9P6AKt2nyfynGfvH5mFfeIKrp_w,2754
379
+ zrb/util/file.py,sha256=RJosRqX63iwJ-TLx0yzJ4pJ97evKR-oxxs4r-v5chq0,2779
380
380
  zrb/util/git.py,sha256=gS_Y9sQgJbY0PfgSQiowLvV3Nf0y9C8nT3j6z6oEsG8,8186
381
381
  zrb/util/git_subtree.py,sha256=E_UB5OIgm8WkHL9beifRxpZ25_BB9p1H578OhLZTgRU,4611
382
382
  zrb/util/group.py,sha256=T82yr3qg9I5k10VPXkMyrIRIqyfzadSH813bqzwKEPI,4718
@@ -387,10 +387,11 @@ zrb/util/string/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
387
387
  zrb/util/string/conversion.py,sha256=sMmstzbrNgLvWAQukqoXz45JtsNpJrniudAtzJaQlYw,6240
388
388
  zrb/util/string/format.py,sha256=MwWGAwSdtOgR_2uz-JCXlg_q-uRYUUI-G8CGkfdgqik,1198
389
389
  zrb/util/string/name.py,sha256=SXEfxJ1-tDOzHqmSV8kvepRVyMqs2XdV_vyoh_9XUu0,1584
390
- zrb/util/todo.py,sha256=VGISej2KQZERpornK-8X7bysp4JydMrMUTnG8B0-liI,20708
390
+ zrb/util/todo.py,sha256=r9_KYF2-hLKMNjsp6AFK9zivykMrywd-kJ4bCwfdafI,19323
391
+ zrb/util/todo_model.py,sha256=0SJ8aLYfJAscDOk5JsH7pXP3h1rAG91VMCS20-c2Y6A,1576
391
392
  zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
392
393
  zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
393
- zrb-1.8.13.dist-info/METADATA,sha256=oqzBj3hnl1XlXUSSib6obfP_75DGHvZnJCIjZIx7tJ4,9274
394
- zrb-1.8.13.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
395
- zrb-1.8.13.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
396
- zrb-1.8.13.dist-info/RECORD,,
394
+ zrb-1.8.14.dist-info/METADATA,sha256=1kgNRHrwoU-WFaxuau8a70wUyazpwpIfoz4CZ9-4yUI,9322
395
+ zrb-1.8.14.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
396
+ zrb-1.8.14.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
397
+ zrb-1.8.14.dist-info/RECORD,,
File without changes