zrb 1.9.1__py3-none-any.whl → 1.9.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.
@@ -29,7 +29,7 @@ async def read_user_prompt(ctx: AnyContext) -> str:
29
29
 
30
30
  _show_info(ctx)
31
31
  final_result = ""
32
- ctx.print(stylize_faint("💬"), plain=True)
32
+ ctx.print("💬 >>", plain=True)
33
33
  ctx.print(ctx.input.message, plain=True)
34
34
  ctx.print("", plain=True)
35
35
  result = await _trigger_ask_and_wait_for_result(
@@ -49,12 +49,12 @@ async def read_user_prompt(ctx: AnyContext) -> str:
49
49
  while True:
50
50
  await asyncio.sleep(0.01)
51
51
  if not multiline_mode:
52
- ctx.print(stylize_faint("💬"), plain=True)
52
+ ctx.print("💬 >>", plain=True)
53
53
  user_input = await user_input_session.prompt_async()
54
54
  if not multiline_mode:
55
55
  ctx.print("", plain=True)
56
56
  # Handle special input
57
- if user_input.strip().lower() in ("/bye", "/quit"):
57
+ if user_input.strip().lower() in ("/bye", "/quit", "/q", "/exit"):
58
58
  user_prompt = "\n".join(user_inputs)
59
59
  user_inputs = []
60
60
  result = await _trigger_ask_and_wait_for_result(ctx, user_prompt)
@@ -108,12 +108,27 @@ async def _trigger_ask_and_wait_for_result(
108
108
  return None
109
109
  await _trigger_ask(ctx, user_prompt, previous_session_name, start_new)
110
110
  result = await _wait_ask_result(ctx)
111
- ctx.print(stylize_faint("\n🤖"), plain=True)
112
- ctx.print(result, plain=True)
111
+ md_result = _render_markdown(result) if result is not None else ""
112
+ ctx.print("\n🤖 >>", plain=True)
113
+ ctx.print(md_result, plain=True)
113
114
  ctx.print("", plain=True)
114
115
  return result
115
116
 
116
117
 
118
+ def _render_markdown(markdown_text: str) -> str:
119
+ """
120
+ Renders Markdown to a string, ensuring link URLs are visible.
121
+ """
122
+ from rich.console import Console
123
+ from rich.markdown import Markdown
124
+
125
+ console = Console()
126
+ markdown = Markdown(markdown_text, hyperlinks=False)
127
+ with console.capture() as capture:
128
+ console.print(markdown)
129
+ return capture.get()
130
+
131
+
117
132
  def get_llm_ask_input_mapping(callback_ctx: AnyContext):
118
133
  """
119
134
  Generates the input mapping for the LLM ask task from the callback context.
@@ -415,6 +415,7 @@ def apply_diff(
415
415
  replace_content: str,
416
416
  ) -> str:
417
417
  """Apply a precise search/replace to a file based on line numbers and content.
418
+ This tool enables you to update certain part of the file efficiently.
418
419
  Args:
419
420
  path (str): Path to modify. Pass exactly as provided, including '~'.
420
421
  start_line (int): The 1-based starting line number of the content to replace.
zrb/llm_config.py CHANGED
@@ -9,32 +9,42 @@ if TYPE_CHECKING:
9
9
 
10
10
 
11
11
  DEFAULT_PERSONA = (
12
- "You are a helpful and precise expert assistant. Your goal is to follow "
13
- "instructions carefully to provide accurate and efficient help. Get "
14
- "straight to the point."
12
+ "You are a helpful and precise expert assistant. Your primary goal is to "
13
+ "assist the user by proactively using your available tools to find "
14
+ "information, execute tasks, and solve problems. Always be accurate, "
15
+ "efficient, and get straight to the point."
15
16
  ).strip()
16
17
 
17
18
  DEFAULT_INTERACTIVE_SYSTEM_PROMPT = (
18
19
  "This is an interactive session. To assist the user, you MUST follow "
19
20
  "this core workflow:\n\n"
20
21
  "# Core Interactive Workflow\n"
21
- "1. **Clarify:** If the user's request is ambiguous, ask clarifying "
22
- "questions to ensure you fully understand their goal.\n"
23
- "2. **Plan:** For any non-trivial task, briefly outline your plan to the "
22
+ "1. **Understand:** First, understand the user's request. If you "
23
+ "encounter any concept, term, or topic you are unfamiliar with, you MUST "
24
+ "use your tools to search for information before proceeding. Do not "
25
+ "apologize for not knowing something; find the answer.\n"
26
+ "2. **Clarify:** If the user's request is ambiguous after your initial "
27
+ "research, ask clarifying questions to ensure you fully understand their "
28
+ "goal.\n"
29
+ "3. **Plan:** For any non-trivial task, briefly outline your plan to the "
24
30
  "user before you begin.\n"
25
- "3. **Execute:** Carry out the plan, using your available tools as "
31
+ "4. **Execute:** Carry out the plan, using your available tools as "
26
32
  "needed.\n"
27
- "4. **Confirm:** Before performing any significant or irreversible "
33
+ "5. **Confirm:** Before performing any significant or irreversible "
28
34
  "action (e.g., modifying files, committing code), state your intention "
29
35
  "and ask for the user's confirmation to proceed."
30
36
  ).strip()
31
37
 
32
38
  DEFAULT_SYSTEM_PROMPT = (
33
39
  "To fulfill this one-shot request, follow this simple process:\n"
34
- "1. **Analyze:** Deconstruct the user's request.\n"
35
- "2. **Execute:** Fulfill the request directly and concisely, using tools "
36
- "if necessary.\n"
37
- "3. **Answer:** Provide a clear and accurate answer."
40
+ "1. **Analyze and Research:** Deconstruct the user's request. If you "
41
+ "encounter any concept, term, or topic you are unfamiliar with, you MUST "
42
+ "use your tools to search for information. Do not state you don't know "
43
+ "something without trying to find out first.\n"
44
+ "2. **Execute:** Fulfill the request directly and concisely, using your "
45
+ "tools to perform actions and gather any final, necessary information.\n"
46
+ "3. **Answer:** Provide a clear, accurate, and well-informed answer "
47
+ "based on your research and execution."
38
48
  ).strip()
39
49
 
40
50
  DEFAULT_SPECIAL_INSTRUCTION_PROMPT = (
@@ -87,8 +97,10 @@ DEFAULT_SUMMARIZATION_PROMPT = (
87
97
  "`Previous Summary`.\n"
88
98
  "1. Update the `Narrative Summary` to include the key events from the "
89
99
  "new conversation turns.\n"
90
- "2. Replace the `Recent History` with the last 4 turns of the *new* "
91
- "conversation.\n\n"
100
+ "2. Replace the `Recent History` with the most recent turns from the *new* "
101
+ "conversation. It is critical to include the user's very last message "
102
+ "and assistant's very last response, ensuring the end of the conversation is "
103
+ "not truncated.\n\n"
92
104
  "### 3. Output Specification\n"
93
105
  "Your entire output MUST be a single block of text containing the "
94
106
  "following two sections in this exact order:\n"
@@ -18,23 +18,18 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
18
18
  )
19
19
 
20
20
  if Agent.is_user_prompt_node(node):
21
- # A user prompt node => The user has provided input
22
- print_func(stylize_faint(f" >> UserPromptNode: {node.user_prompt}"))
21
+ print_func(stylize_faint("🔠 Receiving input..."))
23
22
  elif Agent.is_model_request_node(node):
24
23
  # A model request node => We can stream tokens from the model's request
25
- print_func(
26
- stylize_faint(" >> ModelRequestNode: streaming partial request tokens")
27
- )
24
+ print_func(stylize_faint("🧠 Processing..."))
28
25
  async with node.stream(agent_run.ctx) as request_stream:
29
26
  is_streaming = False
30
27
  async for event in request_stream:
31
- if isinstance(event, PartStartEvent):
28
+ if isinstance(event, PartStartEvent) and event.part:
32
29
  if is_streaming:
33
30
  print_func("")
34
31
  print_func(
35
- stylize_faint(
36
- f" [Request] Starting part {event.index}: {event.part!r}"
37
- ),
32
+ stylize_faint(f" Starting part {event.index}: {event.part}"),
38
33
  )
39
34
  is_streaming = False
40
35
  elif isinstance(event, PartDeltaEvent):
@@ -49,22 +44,18 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
49
44
  end="",
50
45
  )
51
46
  is_streaming = True
52
- elif isinstance(event, FinalResultEvent):
47
+ elif isinstance(event, FinalResultEvent) and event.tool_name:
53
48
  if is_streaming:
54
49
  print_func("")
55
50
  print_func(
56
- stylize_faint(f" [Result] tool_name={event.tool_name}"),
51
+ stylize_faint(f" Result: tool_name={event.tool_name}"),
57
52
  )
58
53
  is_streaming = False
59
54
  if is_streaming:
60
55
  print_func("")
61
56
  elif Agent.is_call_tools_node(node):
62
57
  # A handle-response node => The model returned some data, potentially calls a tool
63
- print_func(
64
- stylize_faint(
65
- " >> CallToolsNode: streaming partial response & tool usage"
66
- )
67
- )
58
+ print_func(stylize_faint("🧰 Calling Tool..."))
68
59
  async with node.stream(agent_run.ctx) as handle_stream:
69
60
  async for event in handle_stream:
70
61
  if isinstance(event, FunctionToolCallEvent):
@@ -84,16 +75,16 @@ async def print_node(print_func: Callable, agent_run: Any, node: Any):
84
75
  del event.part.args["_dummy"]
85
76
  print_func(
86
77
  stylize_faint(
87
- f" [Tools] The LLM calls tool={event.part.tool_name!r} with args={event.part.args} (tool_call_id={event.part.tool_call_id!r})" # noqa
78
+ f" {event.part.tool_call_id} | "
79
+ f"Call {event.part.tool_name} {event.part.args}"
88
80
  )
89
81
  )
90
82
  elif isinstance(event, FunctionToolResultEvent):
91
83
  print_func(
92
84
  stylize_faint(
93
- f" [Tools] Tool call {event.tool_call_id!r} returned => {event.result.content}" # noqa
85
+ f" {event.tool_call_id} | {event.result.content}"
94
86
  )
95
87
  )
96
88
  elif Agent.is_end_node(node):
97
89
  # Once an End node is reached, the agent run is complete
98
- print_func(stylize_faint(" [End of Response]"))
99
- # print_func(stylize_faint(f"{agent_run.result.data}"))
90
+ print_func(stylize_faint(" Completed..."))
zrb/task/llm_task.py CHANGED
@@ -356,7 +356,7 @@ class LLMTask(BaseTask):
356
356
  ctx.xcom[xcom_usage_key] = Xcom([])
357
357
  usage = agent_run.result.usage()
358
358
  ctx.xcom[xcom_usage_key].push(usage)
359
- ctx.print(stylize_faint(f" Token: {usage}"), plain=True)
359
+ ctx.print(stylize_faint(f"💸 Token: {usage}"), plain=True)
360
360
  return agent_run.result.output
361
361
  else:
362
362
  ctx.log_warning("Agent run did not produce a result.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: zrb
3
- Version: 1.9.1
3
+ Version: 1.9.3
4
4
  Summary: Your Automation Powerhouse
5
5
  Home-page: https://github.com/state-alchemists/zrb
6
6
  License: AGPL-3.0-or-later
@@ -32,6 +32,7 @@ Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
32
32
  Requires-Dist: python-dotenv (>=1.1.1,<2.0.0)
33
33
  Requires-Dist: python-jose[cryptography] (>=3.4.0,<4.0.0)
34
34
  Requires-Dist: requests (>=2.32.4,<3.0.0)
35
+ Requires-Dist: rich (>=14.0.0,<15.0.0)
35
36
  Requires-Dist: tiktoken (>=0.8.0,<0.9.0)
36
37
  Requires-Dist: ulid-py (>=1.1.0,<2.0.0)
37
38
  Project-URL: Documentation, https://github.com/state-alchemists/zrb
@@ -91,6 +92,7 @@ This guide shows you how to define two simple tasks:
91
92
  - And another one to convert that script into a PNG image.
92
93
 
93
94
  > **Note:** This assume you have an `OPENAI_API_KEY` and a Mermaid CLI installed (i.e., `npm install -g @mermaid-js/mermaid-cli`)
95
+ > If you want to use other LLM Provider (e.g., Deepseek, Ollama, etc.), you can refer to [Zrb LLM Integration guide](https://github.com/state-alchemists/zrb/blob/main/docs/installation-and-configuration/configuration/llm-integration.md)
94
96
 
95
97
  ## 1. Create Your Task Definition File
96
98
 
@@ -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=iDNHbNX268NWl0uQmjecD3Bn686-mByqqXuMc6IKjOE,7146
12
+ zrb/builtin/llm/chat_session.py,sha256=S7IIY1ZGiNI0jfg1LhFZBKM9edHutiQws_WgwNXzZZ4,7586
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=A7MmDybKSdlO0T-Wted9t1tEtw6ULjV5aG4SAwpkt-w,4532
@@ -18,7 +18,7 @@ zrb/builtin/llm/tool/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
18
18
  zrb/builtin/llm/tool/api.py,sha256=yR9I0ZsI96OeQl9pgwORMASVuXsAL0a89D_iPS4C8Dc,1699
19
19
  zrb/builtin/llm/tool/cli.py,sha256=_CNEmEc6K2Z0i9ppYeM7jGpqaEdT3uxaWQatmxP3jKE,858
20
20
  zrb/builtin/llm/tool/code.py,sha256=t_0-D1ToSm3ATYGiHfkHBpvkRGMnrmwWSYk_M73AVXs,8090
21
- zrb/builtin/llm/tool/file.py,sha256=z0_RihenF09WtJqAoKLMeVmkqTS7Z5W04lwkKbyfESo,22683
21
+ zrb/builtin/llm/tool/file.py,sha256=OFmQYh2m27mgCLwlbKDxNOhp6qkoOtslT3fsso-PMPU,22757
22
22
  zrb/builtin/llm/tool/rag.py,sha256=yqx7vXXyrOCJjhQJl4s0TnLL-2uQUTuKRnkWlSQBW0M,7883
23
23
  zrb/builtin/llm/tool/sub_agent.py,sha256=Xz_nwNA8hW52gCeNdNBT7TXDUU3x7Ube-t17FYxx0-E,4671
24
24
  zrb/builtin/llm/tool/web.py,sha256=SeTT59yRaBJQILi4TETaLDMna2ooeYStYMkAnn0uTZc,5465
@@ -246,7 +246,7 @@ 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=FaX_v_EeZoXoZtwFpjqpvPHkxyaeqAziwcu-zb8lGXM,17144
249
+ zrb/llm_config.py,sha256=Cjfce8Idov3D9gFeU44ycpWjgd4uEeOjw7Zmn6IGTxk,18069
250
250
  zrb/llm_rate_limitter.py,sha256=uM9zmSgV10fQq1dlaDGLDrv72uLj6ldBxMoGjO2Az14,4429
251
251
  zrb/runner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
252
252
  zrb/runner/cli.py,sha256=y_n7O4kQKXpiLAsBsf1WnHNfWgKlrxE9TU0MU1ICUMg,6989
@@ -344,11 +344,11 @@ zrb/task/llm/context_enrichment.py,sha256=MBs5lkI1GFZwtW_P7fJfIc6CWcAS0UWQeBO6gg
344
344
  zrb/task/llm/error.py,sha256=s5PSK3ibGupMzOM0P81nstHWrMr3205H0FSDwfhWUDA,3662
345
345
  zrb/task/llm/history.py,sha256=cpaNqoEzsNAgzZGPPdohA8U5nTrVWmZ3P1Y5RTtXDgc,7986
346
346
  zrb/task/llm/history_summarization.py,sha256=TejPLktJmlxvhM-UmC29m_g6U9bC5e4fxRSEwt22GN0,6032
347
- zrb/task/llm/print_node.py,sha256=VB_ZXD3iQPZcaNWvIMNRxOhmXIJp9__5utRrSbiIRXo,4457
347
+ zrb/task/llm/print_node.py,sha256=zocTKi9gZDxl2I6KNu095TmMc13Yip6SNuWYnswS680,4060
348
348
  zrb/task/llm/prompt.py,sha256=obSsLHF4AHlwMIEQ8XTJmtEnkLlD5XTEkk0RJUmIz4Y,3410
349
349
  zrb/task/llm/tool_wrapper.py,sha256=8_bL8m_WpRf-pVKSrvQIVqT-m2sUA87a1RBQG13lhp4,6457
350
350
  zrb/task/llm/typing.py,sha256=c8VAuPBw_4A3DxfYdydkgedaP-LU61W9_wj3m3CAX1E,58
351
- zrb/task/llm_task.py,sha256=qNXS078y2s6iF50OoVH3-7UWmV5phgfY2_NiZ9KxGSU,21055
351
+ zrb/task/llm_task.py,sha256=EYU3TYhLrMu3nI2h-hid1vbfqpemYg54uht_Q8H8JBo,21056
352
352
  zrb/task/make_task.py,sha256=PD3b_aYazthS8LHeJsLAhwKDEgdurQZpymJDKeN60u0,2265
353
353
  zrb/task/rsync_task.py,sha256=GSL9144bmp6F0EckT6m-2a1xG25AzrrWYzH4k3SVUKM,6370
354
354
  zrb/task/scaffolder.py,sha256=rME18w1HJUHXgi9eTYXx_T2G4JdqDYzBoNOkdOOo5-o,6806
@@ -391,7 +391,7 @@ zrb/util/todo.py,sha256=r9_KYF2-hLKMNjsp6AFK9zivykMrywd-kJ4bCwfdafI,19323
391
391
  zrb/util/todo_model.py,sha256=0SJ8aLYfJAscDOk5JsH7pXP3h1rAG91VMCS20-c2Y6A,1576
392
392
  zrb/xcom/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
393
393
  zrb/xcom/xcom.py,sha256=o79rxR9wphnShrcIushA0Qt71d_p3ZTxjNf7x9hJB78,1571
394
- zrb-1.9.1.dist-info/METADATA,sha256=ohOmILh0PYQYiYzfuNy3dfuqNT7UorikVrHQO5jIE8I,9321
395
- zrb-1.9.1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
396
- zrb-1.9.1.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
397
- zrb-1.9.1.dist-info/RECORD,,
394
+ zrb-1.9.3.dist-info/METADATA,sha256=kFpbPlQwRBKBcKMQgRCnMuqvj2tamyF7j_qJIRYaOUo,9597
395
+ zrb-1.9.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
396
+ zrb-1.9.3.dist-info/entry_points.txt,sha256=-Pg3ElWPfnaSM-XvXqCxEAa-wfVI6BEgcs386s8C8v8,46
397
+ zrb-1.9.3.dist-info/RECORD,,
File without changes