zrb 1.16.2__py3-none-any.whl → 1.16.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
zrb/builtin/__init__.py CHANGED
@@ -9,6 +9,7 @@ from zrb.builtin.git import (
9
9
  from zrb.builtin.git_subtree import git_add_subtree, git_pull_subtree, git_push_subtree
10
10
  from zrb.builtin.http import generate_curl, http_request
11
11
  from zrb.builtin.jwt import decode_jwt, encode_jwt, validate_jwt
12
+ from zrb.builtin.llm.chat_trigger import llm_chat_trigger
12
13
  from zrb.builtin.llm.llm_ask import llm_ask
13
14
  from zrb.builtin.md5 import hash_md5, sum_md5, validate_md5
14
15
  from zrb.builtin.project.add.fastapp.fastapp_task import add_fastapp_to_project
@@ -7,13 +7,20 @@ conversation flow via XCom.
7
7
 
8
8
  import asyncio
9
9
  import sys
10
+ from typing import TYPE_CHECKING, Any
10
11
 
12
+ from zrb.builtin.llm.chat_trigger import llm_chat_trigger
11
13
  from zrb.config.llm_config import llm_config
12
14
  from zrb.context.any_context import AnyContext
13
15
  from zrb.util.cli.markdown import render_markdown
14
16
  from zrb.util.cli.style import stylize_blue, stylize_bold_yellow, stylize_faint
15
17
  from zrb.util.string.conversion import to_boolean
16
18
 
19
+ if TYPE_CHECKING:
20
+ from asyncio import StreamReader
21
+
22
+ from prompt_toolkit import PromptSession
23
+
17
24
 
18
25
  async def read_user_prompt(ctx: AnyContext) -> str:
19
26
  """
@@ -22,7 +29,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
22
29
  """
23
30
  _show_info(ctx)
24
31
  is_tty: bool = ctx.is_tty
25
- reader = await _setup_input_reader(is_tty)
32
+ reader: PromptSession[Any] | StreamReader = await _setup_input_reader(is_tty)
26
33
  multiline_mode = False
27
34
  is_first_time = True
28
35
  current_modes: str = ctx.input.modes
@@ -32,7 +39,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
32
39
  while True:
33
40
  await asyncio.sleep(0.01)
34
41
  previous_session_name: str | None = (
35
- ctx.input.previous_session if is_first_time else None
42
+ ctx.input.previous_session if is_first_time else ""
36
43
  )
37
44
  start_new: bool = ctx.input.start_new if is_first_time else False
38
45
  if is_first_time and ctx.input.message.strip() != "":
@@ -41,7 +48,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
41
48
  # Get user input based on mode
42
49
  if not multiline_mode:
43
50
  ctx.print("💬 >>", plain=True)
44
- user_input = await _read_next_line(reader, ctx)
51
+ user_input = await llm_chat_trigger.wait(reader, ctx)
45
52
  if not multiline_mode:
46
53
  ctx.print("", plain=True)
47
54
  is_first_time = False
@@ -153,7 +160,9 @@ def _show_subcommand(command: str, description: str) -> str:
153
160
  return f" {styled_command} {styled_description}"
154
161
 
155
162
 
156
- async def _setup_input_reader(is_interactive: bool):
163
+ async def _setup_input_reader(
164
+ is_interactive: bool,
165
+ ) -> "PromptSession[Any] | StreamReader":
157
166
  """Sets up and returns the appropriate asynchronous input reader."""
158
167
  if is_interactive:
159
168
  from prompt_toolkit import PromptSession
@@ -167,22 +176,6 @@ async def _setup_input_reader(is_interactive: bool):
167
176
  return reader
168
177
 
169
178
 
170
- async def _read_next_line(reader, ctx: AnyContext) -> str:
171
- """Reads one line of input using the provided reader."""
172
- from prompt_toolkit import PromptSession
173
-
174
- if isinstance(reader, PromptSession):
175
- return await reader.prompt_async()
176
-
177
- line_bytes = await reader.readline()
178
- if not line_bytes:
179
- return "/bye" # Signal to exit
180
-
181
- user_input = line_bytes.decode().strip()
182
- ctx.print(user_input, plain=True)
183
- return user_input
184
-
185
-
186
179
  async def _trigger_ask_and_wait_for_result(
187
180
  ctx: AnyContext,
188
181
  user_prompt: str,
@@ -0,0 +1,73 @@
1
+ import asyncio
2
+ from asyncio import StreamReader
3
+ from typing import TYPE_CHECKING, Any, Callable, Coroutine
4
+
5
+ from zrb.context.any_context import AnyContext
6
+ from zrb.util.run import run_async
7
+
8
+ if TYPE_CHECKING:
9
+ from prompt_toolkit import PromptSession
10
+
11
+
12
+ ChatTrigger = Callable[[AnyContext], Coroutine[Any, Any, str] | str]
13
+
14
+
15
+ class LLMChatTrigger:
16
+
17
+ def __init__(self):
18
+ self._triggers: list[ChatTrigger] = []
19
+
20
+ def add_trigger(self, *trigger: ChatTrigger):
21
+ self.append_trigger(*trigger)
22
+
23
+ def append_trigger(self, *trigger: ChatTrigger):
24
+ for single_trigger in trigger:
25
+ self._triggers.append(single_trigger)
26
+
27
+ async def wait(
28
+ self, reader: "PromptSession[Any] | StreamReader", ctx: AnyContext
29
+ ) -> str:
30
+ trigger_tasks = [
31
+ asyncio.create_task(run_async(self._read_next_line(reader, ctx)))
32
+ ] + [asyncio.create_task(run_async(trigger(ctx))) for trigger in self._triggers]
33
+ final_result: str = ""
34
+ try:
35
+ done, pending = await asyncio.wait(
36
+ trigger_tasks, return_when=asyncio.FIRST_COMPLETED
37
+ )
38
+ for task in done:
39
+ final_result = await task
40
+ if pending:
41
+ for task in pending:
42
+ task.cancel()
43
+ for task in done:
44
+ break
45
+ except asyncio.CancelledError:
46
+ ctx.print("Task cancelled.", plain=True)
47
+ final_result = "/bye"
48
+ except KeyboardInterrupt:
49
+ ctx.print("KeyboardInterrupt detected. Exiting...", plain=True)
50
+ final_result = "/bye"
51
+ return final_result
52
+
53
+ async def _read_next_line(
54
+ self, reader: "PromptSession[Any] | StreamReader", ctx: AnyContext
55
+ ) -> str:
56
+ """Reads one line of input using the provided reader."""
57
+ from prompt_toolkit import PromptSession
58
+
59
+ try:
60
+ if isinstance(reader, PromptSession):
61
+ return await reader.prompt_async()
62
+ line_bytes = await reader.readline()
63
+ if not line_bytes:
64
+ return "/bye" # Signal to exit
65
+ user_input = line_bytes.decode().strip()
66
+ ctx.print(user_input, plain=True)
67
+ return user_input
68
+ except KeyboardInterrupt:
69
+ ctx.print("KeyboardInterrupt detected. Exiting...", plain=True)
70
+ return "/bye"
71
+
72
+
73
+ llm_chat_trigger = LLMChatTrigger()
@@ -106,7 +106,7 @@ def _render_yolo_mode_input(ctx: AnyContext) -> list[str] | bool | None:
106
106
  return elements
107
107
 
108
108
 
109
- def _get_inputs(require_message: bool = True) -> list[AnyInput]:
109
+ def _get_inputs(require_message: bool = True) -> list[AnyInput | None]:
110
110
  return [
111
111
  StrInput(
112
112
  "model",
@@ -120,6 +120,10 @@ async def analyze_repo(
120
120
  goal=goal,
121
121
  token_limit=extraction_token_threshold,
122
122
  )
123
+ if len(extracted_infos) == 0:
124
+ raise RuntimeError(
125
+ "No info can be extracted, adjust extensions or exclude_patterns."
126
+ )
123
127
  if len(extracted_infos) == 1:
124
128
  return extracted_infos[0]
125
129
  summarized_infos = extracted_infos
@@ -146,11 +150,11 @@ def _get_file_metadatas(
146
150
  if not any(file.endswith(f".{ext}") for ext in extensions):
147
151
  continue
148
152
  file_path = os.path.join(root, file)
149
- if is_excluded(file_path, exclude_patterns):
150
- continue
151
153
  try:
154
+ rel_path = os.path.relpath(file_path, dir_path)
155
+ if is_excluded(rel_path, exclude_patterns):
156
+ continue
152
157
  with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
153
- rel_path = os.path.relpath(file_path, dir_path)
154
158
  metadata_list.append({"path": rel_path, "content": f.read()})
155
159
  except Exception as e:
156
160
  print(f"Error reading file {file_path}: {e}")
@@ -1,4 +1,3 @@
1
- import json
2
1
  from collections.abc import Callable
3
2
  from textwrap import dedent
4
3
  from typing import TYPE_CHECKING, Any, Coroutine
@@ -9,7 +8,7 @@ from zrb.task.llm.config import get_model, get_model_settings
9
8
  from zrb.task.llm.prompt import get_system_and_user_prompt
10
9
 
11
10
  if TYPE_CHECKING:
12
- from pydantic_ai import Agent, Tool
11
+ from pydantic_ai import Tool
13
12
  from pydantic_ai.models import Model
14
13
  from pydantic_ai.settings import ModelSettings
15
14
  from pydantic_ai.toolsets import AbstractToolset
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: zrb
3
- Version: 1.16.2
3
+ Version: 1.16.3
4
4
  Summary: Your Automation Powerhouse
5
5
  License: AGPL-3.0-or-later
6
6
  Keywords: Automation,Task Runner,Code Generator,Monorepo,Low Code
@@ -2,25 +2,26 @@ zrb/__init__.py,sha256=qkCV2EnAGIgvsawBHYvKgPAp0zzPcikYSmbQXATLzg4,5060
2
2
  zrb/__main__.py,sha256=9SXH9MK4PVyU9lkEyHxiIUABbcsV2wseP94HmlqTR4M,2657
3
3
  zrb/attr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
4
  zrb/attr/type.py,sha256=4TV5gPYMMrKh5V-yB6iRYKCbsXAH_AvGXMsjxKLHcUs,568
5
- zrb/builtin/__init__.py,sha256=NjXpvBgAiPH-dNsJx5Fa-zSZE5JVnmVb1GhMNtevpGQ,1614
5
+ zrb/builtin/__init__.py,sha256=qeLg_S7mRWe48AYrzNutAgAnLh2YE57-iEVK0ICd-3A,1672
6
6
  zrb/builtin/base64.py,sha256=UjaFttE2oRx0T7_RpKtKfgMtWfiQXfJBAJmA16ek8Ic,1507
7
7
  zrb/builtin/git.py,sha256=8_qVE_2lVQEVXQ9vhiw8Tn4Prj1VZB78ZjEJJS5Ab3M,5461
8
8
  zrb/builtin/git_subtree.py,sha256=7BKwOkVTWDrR0DXXQ4iJyHqeR6sV5VYRt8y_rEB0EHg,3505
9
9
  zrb/builtin/group.py,sha256=zYC5uw0VE97TXiLCr464kFJ-CJIJyeQ2RXjnVRY5ovs,2577
10
10
  zrb/builtin/http.py,sha256=L6RE73c65wWwG5iHFN-tpOhyh56KsrgVskDd3c3YXtk,4246
11
11
  zrb/builtin/jwt.py,sha256=3M5uaQhJZbKQLjTUft1OwPz_JxtmK-xtkjxWjciOQho,2859
12
- zrb/builtin/llm/chat_session.py,sha256=DVPti3iR8bRDsmp6SvmktjXumiPk-PsOsv3AJjYHnoU,10629
12
+ zrb/builtin/llm/chat_session.py,sha256=6q40xQdv56OtaTZCVSS16WDchn4l0sagZI2BGX_JyQM,10448
13
+ zrb/builtin/llm/chat_trigger.py,sha256=xaJmzrvBGz6LFPOpYnG9bMeT1dY6XqZPXamtr9e72-w,2427
13
14
  zrb/builtin/llm/history.py,sha256=LDOrL0p7r_AHLa5L8Dp7bHNsOALugmJd7OguXRWGnm4,3087
14
15
  zrb/builtin/llm/input.py,sha256=Nw-26uTWp2QhUgKJcP_IMHmtk-b542CCSQ_vCOjhvhM,877
15
- zrb/builtin/llm/llm_ask.py,sha256=1gQea8lGAnIr5wSDXOZe3P_SMAUBQ-SIDrx1bwuml8k,7539
16
+ zrb/builtin/llm/llm_ask.py,sha256=8V5YAShUPes5qnlxLaS9Ks4KOs7oCQFGrpfkj-6rLMU,7546
16
17
  zrb/builtin/llm/previous-session.js,sha256=xMKZvJoAbrwiyHS0OoPrWuaKxWYLoyR5sguePIoCjTY,816
17
18
  zrb/builtin/llm/tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
19
  zrb/builtin/llm/tool/api.py,sha256=p55Fs6QTmsM2u-vVcBJb9xYxGAkiHIKX2wYKhsGlWFE,2417
19
20
  zrb/builtin/llm/tool/cli.py,sha256=sm_maE1WBB051odh1xXr8QQOWln_ewAU_7OScKAneT4,1244
20
- zrb/builtin/llm/tool/code.py,sha256=mtmXTDZTbUh6bEf4fsVPvfM0bokHMMETDWAHOXRmRmI,8798
21
+ zrb/builtin/llm/tool/code.py,sha256=-MKUpXX4jkWm4rCqrUmTTzsYhjfzKle9_XsNPtq8PNM,8952
21
22
  zrb/builtin/llm/tool/file.py,sha256=fDgt31CWwZtOYOk6lfBSBxX85NARLr-ZzXPvG1JP8C0,23589
22
23
  zrb/builtin/llm/tool/rag.py,sha256=aN8D8ZqzGXWCP_1F1LbN0QgfyzaK9CKrjfTPorDIYjw,9824
23
- zrb/builtin/llm/tool/sub_agent.py,sha256=5J2Ohjc-o1DZsU21DNHubkyc_3twIU8qPBLae8VWjkk,5086
24
+ zrb/builtin/llm/tool/sub_agent.py,sha256=nYluPfc8FlSobpP_4vnBIqkPARrDHq_SwKkmlh_ATUI,5067
24
25
  zrb/builtin/llm/tool/web.py,sha256=zDgxYRIQRj9A8QXb80-ZSPmGCvIOWy8bpJMGSAuTL8Y,7491
25
26
  zrb/builtin/md5.py,sha256=690RV2LbW7wQeTFxY-lmmqTSVEEZv3XZbjEUW1Q3XpE,1480
26
27
  zrb/builtin/project/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -410,7 +411,7 @@ zrb/util/todo_model.py,sha256=hhzAX-uFl5rsg7iVX1ULlJOfBtblwQ_ieNUxBWfc-Os,1670
410
411
  zrb/util/truncate.py,sha256=eSzmjBpc1Qod3lM3M73snNbDOcARHukW_tq36dWdPvc,921
411
412
  zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
412
413
  zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
413
- zrb-1.16.2.dist-info/METADATA,sha256=6fqvlgzoSAT-9VVwy0e3dCXDw_3ygkgPNNqfXmcmGoA,9935
414
- zrb-1.16.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
415
- zrb-1.16.2.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
416
- zrb-1.16.2.dist-info/RECORD,,
414
+ zrb-1.16.3.dist-info/METADATA,sha256=XONEHMCkv5j0YPf35oaP5MYliI1CYXoPXUv-8FNKFI4,9935
415
+ zrb-1.16.3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
416
+ zrb-1.16.3.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
417
+ zrb-1.16.3.dist-info/RECORD,,
File without changes