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.
- zrb/__init__.py +118 -133
- zrb/attr/type.py +10 -7
- zrb/builtin/__init__.py +55 -1
- zrb/builtin/git.py +12 -1
- zrb/builtin/group.py +31 -15
- zrb/builtin/llm/chat.py +147 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
- zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
- zrb/builtin/searxng/config/settings.yml +5671 -0
- zrb/builtin/searxng/start.py +21 -0
- zrb/builtin/shell/autocomplete/bash.py +4 -3
- zrb/builtin/shell/autocomplete/zsh.py +4 -3
- zrb/callback/callback.py +8 -1
- zrb/cmd/cmd_result.py +2 -1
- zrb/config/config.py +555 -169
- zrb/config/helper.py +84 -0
- zrb/config/web_auth_config.py +50 -35
- zrb/context/any_shared_context.py +20 -3
- zrb/context/context.py +39 -5
- zrb/context/print_fn.py +13 -0
- zrb/context/shared_context.py +17 -8
- zrb/group/any_group.py +3 -3
- zrb/group/group.py +3 -3
- zrb/input/any_input.py +5 -1
- zrb/input/base_input.py +18 -6
- zrb/input/option_input.py +41 -1
- zrb/input/text_input.py +7 -24
- zrb/llm/agent/__init__.py +9 -0
- zrb/llm/agent/agent.py +215 -0
- zrb/llm/agent/summarizer.py +20 -0
- zrb/llm/app/__init__.py +10 -0
- zrb/llm/app/completion.py +281 -0
- zrb/llm/app/confirmation/allow_tool.py +66 -0
- zrb/llm/app/confirmation/handler.py +178 -0
- zrb/llm/app/confirmation/replace_confirmation.py +77 -0
- zrb/llm/app/keybinding.py +34 -0
- zrb/llm/app/layout.py +117 -0
- zrb/llm/app/lexer.py +155 -0
- zrb/llm/app/redirection.py +28 -0
- zrb/llm/app/style.py +16 -0
- zrb/llm/app/ui.py +733 -0
- zrb/llm/config/__init__.py +4 -0
- zrb/llm/config/config.py +122 -0
- zrb/llm/config/limiter.py +247 -0
- zrb/llm/history_manager/__init__.py +4 -0
- zrb/llm/history_manager/any_history_manager.py +23 -0
- zrb/llm/history_manager/file_history_manager.py +91 -0
- zrb/llm/history_processor/summarizer.py +108 -0
- zrb/llm/note/__init__.py +3 -0
- zrb/llm/note/manager.py +122 -0
- zrb/llm/prompt/__init__.py +29 -0
- zrb/llm/prompt/claude_compatibility.py +92 -0
- zrb/llm/prompt/compose.py +55 -0
- zrb/llm/prompt/default.py +51 -0
- zrb/llm/prompt/markdown/file_extractor.md +112 -0
- zrb/llm/prompt/markdown/mandate.md +23 -0
- zrb/llm/prompt/markdown/persona.md +3 -0
- zrb/llm/prompt/markdown/repo_extractor.md +112 -0
- zrb/llm/prompt/markdown/repo_summarizer.md +29 -0
- zrb/llm/prompt/markdown/summarizer.md +21 -0
- zrb/llm/prompt/note.py +41 -0
- zrb/llm/prompt/system_context.py +46 -0
- zrb/llm/prompt/zrb.py +41 -0
- zrb/llm/skill/__init__.py +3 -0
- zrb/llm/skill/manager.py +86 -0
- zrb/llm/task/__init__.py +4 -0
- zrb/llm/task/llm_chat_task.py +316 -0
- zrb/llm/task/llm_task.py +245 -0
- zrb/llm/tool/__init__.py +39 -0
- zrb/llm/tool/bash.py +75 -0
- zrb/llm/tool/code.py +266 -0
- zrb/llm/tool/file.py +419 -0
- zrb/llm/tool/note.py +70 -0
- zrb/{builtin/llm → llm}/tool/rag.py +33 -37
- zrb/llm/tool/search/brave.py +53 -0
- zrb/llm/tool/search/searxng.py +47 -0
- zrb/llm/tool/search/serpapi.py +47 -0
- zrb/llm/tool/skill.py +19 -0
- zrb/llm/tool/sub_agent.py +70 -0
- zrb/llm/tool/web.py +97 -0
- zrb/llm/tool/zrb_task.py +66 -0
- zrb/llm/util/attachment.py +101 -0
- zrb/llm/util/prompt.py +104 -0
- zrb/llm/util/stream_response.py +178 -0
- zrb/runner/cli.py +21 -20
- zrb/runner/common_util.py +24 -19
- zrb/runner/web_route/task_input_api_route.py +5 -5
- zrb/runner/web_util/user.py +7 -3
- zrb/session/any_session.py +12 -9
- zrb/session/session.py +38 -17
- zrb/task/any_task.py +24 -3
- zrb/task/base/context.py +42 -22
- zrb/task/base/execution.py +67 -55
- zrb/task/base/lifecycle.py +14 -7
- zrb/task/base/monitoring.py +12 -7
- zrb/task/base_task.py +113 -50
- zrb/task/base_trigger.py +16 -6
- zrb/task/cmd_task.py +6 -0
- zrb/task/http_check.py +11 -5
- zrb/task/make_task.py +5 -3
- zrb/task/rsync_task.py +30 -10
- zrb/task/scaffolder.py +7 -4
- zrb/task/scheduler.py +7 -4
- zrb/task/tcp_check.py +6 -4
- zrb/util/ascii_art/art/bee.txt +17 -0
- zrb/util/ascii_art/art/cat.txt +9 -0
- zrb/util/ascii_art/art/ghost.txt +16 -0
- zrb/util/ascii_art/art/panda.txt +17 -0
- zrb/util/ascii_art/art/rose.txt +14 -0
- zrb/util/ascii_art/art/unicorn.txt +15 -0
- zrb/util/ascii_art/banner.py +92 -0
- zrb/util/attr.py +54 -39
- zrb/util/cli/markdown.py +32 -0
- zrb/util/cli/text.py +30 -0
- zrb/util/cmd/command.py +33 -10
- zrb/util/file.py +61 -33
- zrb/util/git.py +2 -2
- zrb/util/{llm/prompt.py → markdown.py} +2 -3
- zrb/util/match.py +78 -0
- zrb/util/run.py +3 -3
- zrb/util/string/conversion.py +1 -1
- zrb/util/truncate.py +23 -0
- zrb/util/yaml.py +204 -0
- zrb/xcom/xcom.py +10 -0
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/METADATA +41 -27
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/RECORD +129 -131
- {zrb-1.15.3.dist-info → zrb-2.0.0a4.dist-info}/WHEEL +1 -1
- zrb/attr/__init__.py +0 -0
- zrb/builtin/llm/chat_session.py +0 -311
- zrb/builtin/llm/history.py +0 -71
- zrb/builtin/llm/input.py +0 -27
- zrb/builtin/llm/llm_ask.py +0 -187
- zrb/builtin/llm/previous-session.js +0 -21
- zrb/builtin/llm/tool/__init__.py +0 -0
- zrb/builtin/llm/tool/api.py +0 -71
- zrb/builtin/llm/tool/cli.py +0 -38
- zrb/builtin/llm/tool/code.py +0 -254
- zrb/builtin/llm/tool/file.py +0 -626
- zrb/builtin/llm/tool/sub_agent.py +0 -137
- zrb/builtin/llm/tool/web.py +0 -195
- zrb/builtin/project/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/template/app_template/module/my_module/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/common/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/permission/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/role/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/module/auth/service/user/__init__.py +0 -0
- zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/schema/__init__.py +0 -0
- zrb/builtin/project/create/__init__.py +0 -0
- zrb/builtin/shell/__init__.py +0 -0
- zrb/builtin/shell/autocomplete/__init__.py +0 -0
- zrb/callback/__init__.py +0 -0
- zrb/cmd/__init__.py +0 -0
- zrb/config/default_prompt/file_extractor_system_prompt.md +0 -12
- zrb/config/default_prompt/interactive_system_prompt.md +0 -35
- zrb/config/default_prompt/persona.md +0 -1
- zrb/config/default_prompt/repo_extractor_system_prompt.md +0 -112
- zrb/config/default_prompt/repo_summarizer_system_prompt.md +0 -10
- zrb/config/default_prompt/summarization_prompt.md +0 -16
- zrb/config/default_prompt/system_prompt.md +0 -32
- zrb/config/llm_config.py +0 -243
- zrb/config/llm_context/config.py +0 -129
- zrb/config/llm_context/config_parser.py +0 -46
- zrb/config/llm_rate_limitter.py +0 -137
- zrb/content_transformer/__init__.py +0 -0
- zrb/context/__init__.py +0 -0
- zrb/dot_dict/__init__.py +0 -0
- zrb/env/__init__.py +0 -0
- zrb/group/__init__.py +0 -0
- zrb/input/__init__.py +0 -0
- zrb/runner/__init__.py +0 -0
- zrb/runner/web_route/__init__.py +0 -0
- zrb/runner/web_route/home_page/__init__.py +0 -0
- zrb/session/__init__.py +0 -0
- zrb/session_state_log/__init__.py +0 -0
- zrb/session_state_logger/__init__.py +0 -0
- zrb/task/__init__.py +0 -0
- zrb/task/base/__init__.py +0 -0
- zrb/task/llm/__init__.py +0 -0
- zrb/task/llm/agent.py +0 -243
- zrb/task/llm/config.py +0 -103
- zrb/task/llm/conversation_history.py +0 -128
- zrb/task/llm/conversation_history_model.py +0 -242
- zrb/task/llm/default_workflow/coding.md +0 -24
- zrb/task/llm/default_workflow/copywriting.md +0 -17
- zrb/task/llm/default_workflow/researching.md +0 -18
- zrb/task/llm/error.py +0 -95
- zrb/task/llm/history_summarization.py +0 -216
- zrb/task/llm/print_node.py +0 -101
- zrb/task/llm/prompt.py +0 -325
- zrb/task/llm/tool_wrapper.py +0 -220
- zrb/task/llm/typing.py +0 -3
- zrb/task/llm_task.py +0 -341
- zrb/task_status/__init__.py +0 -0
- zrb/util/__init__.py +0 -0
- zrb/util/cli/__init__.py +0 -0
- zrb/util/cmd/__init__.py +0 -0
- zrb/util/codemod/__init__.py +0 -0
- zrb/util/string/__init__.py +0 -0
- zrb/xcom/__init__.py +0 -0
- {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
|
zrb/llm/skill/manager.py
ADDED
|
@@ -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()
|
zrb/llm/task/__init__.py
ADDED
|
@@ -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
|