zrb 1.15.3__py3-none-any.whl → 2.0.0a4__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 (204) hide show
  1. zrb/__init__.py +118 -133
  2. zrb/attr/type.py +10 -7
  3. zrb/builtin/__init__.py +55 -1
  4. zrb/builtin/git.py +12 -1
  5. zrb/builtin/group.py +31 -15
  6. zrb/builtin/llm/chat.py +147 -0
  7. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  8. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  9. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  10. zrb/builtin/searxng/config/settings.yml +5671 -0
  11. zrb/builtin/searxng/start.py +21 -0
  12. zrb/builtin/shell/autocomplete/bash.py +4 -3
  13. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  14. zrb/callback/callback.py +8 -1
  15. zrb/cmd/cmd_result.py +2 -1
  16. zrb/config/config.py +555 -169
  17. zrb/config/helper.py +84 -0
  18. zrb/config/web_auth_config.py +50 -35
  19. zrb/context/any_shared_context.py +20 -3
  20. zrb/context/context.py +39 -5
  21. zrb/context/print_fn.py +13 -0
  22. zrb/context/shared_context.py +17 -8
  23. zrb/group/any_group.py +3 -3
  24. zrb/group/group.py +3 -3
  25. zrb/input/any_input.py +5 -1
  26. zrb/input/base_input.py +18 -6
  27. zrb/input/option_input.py +41 -1
  28. zrb/input/text_input.py +7 -24
  29. zrb/llm/agent/__init__.py +9 -0
  30. zrb/llm/agent/agent.py +215 -0
  31. zrb/llm/agent/summarizer.py +20 -0
  32. zrb/llm/app/__init__.py +10 -0
  33. zrb/llm/app/completion.py +281 -0
  34. zrb/llm/app/confirmation/allow_tool.py +66 -0
  35. zrb/llm/app/confirmation/handler.py +178 -0
  36. zrb/llm/app/confirmation/replace_confirmation.py +77 -0
  37. zrb/llm/app/keybinding.py +34 -0
  38. zrb/llm/app/layout.py +117 -0
  39. zrb/llm/app/lexer.py +155 -0
  40. zrb/llm/app/redirection.py +28 -0
  41. zrb/llm/app/style.py +16 -0
  42. zrb/llm/app/ui.py +733 -0
  43. zrb/llm/config/__init__.py +4 -0
  44. zrb/llm/config/config.py +122 -0
  45. zrb/llm/config/limiter.py +247 -0
  46. zrb/llm/history_manager/__init__.py +4 -0
  47. zrb/llm/history_manager/any_history_manager.py +23 -0
  48. zrb/llm/history_manager/file_history_manager.py +91 -0
  49. zrb/llm/history_processor/summarizer.py +108 -0
  50. zrb/llm/note/__init__.py +3 -0
  51. zrb/llm/note/manager.py +122 -0
  52. zrb/llm/prompt/__init__.py +29 -0
  53. zrb/llm/prompt/claude_compatibility.py +92 -0
  54. zrb/llm/prompt/compose.py +55 -0
  55. zrb/llm/prompt/default.py +51 -0
  56. zrb/llm/prompt/markdown/file_extractor.md +112 -0
  57. zrb/llm/prompt/markdown/mandate.md +23 -0
  58. zrb/llm/prompt/markdown/persona.md +3 -0
  59. zrb/llm/prompt/markdown/repo_extractor.md +112 -0
  60. zrb/llm/prompt/markdown/repo_summarizer.md +29 -0
  61. zrb/llm/prompt/markdown/summarizer.md +21 -0
  62. zrb/llm/prompt/note.py +41 -0
  63. zrb/llm/prompt/system_context.py +46 -0
  64. zrb/llm/prompt/zrb.py +41 -0
  65. zrb/llm/skill/__init__.py +3 -0
  66. zrb/llm/skill/manager.py +86 -0
  67. zrb/llm/task/__init__.py +4 -0
  68. zrb/llm/task/llm_chat_task.py +316 -0
  69. zrb/llm/task/llm_task.py +245 -0
  70. zrb/llm/tool/__init__.py +39 -0
  71. zrb/llm/tool/bash.py +75 -0
  72. zrb/llm/tool/code.py +266 -0
  73. zrb/llm/tool/file.py +419 -0
  74. zrb/llm/tool/note.py +70 -0
  75. zrb/{builtin/llm → llm}/tool/rag.py +33 -37
  76. zrb/llm/tool/search/brave.py +53 -0
  77. zrb/llm/tool/search/searxng.py +47 -0
  78. zrb/llm/tool/search/serpapi.py +47 -0
  79. zrb/llm/tool/skill.py +19 -0
  80. zrb/llm/tool/sub_agent.py +70 -0
  81. zrb/llm/tool/web.py +97 -0
  82. zrb/llm/tool/zrb_task.py +66 -0
  83. zrb/llm/util/attachment.py +101 -0
  84. zrb/llm/util/prompt.py +104 -0
  85. zrb/llm/util/stream_response.py +178 -0
  86. zrb/runner/cli.py +21 -20
  87. zrb/runner/common_util.py +24 -19
  88. zrb/runner/web_route/task_input_api_route.py +5 -5
  89. zrb/runner/web_util/user.py +7 -3
  90. zrb/session/any_session.py +12 -9
  91. zrb/session/session.py +38 -17
  92. zrb/task/any_task.py +24 -3
  93. zrb/task/base/context.py +42 -22
  94. zrb/task/base/execution.py +67 -55
  95. zrb/task/base/lifecycle.py +14 -7
  96. zrb/task/base/monitoring.py +12 -7
  97. zrb/task/base_task.py +113 -50
  98. zrb/task/base_trigger.py +16 -6
  99. zrb/task/cmd_task.py +6 -0
  100. zrb/task/http_check.py +11 -5
  101. zrb/task/make_task.py +5 -3
  102. zrb/task/rsync_task.py +30 -10
  103. zrb/task/scaffolder.py +7 -4
  104. zrb/task/scheduler.py +7 -4
  105. zrb/task/tcp_check.py +6 -4
  106. zrb/util/ascii_art/art/bee.txt +17 -0
  107. zrb/util/ascii_art/art/cat.txt +9 -0
  108. zrb/util/ascii_art/art/ghost.txt +16 -0
  109. zrb/util/ascii_art/art/panda.txt +17 -0
  110. zrb/util/ascii_art/art/rose.txt +14 -0
  111. zrb/util/ascii_art/art/unicorn.txt +15 -0
  112. zrb/util/ascii_art/banner.py +92 -0
  113. zrb/util/attr.py +54 -39
  114. zrb/util/cli/markdown.py +32 -0
  115. zrb/util/cli/text.py +30 -0
  116. zrb/util/cmd/command.py +33 -10
  117. zrb/util/file.py +61 -33
  118. zrb/util/git.py +2 -2
  119. zrb/util/{llm/prompt.py → markdown.py} +2 -3
  120. zrb/util/match.py +78 -0
  121. zrb/util/run.py +3 -3
  122. zrb/util/string/conversion.py +1 -1
  123. zrb/util/truncate.py +23 -0
  124. zrb/util/yaml.py +204 -0
  125. zrb/xcom/xcom.py +10 -0
  126. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/METADATA +41 -27
  127. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/RECORD +129 -131
  128. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/WHEEL +1 -1
  129. zrb/attr/__init__.py +0 -0
  130. zrb/builtin/llm/chat_session.py +0 -311
  131. zrb/builtin/llm/history.py +0 -71
  132. zrb/builtin/llm/input.py +0 -27
  133. zrb/builtin/llm/llm_ask.py +0 -187
  134. zrb/builtin/llm/previous-session.js +0 -21
  135. zrb/builtin/llm/tool/__init__.py +0 -0
  136. zrb/builtin/llm/tool/api.py +0 -71
  137. zrb/builtin/llm/tool/cli.py +0 -38
  138. zrb/builtin/llm/tool/code.py +0 -254
  139. zrb/builtin/llm/tool/file.py +0 -626
  140. zrb/builtin/llm/tool/sub_agent.py +0 -137
  141. zrb/builtin/llm/tool/web.py +0 -195
  142. zrb/builtin/project/__init__.py +0 -0
  143. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/__init__.py +0 -0
  144. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/service/__init__.py +0 -0
  145. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/__init__.py +0 -0
  146. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/__init__.py +0 -0
  147. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/__init__.py +0 -0
  148. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
  149. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
  150. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/__init__.py +0 -0
  151. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py +0 -0
  152. zrb/builtin/project/create/__init__.py +0 -0
  153. zrb/builtin/shell/__init__.py +0 -0
  154. zrb/builtin/shell/autocomplete/__init__.py +0 -0
  155. zrb/callback/__init__.py +0 -0
  156. zrb/cmd/__init__.py +0 -0
  157. zrb/config/default_prompt/file_extractor_system_prompt.md +0 -12
  158. zrb/config/default_prompt/interactive_system_prompt.md +0 -35
  159. zrb/config/default_prompt/persona.md +0 -1
  160. zrb/config/default_prompt/repo_extractor_system_prompt.md +0 -112
  161. zrb/config/default_prompt/repo_summarizer_system_prompt.md +0 -10
  162. zrb/config/default_prompt/summarization_prompt.md +0 -16
  163. zrb/config/default_prompt/system_prompt.md +0 -32
  164. zrb/config/llm_config.py +0 -243
  165. zrb/config/llm_context/config.py +0 -129
  166. zrb/config/llm_context/config_parser.py +0 -46
  167. zrb/config/llm_rate_limitter.py +0 -137
  168. zrb/content_transformer/__init__.py +0 -0
  169. zrb/context/__init__.py +0 -0
  170. zrb/dot_dict/__init__.py +0 -0
  171. zrb/env/__init__.py +0 -0
  172. zrb/group/__init__.py +0 -0
  173. zrb/input/__init__.py +0 -0
  174. zrb/runner/__init__.py +0 -0
  175. zrb/runner/web_route/__init__.py +0 -0
  176. zrb/runner/web_route/home_page/__init__.py +0 -0
  177. zrb/session/__init__.py +0 -0
  178. zrb/session_state_log/__init__.py +0 -0
  179. zrb/session_state_logger/__init__.py +0 -0
  180. zrb/task/__init__.py +0 -0
  181. zrb/task/base/__init__.py +0 -0
  182. zrb/task/llm/__init__.py +0 -0
  183. zrb/task/llm/agent.py +0 -243
  184. zrb/task/llm/config.py +0 -103
  185. zrb/task/llm/conversation_history.py +0 -128
  186. zrb/task/llm/conversation_history_model.py +0 -242
  187. zrb/task/llm/default_workflow/coding.md +0 -24
  188. zrb/task/llm/default_workflow/copywriting.md +0 -17
  189. zrb/task/llm/default_workflow/researching.md +0 -18
  190. zrb/task/llm/error.py +0 -95
  191. zrb/task/llm/history_summarization.py +0 -216
  192. zrb/task/llm/print_node.py +0 -101
  193. zrb/task/llm/prompt.py +0 -325
  194. zrb/task/llm/tool_wrapper.py +0 -220
  195. zrb/task/llm/typing.py +0 -3
  196. zrb/task/llm_task.py +0 -341
  197. zrb/task_status/__init__.py +0 -0
  198. zrb/util/__init__.py +0 -0
  199. zrb/util/cli/__init__.py +0 -0
  200. zrb/util/cmd/__init__.py +0 -0
  201. zrb/util/codemod/__init__.py +0 -0
  202. zrb/util/string/__init__.py +0 -0
  203. zrb/xcom/__init__.py +0 -0
  204. {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/entry_points.txt +0 -0
zrb/llm/prompt/note.py ADDED
@@ -0,0 +1,41 @@
1
+ import os
2
+ from typing import Callable
3
+
4
+ from zrb.context.any_context import AnyContext
5
+ from zrb.llm.note.manager import NoteManager
6
+ from zrb.util.markdown import make_markdown_section
7
+
8
+
9
+ def create_note_prompt(note_manager: NoteManager):
10
+ def note_prompt(
11
+ ctx: AnyContext,
12
+ current_prompt: str,
13
+ next_handler: Callable[[AnyContext, str], str],
14
+ ) -> str:
15
+ cwd = os.getcwd()
16
+ notes = note_manager.read_all(cwd)
17
+
18
+ if not notes:
19
+ return next_handler(ctx, current_prompt)
20
+
21
+ # Format notes
22
+ note_lines = []
23
+
24
+ # Sort keys for deterministic output
25
+ sorted_keys = sorted(notes.keys())
26
+
27
+ for key in sorted_keys:
28
+ content = notes[key].strip()
29
+ if not content:
30
+ continue
31
+ note_lines.append(f"**{key}**:\n{content}\n")
32
+
33
+ if not note_lines:
34
+ return next_handler(ctx, current_prompt)
35
+
36
+ full_note_content = "\n".join(note_lines)
37
+ note_block = make_markdown_section("Notes & Context", full_note_content)
38
+
39
+ return next_handler(ctx, f"{current_prompt}\n\n{note_block}")
40
+
41
+ return note_prompt
@@ -0,0 +1,46 @@
1
+ import os
2
+ import platform
3
+ import subprocess
4
+ from datetime import datetime
5
+ from typing import Callable
6
+
7
+ from zrb.context.any_context import AnyContext
8
+ from zrb.util.markdown import make_markdown_section
9
+
10
+
11
+ def system_context(
12
+ ctx: AnyContext, current_prompt: str, next_handler: Callable[[AnyContext, str], str]
13
+ ) -> str:
14
+ # Time
15
+ now = datetime.now().strftime("%A, %B %d, %Y %H:%M:%S")
16
+
17
+ # System
18
+ os_info = f"{platform.system()} {platform.release()}"
19
+
20
+ # CWD
21
+ cwd = os.getcwd()
22
+
23
+ # Git
24
+ git_info = ""
25
+ try:
26
+ if os.path.isdir(os.path.join(cwd, ".git")):
27
+ # Get branch
28
+ res = subprocess.run(
29
+ ["git", "branch", "--show-current"], capture_output=True, text=True
30
+ )
31
+ if res.returncode == 0:
32
+ branch = res.stdout.strip()
33
+ if branch:
34
+ git_info = f"\n- Git Branch: {branch}"
35
+ except Exception:
36
+ pass
37
+
38
+ info_content = "\n".join(
39
+ [
40
+ f"- Date: {now}",
41
+ f"- OS: {os_info}",
42
+ f"- Directory: {cwd}{git_info}",
43
+ ]
44
+ )
45
+ info_block = make_markdown_section("System Context", info_content)
46
+ return next_handler(ctx, f"{current_prompt}\n\n{info_block}")
zrb/llm/prompt/zrb.py ADDED
@@ -0,0 +1,41 @@
1
+ from typing import Callable
2
+
3
+ from zrb.config.config import CFG
4
+ from zrb.context.any_context import AnyContext
5
+ from zrb.runner.cli import cli
6
+ from zrb.util.markdown import make_markdown_section
7
+
8
+
9
+ def create_zrb_prompt():
10
+ def zrb_prompt(
11
+ ctx: AnyContext,
12
+ current_prompt: str,
13
+ next_handler: Callable[[AnyContext, str], str],
14
+ ) -> str:
15
+ additional_context = []
16
+ # Available Zrb Workflows (Skills)
17
+ zrb_cmd = CFG.ROOT_GROUP_NAME
18
+ zrb_context = []
19
+
20
+ # List top-level groups
21
+ if cli.subgroups:
22
+ zrb_context.append(f"Groups (Use 'list_{zrb_cmd}_tasks' to see details):")
23
+ for alias, grp in cli.subgroups.items():
24
+ zrb_context.append(f"- {alias}: {grp.description}")
25
+
26
+ # List top-level tasks
27
+ if cli.subtasks:
28
+ zrb_context.append("Tasks:")
29
+ for alias, task in cli.subtasks.items():
30
+ zrb_context.append(f"- {alias}: {task.description}")
31
+
32
+ additional_context.append(
33
+ make_markdown_section(
34
+ f"Available Skills ({zrb_cmd} Workflows)", "\n".join(zrb_context)
35
+ )
36
+ )
37
+
38
+ new_section = "\n\n".join(additional_context)
39
+ return next_handler(ctx, f"{current_prompt}\n\n{new_section}")
40
+
41
+ return zrb_prompt
@@ -0,0 +1,3 @@
1
+ from zrb.llm.skill.manager import Skill, SkillManager, skill_manager
2
+
3
+ __all__ = ["Skill", "SkillManager", "skill_manager"]
@@ -0,0 +1,86 @@
1
+ import os
2
+ from typing import Dict, List, Optional
3
+
4
+ IGNORE_DIRS = {
5
+ ".git",
6
+ "node_modules",
7
+ "__pycache__",
8
+ ".venv",
9
+ "venv",
10
+ "dist",
11
+ "build",
12
+ ".idea",
13
+ ".vscode",
14
+ }
15
+
16
+
17
+ class Skill:
18
+ def __init__(self, name: str, path: str, description: str):
19
+ self.name = name
20
+ self.path = path
21
+ self.description = description
22
+
23
+
24
+ class SkillManager:
25
+ def __init__(self, root_dir: str = "."):
26
+ self.root_dir = root_dir
27
+ self._skills: Dict[str, Skill] = {}
28
+
29
+ def scan(self) -> List[Skill]:
30
+ self._skills = {}
31
+ for root, dirs, files in os.walk(self.root_dir):
32
+ dirs[:] = [d for d in dirs if d not in IGNORE_DIRS]
33
+
34
+ for file in files:
35
+ if file == "SKILL.md" or file.endswith(".skill.md"):
36
+ full_path = os.path.join(root, file)
37
+ rel_path = os.path.relpath(full_path, self.root_dir)
38
+ self._load_skill(rel_path, full_path)
39
+
40
+ return list(self._skills.values())
41
+
42
+ def _load_skill(self, rel_path: str, full_path: str):
43
+ try:
44
+ with open(full_path, "r", encoding="utf-8") as f:
45
+ lines = f.readlines()
46
+
47
+ name = os.path.basename(os.path.dirname(full_path))
48
+ description = "No description"
49
+
50
+ # Parse Markdown for Header 1
51
+ for line in lines:
52
+ stripped = line.strip()
53
+ if stripped.startswith("# "):
54
+ name = stripped[2:].strip()
55
+ break
56
+
57
+ # Use name as key, handle duplicates
58
+ key = name
59
+ if key in self._skills:
60
+ key = f"{name} ({rel_path})"
61
+
62
+ self._skills[key] = Skill(name=key, path=rel_path, description=description)
63
+
64
+ except Exception:
65
+ pass
66
+
67
+ def get_skill_content(self, name: str) -> Optional[str]:
68
+ skill = self._skills.get(name)
69
+ if not skill:
70
+ # Try partial match or path match
71
+ for s in self._skills.values():
72
+ if s.name == name or s.path == name:
73
+ skill = s
74
+ break
75
+
76
+ if not skill:
77
+ return None
78
+
79
+ try:
80
+ with open(skill.path, "r", encoding="utf-8") as f:
81
+ return f.read()
82
+ except Exception as e:
83
+ return f"Error reading skill file: {e}"
84
+
85
+
86
+ skill_manager = SkillManager()
@@ -0,0 +1,4 @@
1
+ from zrb.llm.task.llm_chat_task import LLMChatTask
2
+ from zrb.llm.task.llm_task import LLMTask
3
+
4
+ __all__ = ["LLMChatTask", "LLMTask"]
@@ -0,0 +1,316 @@
1
+ from collections.abc import Callable
2
+ from typing import TYPE_CHECKING, Any
3
+
4
+ from zrb.attr.type import BoolAttr, StrAttr, fstring
5
+ from zrb.config.config import CFG
6
+ from zrb.context.any_context import AnyContext
7
+ from zrb.context.print_fn import PrintFn
8
+ from zrb.context.shared_context import SharedContext
9
+ from zrb.env.any_env import AnyEnv
10
+ from zrb.input.any_input import AnyInput
11
+ from zrb.input.bool_input import BoolInput
12
+ from zrb.input.str_input import StrInput
13
+ from zrb.llm.app.confirmation.handler import ConfirmationMiddleware
14
+ from zrb.llm.config.config import LLMConfig
15
+ from zrb.llm.config.config import llm_config as default_llm_config
16
+ from zrb.llm.config.limiter import LLMLimiter
17
+ from zrb.llm.history_manager.any_history_manager import AnyHistoryManager
18
+ from zrb.llm.history_manager.file_history_manager import FileHistoryManager
19
+ from zrb.llm.prompt.compose import PromptManager
20
+ from zrb.llm.task.llm_task import LLMTask
21
+ from zrb.llm.util.attachment import get_attachments
22
+ from zrb.session.session import Session
23
+ from zrb.task.any_task import AnyTask
24
+ from zrb.task.base_task import BaseTask
25
+ from zrb.util.attr import get_attr, get_bool_attr, get_str_attr
26
+ from zrb.util.string.name import get_random_name
27
+
28
+ if TYPE_CHECKING:
29
+ from pydantic_ai import Tool, UserContent
30
+ from pydantic_ai._agent_graph import HistoryProcessor
31
+ from pydantic_ai.models import Model
32
+ from pydantic_ai.settings import ModelSettings
33
+ from pydantic_ai.tools import ToolFuncEither
34
+ from pydantic_ai.toolsets import AbstractToolset
35
+ from rich.theme import Theme
36
+
37
+
38
+ class LLMChatTask(BaseTask):
39
+
40
+ def __init__(
41
+ self,
42
+ name: str,
43
+ color: int | None = None,
44
+ icon: str | None = None,
45
+ description: str | None = None,
46
+ cli_only: bool = False,
47
+ input: list[AnyInput | None] | AnyInput | None = None,
48
+ env: list[AnyEnv | None] | AnyEnv | None = None,
49
+ system_prompt: (
50
+ "Callable[[AnyContext], str | fstring | None] | str | None"
51
+ ) = None,
52
+ render_system_prompt: bool = False,
53
+ prompt_manager: PromptManager | None = None,
54
+ tools: list["Tool | ToolFuncEither"] = [],
55
+ toolsets: list["AbstractToolset[None]"] = [],
56
+ message: StrAttr | None = None,
57
+ render_message: bool = True,
58
+ attachment: "UserContent | list[UserContent] | Callable[[AnyContext], UserContent | list[UserContent]] | None" = None, # noqa
59
+ history_processors: list["HistoryProcessor"] = [],
60
+ llm_config: LLMConfig | None = None,
61
+ llm_limitter: LLMLimiter | None = None,
62
+ model: (
63
+ "Callable[[AnyContext], Model | str | fstring | None] | Model | None"
64
+ ) = None,
65
+ render_model: bool = True,
66
+ model_settings: (
67
+ "ModelSettings | Callable[[AnyContext], ModelSettings] | None"
68
+ ) = None,
69
+ conversation_name: StrAttr | None = None,
70
+ render_conversation_name: bool = True,
71
+ history_manager: AnyHistoryManager | None = None,
72
+ tool_confirmation: Callable[[Any], Any] | None = None,
73
+ yolo: BoolAttr = False,
74
+ ui_summarize_commands: list[str] = [],
75
+ ui_attach_commands: list[str] = [],
76
+ ui_exit_commands: list[str] = [],
77
+ ui_info_commands: list[str] = [],
78
+ ui_save_commands: list[str] = [],
79
+ ui_load_commands: list[str] = [],
80
+ ui_redirect_output_commands: list[str] = [],
81
+ ui_yolo_toggle_commands: list[str] = [],
82
+ ui_exec_commands: list[str] = [],
83
+ ui_greeting: StrAttr | None = None,
84
+ render_ui_greeting: bool = True,
85
+ ui_assistant_name: StrAttr | None = None,
86
+ render_ui_assistant_name: bool = True,
87
+ ui_jargon: StrAttr | None = None,
88
+ render_ui_jargon: bool = True,
89
+ ui_ascii_art: StrAttr | None = None,
90
+ render_ui_ascii_art_name: bool = True,
91
+ triggers: list[Callable[[], Any]] = [],
92
+ confirmation_middlewares: list[ConfirmationMiddleware] = [],
93
+ markdown_theme: "Theme | None" = None,
94
+ interactive: BoolAttr = True,
95
+ execute_condition: bool | str | Callable[[AnyContext], bool] = True,
96
+ retries: int = 2,
97
+ retry_period: float = 0,
98
+ readiness_check: list[AnyTask] | AnyTask | None = None,
99
+ readiness_check_delay: float = 0.5,
100
+ readiness_check_period: float = 5,
101
+ readiness_failure_threshold: int = 1,
102
+ readiness_timeout: int = 60,
103
+ monitor_readiness: bool = False,
104
+ upstream: list[AnyTask] | AnyTask | None = None,
105
+ fallback: list[AnyTask] | AnyTask | None = None,
106
+ successor: list[AnyTask] | AnyTask | None = None,
107
+ print_fn: PrintFn | None = None,
108
+ ):
109
+ super().__init__(
110
+ name=name,
111
+ color=color,
112
+ icon=icon,
113
+ description=description,
114
+ cli_only=cli_only,
115
+ input=input,
116
+ env=env,
117
+ execute_condition=execute_condition,
118
+ retries=retries,
119
+ retry_period=retry_period,
120
+ readiness_check=readiness_check,
121
+ readiness_check_delay=readiness_check_delay,
122
+ readiness_check_period=readiness_check_period,
123
+ readiness_failure_threshold=readiness_failure_threshold,
124
+ readiness_timeout=readiness_timeout,
125
+ monitor_readiness=monitor_readiness,
126
+ upstream=upstream,
127
+ fallback=fallback,
128
+ successor=successor,
129
+ print_fn=print_fn,
130
+ )
131
+ self._llm_config = default_llm_config if llm_config is None else llm_config
132
+ self._llm_limitter = llm_limitter
133
+ self._system_prompt = system_prompt
134
+ self._render_system_prompt = render_system_prompt
135
+ self._prompt_manager = prompt_manager
136
+ self._tools = tools
137
+ self._toolsets = toolsets
138
+ self._message = message
139
+ self._render_message = render_message
140
+ self._attachment = attachment
141
+ self._history_processors = history_processors
142
+ self._model = model
143
+ self._render_model = render_model
144
+ self._model_settings = model_settings
145
+ self._conversation_name = conversation_name
146
+ self._render_conversation_name = render_conversation_name
147
+ self._history_manager = (
148
+ FileHistoryManager(history_dir=CFG.LLM_HISTORY_DIR)
149
+ if history_manager is None
150
+ else history_manager
151
+ )
152
+ self._tool_confirmation = tool_confirmation
153
+ self._yolo = yolo
154
+ self._ui_summarize_commands = ui_summarize_commands
155
+ self._ui_attach_commands = ui_attach_commands
156
+ self._ui_exit_commands = ui_exit_commands
157
+ self._ui_info_commands = ui_info_commands
158
+ self._ui_save_commands = ui_save_commands
159
+ self._ui_load_commands = ui_load_commands
160
+ self._ui_redirect_output_commands = ui_redirect_output_commands
161
+ self._ui_yolo_toggle_commands = ui_yolo_toggle_commands
162
+ self._ui_exec_commands = ui_exec_commands
163
+ self._ui_greeting = ui_greeting
164
+ self._render_ui_greeting = render_ui_greeting
165
+ self._ui_assistant_name = ui_assistant_name
166
+ self._render_ui_assistant_name = render_ui_assistant_name
167
+ self._ui_jargon = ui_jargon
168
+ self._render_ui_jargon = render_ui_jargon
169
+ self._ui_ascii_art_name = ui_ascii_art
170
+ self._render_ui_ascii_art_name = render_ui_ascii_art_name
171
+ self._triggers = triggers
172
+ self._confirmation_middlewares = confirmation_middlewares
173
+ self._markdown_theme = markdown_theme
174
+ self._interactive = interactive
175
+
176
+ @property
177
+ def prompt_manager(self) -> PromptManager:
178
+ if self._prompt_manager is None:
179
+ raise ValueError(f"Task {self.name} doesn't have prompt_manager")
180
+ return self._prompt_manager
181
+
182
+ def add_toolset(self, *toolset: "AbstractToolset"):
183
+ self.append_toolset(*toolset)
184
+
185
+ def append_toolset(self, *toolset: "AbstractToolset"):
186
+ self._toolsets += list(toolset)
187
+
188
+ def add_tool(self, *tool: "Tool | ToolFuncEither"):
189
+ self.append_tool(*tool)
190
+
191
+ def append_tool(self, *tool: "Tool | ToolFuncEither"):
192
+ self._tools += list(tool)
193
+
194
+ def add_history_processor(self, *processor: "HistoryProcessor"):
195
+ self.append_history_processor(*processor)
196
+
197
+ def append_history_processor(self, *processor: "HistoryProcessor"):
198
+ self._history_processors += list(processor)
199
+
200
+ def add_confirmation_middleware(self, *middleware: ConfirmationMiddleware):
201
+ self.prepend_confirmation_middleware(*middleware)
202
+
203
+ def prepend_confirmation_middleware(self, *middleware: ConfirmationMiddleware):
204
+ self._confirmation_middlewares = (
205
+ list(middleware) + self._confirmation_middlewares
206
+ )
207
+
208
+ def add_trigger(self, *trigger: Callable[[], Any]):
209
+ self.append_trigger(*trigger)
210
+
211
+ def append_trigger(self, *trigger: Callable[[], Any]):
212
+ self._triggers += trigger
213
+
214
+ async def _exec_action(self, ctx: AnyContext) -> Any:
215
+ from zrb.llm.app.lexer import CLIStyleLexer
216
+ from zrb.llm.app.ui import UI
217
+
218
+ initial_conversation_name = self._get_conversation_name(ctx)
219
+ initial_yolo = get_bool_attr(ctx, self._yolo, False)
220
+ initial_message = get_attr(ctx, self._message, "", self._render_message)
221
+ initial_attachments = get_attachments(ctx, self._attachment)
222
+ ui_greeting = get_str_attr(ctx, self._ui_greeting, "", self._render_ui_greeting)
223
+ ui_assistant_name = get_str_attr(
224
+ ctx, self._ui_assistant_name, "", self._render_ui_assistant_name
225
+ )
226
+ ui_jargon = get_str_attr(ctx, self._ui_jargon, "", self._render_ui_jargon)
227
+ ascii_art = get_str_attr(
228
+ ctx, self._ui_ascii_art_name, "", self._render_ui_ascii_art_name
229
+ )
230
+ interactive = get_bool_attr(ctx, self._interactive, True)
231
+
232
+ llm_task_core = LLMTask(
233
+ name=f"{self.name}-process",
234
+ input=[
235
+ StrInput("message", "Message"),
236
+ StrInput("session", "Conversation Session"),
237
+ BoolInput("yolo", "YOLO Mode"),
238
+ StrInput("attachments", "Attachments"),
239
+ ],
240
+ env=self.envs,
241
+ system_prompt=self._system_prompt,
242
+ render_system_prompt=self._render_system_prompt,
243
+ prompt_manager=self._prompt_manager,
244
+ tools=self._tools,
245
+ toolsets=self._toolsets,
246
+ history_processors=self._history_processors,
247
+ llm_config=self._llm_config,
248
+ llm_limitter=self._llm_limitter,
249
+ model=self._model,
250
+ render_model=self._render_model,
251
+ model_settings=self._model_settings,
252
+ history_manager=self._history_manager,
253
+ message="{ctx.input.message}",
254
+ conversation_name="{ctx.input.session}",
255
+ yolo="{ctx.input.yolo}",
256
+ attachment=lambda ctx: ctx.input.attachments,
257
+ summarize_command=self._ui_summarize_commands,
258
+ )
259
+
260
+ if not interactive:
261
+ session_input = {
262
+ "message": initial_message,
263
+ "session": initial_conversation_name,
264
+ "yolo": initial_yolo,
265
+ "attachments": initial_attachments,
266
+ }
267
+ shared_ctx = SharedContext(
268
+ input=session_input,
269
+ print_fn=ctx.shared_print, # Use current task's print function
270
+ )
271
+ session = Session(shared_ctx)
272
+ return await llm_task_core.async_run(session)
273
+
274
+ ui = UI(
275
+ greeting=ui_greeting,
276
+ assistant_name=ui_assistant_name,
277
+ ascii_art=ascii_art,
278
+ jargon=ui_jargon,
279
+ output_lexer=CLIStyleLexer(),
280
+ llm_task=llm_task_core,
281
+ history_manager=self._history_manager,
282
+ initial_message=initial_message,
283
+ initial_attachments=initial_attachments,
284
+ conversation_session_name=initial_conversation_name,
285
+ yolo=initial_yolo,
286
+ triggers=self._triggers,
287
+ confirmation_middlewares=self._confirmation_middlewares,
288
+ markdown_theme=self._markdown_theme,
289
+ summarize_commands=self._ui_summarize_commands,
290
+ attach_commands=self._ui_attach_commands,
291
+ exit_commands=self._ui_exit_commands,
292
+ info_commands=self._ui_info_commands,
293
+ save_commands=self._ui_save_commands,
294
+ load_commands=self._ui_load_commands,
295
+ yolo_toggle_commands=self._ui_yolo_toggle_commands,
296
+ redirect_output_commands=self._ui_redirect_output_commands,
297
+ exec_commands=self._ui_exec_commands,
298
+ model=self._get_model(ctx),
299
+ )
300
+ await ui.run_async()
301
+ return ui.last_output
302
+
303
+ def _get_conversation_name(self, ctx: AnyContext) -> str:
304
+ conversation_name = str(
305
+ get_attr(ctx, self._conversation_name, "", self._render_conversation_name)
306
+ )
307
+ if conversation_name.strip() == "":
308
+ conversation_name = get_random_name()
309
+ return conversation_name
310
+
311
+ def _get_model(self, ctx: AnyContext) -> "str | Model":
312
+ model = self._model
313
+ rendered_model = get_attr(ctx, model, None, auto_render=self._render_model)
314
+ if rendered_model is not None:
315
+ return rendered_model
316
+ return self._llm_config.model