zrb 1.13.1__py3-none-any.whl ā 1.21.17__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/__init__.py +2 -6
- zrb/attr/type.py +8 -8
- zrb/builtin/__init__.py +2 -0
- zrb/builtin/group.py +31 -15
- zrb/builtin/http.py +7 -8
- zrb/builtin/llm/attachment.py +40 -0
- zrb/builtin/llm/chat_session.py +130 -144
- zrb/builtin/llm/chat_session_cmd.py +226 -0
- zrb/builtin/llm/chat_trigger.py +73 -0
- zrb/builtin/llm/history.py +4 -4
- zrb/builtin/llm/llm_ask.py +218 -110
- zrb/builtin/llm/tool/api.py +74 -62
- zrb/builtin/llm/tool/cli.py +35 -16
- zrb/builtin/llm/tool/code.py +49 -47
- zrb/builtin/llm/tool/file.py +262 -251
- zrb/builtin/llm/tool/note.py +84 -0
- zrb/builtin/llm/tool/rag.py +25 -18
- zrb/builtin/llm/tool/sub_agent.py +29 -22
- zrb/builtin/llm/tool/web.py +135 -143
- 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/setup/latex/ubuntu.py +1 -0
- zrb/builtin/setup/ubuntu.py +1 -1
- zrb/builtin/shell/autocomplete/bash.py +4 -3
- zrb/builtin/shell/autocomplete/zsh.py +4 -3
- zrb/config/config.py +255 -78
- zrb/config/default_prompt/file_extractor_system_prompt.md +109 -9
- zrb/config/default_prompt/interactive_system_prompt.md +24 -30
- zrb/config/default_prompt/persona.md +1 -1
- zrb/config/default_prompt/repo_extractor_system_prompt.md +31 -31
- zrb/config/default_prompt/repo_summarizer_system_prompt.md +27 -8
- zrb/config/default_prompt/summarization_prompt.md +8 -13
- zrb/config/default_prompt/system_prompt.md +36 -30
- zrb/config/llm_config.py +129 -24
- zrb/config/llm_context/config.py +127 -90
- zrb/config/llm_context/config_parser.py +1 -7
- zrb/config/llm_context/workflow.py +81 -0
- zrb/config/llm_rate_limitter.py +89 -45
- zrb/context/any_shared_context.py +7 -1
- zrb/context/context.py +8 -2
- zrb/context/shared_context.py +6 -8
- zrb/group/any_group.py +12 -5
- zrb/group/group.py +67 -3
- zrb/input/any_input.py +5 -1
- zrb/input/base_input.py +18 -6
- zrb/input/text_input.py +7 -24
- 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_route/task_session_api_route.py +1 -4
- zrb/runner/web_util/user.py +7 -3
- zrb/session/any_session.py +12 -6
- zrb/session/session.py +39 -18
- zrb/task/any_task.py +24 -3
- zrb/task/base/context.py +17 -9
- zrb/task/base/execution.py +15 -8
- zrb/task/base/lifecycle.py +8 -4
- zrb/task/base/monitoring.py +12 -7
- zrb/task/base_task.py +69 -5
- zrb/task/base_trigger.py +12 -5
- zrb/task/llm/agent.py +138 -52
- zrb/task/llm/config.py +45 -13
- zrb/task/llm/conversation_history.py +76 -6
- zrb/task/llm/conversation_history_model.py +0 -168
- zrb/task/llm/default_workflow/coding/workflow.md +41 -0
- zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
- zrb/task/llm/default_workflow/git/workflow.md +118 -0
- zrb/task/llm/default_workflow/golang/workflow.md +128 -0
- zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
- zrb/task/llm/default_workflow/java/workflow.md +146 -0
- zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
- zrb/task/llm/default_workflow/python/workflow.md +160 -0
- zrb/task/llm/default_workflow/researching/workflow.md +153 -0
- zrb/task/llm/default_workflow/rust/workflow.md +162 -0
- zrb/task/llm/default_workflow/shell/workflow.md +299 -0
- zrb/task/llm/file_replacement.py +206 -0
- zrb/task/llm/file_tool_model.py +57 -0
- zrb/task/llm/history_summarization.py +22 -35
- zrb/task/llm/history_summarization_tool.py +24 -0
- zrb/task/llm/print_node.py +182 -63
- zrb/task/llm/prompt.py +213 -153
- zrb/task/llm/tool_wrapper.py +210 -53
- zrb/task/llm/workflow.py +76 -0
- zrb/task/llm_task.py +98 -47
- zrb/task/make_task.py +2 -3
- zrb/task/rsync_task.py +25 -10
- zrb/task/scheduler.py +4 -4
- zrb/util/attr.py +50 -40
- zrb/util/cli/markdown.py +12 -0
- zrb/util/cli/text.py +30 -0
- zrb/util/file.py +27 -11
- zrb/util/{llm/prompt.py ā markdown.py} +2 -3
- zrb/util/string/conversion.py +1 -1
- zrb/util/truncate.py +23 -0
- zrb/util/yaml.py +204 -0
- {zrb-1.13.1.dist-info ā zrb-1.21.17.dist-info}/METADATA +40 -20
- {zrb-1.13.1.dist-info ā zrb-1.21.17.dist-info}/RECORD +102 -79
- {zrb-1.13.1.dist-info ā zrb-1.21.17.dist-info}/WHEEL +1 -1
- 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-1.13.1.dist-info ā zrb-1.21.17.dist-info}/entry_points.txt +0 -0
zrb/__init__.py
CHANGED
|
@@ -61,6 +61,7 @@ _LAZY_LOAD = {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
if TYPE_CHECKING:
|
|
64
|
+
from zrb import builtin
|
|
64
65
|
from zrb.attr.type import (
|
|
65
66
|
AnyAttr,
|
|
66
67
|
BoolAttr,
|
|
@@ -126,9 +127,4 @@ def __getattr__(name: str) -> Any:
|
|
|
126
127
|
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
127
128
|
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
CFG = __getattr__("CFG")
|
|
131
|
-
if CFG.LOAD_BUILTIN:
|
|
132
|
-
from zrb import builtin
|
|
133
|
-
|
|
134
|
-
assert builtin
|
|
130
|
+
from zrb import builtin
|
zrb/attr/type.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from typing import Any, Callable
|
|
2
2
|
|
|
3
|
-
from zrb.context.
|
|
3
|
+
from zrb.context.any_context import AnyContext
|
|
4
4
|
|
|
5
5
|
fstring = str
|
|
6
|
-
AnyAttr = Any | fstring | Callable[[
|
|
7
|
-
StrAttr = str | fstring | Callable[[
|
|
8
|
-
BoolAttr = bool | fstring | Callable[[
|
|
9
|
-
IntAttr = int | fstring | Callable[[
|
|
10
|
-
FloatAttr = float | fstring | Callable[[
|
|
11
|
-
StrDictAttr = dict[str, StrAttr] | Callable[[
|
|
12
|
-
StrListAttr = list[StrAttr] | Callable[[
|
|
6
|
+
AnyAttr = Any | fstring | Callable[[AnyContext], Any]
|
|
7
|
+
StrAttr = str | fstring | Callable[[AnyContext], str | None]
|
|
8
|
+
BoolAttr = bool | fstring | Callable[[AnyContext], bool | None]
|
|
9
|
+
IntAttr = int | fstring | Callable[[AnyContext], int | None]
|
|
10
|
+
FloatAttr = float | fstring | Callable[[AnyContext], float | None]
|
|
11
|
+
StrDictAttr = dict[str, StrAttr] | Callable[[AnyContext], dict[str, Any]]
|
|
12
|
+
StrListAttr = list[StrAttr] | Callable[[AnyContext], list[str]]
|
zrb/builtin/__init__.py
CHANGED
|
@@ -9,12 +9,14 @@ 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
|
|
15
16
|
from zrb.builtin.project.create.project_task import create_project
|
|
16
17
|
from zrb.builtin.python import format_python_code
|
|
17
18
|
from zrb.builtin.random import shuffle_values, throw_dice
|
|
19
|
+
from zrb.builtin.searxng.start import start_searxng
|
|
18
20
|
from zrb.builtin.setup.asdf.asdf import setup_asdf
|
|
19
21
|
from zrb.builtin.setup.latex.ubuntu import setup_latex_on_ubuntu
|
|
20
22
|
from zrb.builtin.setup.tmux.tmux import setup_tmux
|
zrb/builtin/group.py
CHANGED
|
@@ -1,39 +1,51 @@
|
|
|
1
|
+
from zrb.config.config import CFG
|
|
1
2
|
from zrb.group.group import Group
|
|
2
3
|
from zrb.runner.cli import cli
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
def _maybe_add_group(group: Group):
|
|
7
|
+
if CFG.LOAD_BUILTIN:
|
|
8
|
+
cli.add_group(group)
|
|
9
|
+
return group
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
base64_group = _maybe_add_group(
|
|
13
|
+
Group(name="base64", description="š Base64 operations")
|
|
14
|
+
)
|
|
15
|
+
uuid_group = _maybe_add_group(Group(name="uuid", description="š UUID operations"))
|
|
6
16
|
uuid_v1_group = uuid_group.add_group(Group(name="v1", description="UUID V1 operations"))
|
|
7
17
|
uuid_v3_group = uuid_group.add_group(Group(name="v3", description="UUID V3 operations"))
|
|
8
18
|
uuid_v4_group = uuid_group.add_group(Group(name="v4", description="UUID V4 operations"))
|
|
9
19
|
uuid_v5_group = uuid_group.add_group(Group(name="v5", description="UUID V5 operations"))
|
|
10
|
-
ulid_group =
|
|
11
|
-
jwt_group =
|
|
12
|
-
http_group =
|
|
20
|
+
ulid_group = _maybe_add_group(Group(name="ulid", description="š¢ ULID operations"))
|
|
21
|
+
jwt_group = _maybe_add_group(Group(name="jwt", description="š JWT encode/decode"))
|
|
22
|
+
http_group = _maybe_add_group(
|
|
23
|
+
Group(name="http", description="š HTTP request operations")
|
|
24
|
+
)
|
|
13
25
|
|
|
14
|
-
random_group =
|
|
15
|
-
git_group =
|
|
26
|
+
random_group = _maybe_add_group(Group(name="random", description="š Random operation"))
|
|
27
|
+
git_group = _maybe_add_group(Group(name="git", description="š± Git related commands"))
|
|
16
28
|
git_branch_group = git_group.add_group(
|
|
17
29
|
Group(name="branch", description="šæ Git branch related commands")
|
|
18
30
|
)
|
|
19
31
|
git_subtree_group = git_group.add_group(
|
|
20
32
|
Group(name="subtree", description="š³ Git subtree related commands")
|
|
21
33
|
)
|
|
22
|
-
llm_group =
|
|
23
|
-
md5_group =
|
|
24
|
-
python_group =
|
|
34
|
+
llm_group = _maybe_add_group(Group(name="llm", description="š¤ LLM operations"))
|
|
35
|
+
md5_group = _maybe_add_group(Group(name="md5", description="š¢ Md5 operations"))
|
|
36
|
+
python_group = _maybe_add_group(
|
|
25
37
|
Group(name="python", description="š Python related commands")
|
|
26
38
|
)
|
|
27
|
-
todo_group =
|
|
39
|
+
todo_group = _maybe_add_group(Group(name="todo", description="ā
Todo management"))
|
|
28
40
|
|
|
29
|
-
shell_group =
|
|
41
|
+
shell_group = _maybe_add_group(
|
|
30
42
|
Group(name="shell", description="š¬ Shell related commands")
|
|
31
43
|
)
|
|
32
|
-
shell_autocomplete_group
|
|
44
|
+
shell_autocomplete_group = shell_group.add_group(
|
|
33
45
|
Group(name="autocomplete", description="āØļø Shell autocomplete related commands")
|
|
34
46
|
)
|
|
35
47
|
|
|
36
|
-
project_group =
|
|
48
|
+
project_group = _maybe_add_group(
|
|
37
49
|
Group(name="project", description="š Project related commands")
|
|
38
50
|
)
|
|
39
51
|
add_to_project_group = project_group.add_group(
|
|
@@ -43,7 +55,11 @@ add_fastapp_to_project_group = add_to_project_group.add_group(
|
|
|
43
55
|
Group(name="fastapp", description="š Add Fastapp resources")
|
|
44
56
|
)
|
|
45
57
|
|
|
46
|
-
setup_group =
|
|
58
|
+
setup_group = _maybe_add_group(Group(name="setup", description="š§ Setup"))
|
|
47
59
|
setup_latex_group = setup_group.add_group(
|
|
48
60
|
Group(name="latex", description="āļø Setup LaTeX")
|
|
49
61
|
)
|
|
62
|
+
|
|
63
|
+
searxng_group = _maybe_add_group(
|
|
64
|
+
Group(name="searxng", description="š Searxng related command")
|
|
65
|
+
)
|
zrb/builtin/http.py
CHANGED
|
@@ -2,6 +2,7 @@ from typing import Any
|
|
|
2
2
|
|
|
3
3
|
from zrb.builtin.group import http_group
|
|
4
4
|
from zrb.context.any_context import AnyContext
|
|
5
|
+
from zrb.input.bool_input import BoolInput
|
|
5
6
|
from zrb.input.option_input import OptionInput
|
|
6
7
|
from zrb.input.str_input import StrInput
|
|
7
8
|
from zrb.task.make_task import make_task
|
|
@@ -32,10 +33,9 @@ from zrb.task.make_task import make_task
|
|
|
32
33
|
prompt="Enter body as JSON",
|
|
33
34
|
default="{}",
|
|
34
35
|
),
|
|
35
|
-
|
|
36
|
+
BoolInput(
|
|
36
37
|
name="verify_ssl",
|
|
37
|
-
default=
|
|
38
|
-
options=["true", "false"],
|
|
38
|
+
default=True,
|
|
39
39
|
description="Verify SSL certificate",
|
|
40
40
|
),
|
|
41
41
|
],
|
|
@@ -55,7 +55,7 @@ def http_request(ctx: AnyContext) -> Any:
|
|
|
55
55
|
body = json.loads(ctx.input.body)
|
|
56
56
|
|
|
57
57
|
# Make request
|
|
58
|
-
verify = ctx.input.verify_ssl
|
|
58
|
+
verify = ctx.input.verify_ssl
|
|
59
59
|
response = requests.request(
|
|
60
60
|
method=ctx.input.method,
|
|
61
61
|
url=ctx.input.url,
|
|
@@ -107,10 +107,9 @@ def http_request(ctx: AnyContext) -> Any:
|
|
|
107
107
|
prompt="Enter body as JSON",
|
|
108
108
|
default="{}",
|
|
109
109
|
),
|
|
110
|
-
|
|
110
|
+
BoolInput(
|
|
111
111
|
name="verify_ssl",
|
|
112
|
-
default=
|
|
113
|
-
options=["true", "false"],
|
|
112
|
+
default=True,
|
|
114
113
|
description="Verify SSL certificate",
|
|
115
114
|
),
|
|
116
115
|
],
|
|
@@ -137,7 +136,7 @@ def generate_curl(ctx: AnyContext) -> str:
|
|
|
137
136
|
parts.extend(["--data-raw", shlex.quote(ctx.input.body)])
|
|
138
137
|
|
|
139
138
|
# Add SSL verification
|
|
140
|
-
if ctx.input.verify_ssl
|
|
139
|
+
if not ctx.input.verify_ssl:
|
|
141
140
|
parts.append("--insecure")
|
|
142
141
|
|
|
143
142
|
# Add URL
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
def get_media_type(filename: str) -> str | None:
|
|
2
|
+
"""Guess media type string based on file extension."""
|
|
3
|
+
ext = filename.lower().rsplit(".", 1)[-1] if "." in filename else ""
|
|
4
|
+
mapping: dict[str, str] = {
|
|
5
|
+
# Audio
|
|
6
|
+
"wav": "audio/wav",
|
|
7
|
+
"mp3": "audio/mpeg",
|
|
8
|
+
"ogg": "audio/ogg",
|
|
9
|
+
"flac": "audio/flac",
|
|
10
|
+
"aiff": "audio/aiff",
|
|
11
|
+
"aac": "audio/aac",
|
|
12
|
+
# Image
|
|
13
|
+
"jpg": "image/jpeg",
|
|
14
|
+
"jpeg": "image/jpeg",
|
|
15
|
+
"png": "image/png",
|
|
16
|
+
"gif": "image/gif",
|
|
17
|
+
"webp": "image/webp",
|
|
18
|
+
# Document
|
|
19
|
+
"pdf": "application/pdf",
|
|
20
|
+
"txt": "text/plain",
|
|
21
|
+
"csv": "text/csv",
|
|
22
|
+
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
23
|
+
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
24
|
+
"html": "text/html",
|
|
25
|
+
"htm": "text/html",
|
|
26
|
+
"md": "text/markdown",
|
|
27
|
+
"doc": "application/msword",
|
|
28
|
+
"xls": "application/vnd.ms-excel",
|
|
29
|
+
# Video
|
|
30
|
+
"mkv": "video/x-matroska",
|
|
31
|
+
"mov": "video/quicktime",
|
|
32
|
+
"mp4": "video/mp4",
|
|
33
|
+
"webm": "video/webm",
|
|
34
|
+
"flv": "video/x-flv",
|
|
35
|
+
"mpeg": "video/mpeg",
|
|
36
|
+
"mpg": "video/mpeg",
|
|
37
|
+
"wmv": "video/x-ms-wmv",
|
|
38
|
+
"3gp": "video/3gpp",
|
|
39
|
+
}
|
|
40
|
+
return mapping.get(ext)
|
zrb/builtin/llm/chat_session.py
CHANGED
|
@@ -1,16 +1,37 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module provides functions for managing interactive chat sessions with an LLM.
|
|
3
|
-
|
|
4
|
-
It handles reading user input, triggering the LLM task, and managing the
|
|
5
|
-
conversation flow via XCom.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
1
|
import asyncio
|
|
9
2
|
import sys
|
|
10
|
-
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from zrb.builtin.llm.chat_session_cmd import (
|
|
6
|
+
ATTACHMENT_CMD,
|
|
7
|
+
HELP_CMD,
|
|
8
|
+
MULTILINE_END_CMD,
|
|
9
|
+
MULTILINE_START_CMD,
|
|
10
|
+
QUIT_CMD,
|
|
11
|
+
RUN_CLI_CMD,
|
|
12
|
+
SAVE_CMD,
|
|
13
|
+
WORKFLOW_CMD,
|
|
14
|
+
YOLO_CMD,
|
|
15
|
+
get_new_attachments,
|
|
16
|
+
get_new_workflows,
|
|
17
|
+
get_new_yolo_mode,
|
|
18
|
+
is_command_match,
|
|
19
|
+
print_commands,
|
|
20
|
+
print_current_attachments,
|
|
21
|
+
print_current_workflows,
|
|
22
|
+
print_current_yolo_mode,
|
|
23
|
+
run_cli_command,
|
|
24
|
+
save_final_result,
|
|
25
|
+
)
|
|
26
|
+
from zrb.builtin.llm.chat_trigger import llm_chat_trigger
|
|
11
27
|
from zrb.config.llm_config import llm_config
|
|
12
28
|
from zrb.context.any_context import AnyContext
|
|
13
|
-
from zrb.util.cli.
|
|
29
|
+
from zrb.util.cli.markdown import render_markdown
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from asyncio import StreamReader
|
|
33
|
+
|
|
34
|
+
from prompt_toolkit import PromptSession
|
|
14
35
|
|
|
15
36
|
|
|
16
37
|
async def read_user_prompt(ctx: AnyContext) -> str:
|
|
@@ -18,114 +39,97 @@ async def read_user_prompt(ctx: AnyContext) -> str:
|
|
|
18
39
|
Reads user input from the CLI for an interactive chat session.
|
|
19
40
|
Orchestrates the session by calling helper functions.
|
|
20
41
|
"""
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return final_result
|
|
25
|
-
is_tty = ctx.is_tty
|
|
26
|
-
reader = await _setup_input_reader(is_tty)
|
|
42
|
+
print_commands(ctx)
|
|
43
|
+
is_tty: bool = ctx.is_tty
|
|
44
|
+
reader: PromptSession[Any] | StreamReader = await _setup_input_reader(is_tty)
|
|
27
45
|
multiline_mode = False
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
is_first_time = True
|
|
47
|
+
current_workflows: str = ctx.input.workflows
|
|
48
|
+
current_yolo_mode: bool | str = ctx.input.yolo
|
|
49
|
+
current_attachments: str = ctx.input.attach
|
|
50
|
+
user_inputs: list[str] = []
|
|
51
|
+
final_result: str = ""
|
|
52
|
+
should_end = False
|
|
53
|
+
while not should_end:
|
|
31
54
|
await asyncio.sleep(0.01)
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if
|
|
37
|
-
ctx.
|
|
38
|
-
# Handle user input
|
|
39
|
-
if user_input.strip().lower() in ("/bye", "/quit", "/q", "/exit"):
|
|
40
|
-
user_prompt = "\n".join(user_inputs)
|
|
41
|
-
user_inputs = []
|
|
42
|
-
result = await _trigger_ask_and_wait_for_result(
|
|
43
|
-
ctx, user_prompt, current_modes
|
|
44
|
-
)
|
|
45
|
-
if result is not None:
|
|
46
|
-
final_result = result
|
|
47
|
-
break
|
|
48
|
-
elif user_input.strip().lower() in ("/multi",):
|
|
49
|
-
multiline_mode = True
|
|
50
|
-
elif user_input.strip().lower() in ("/end",):
|
|
51
|
-
ctx.print("", plain=True)
|
|
52
|
-
multiline_mode = False
|
|
53
|
-
user_prompt = "\n".join(user_inputs)
|
|
54
|
-
user_inputs = []
|
|
55
|
-
result = await _trigger_ask_and_wait_for_result(
|
|
56
|
-
ctx, user_prompt, current_modes
|
|
57
|
-
)
|
|
58
|
-
if result is not None:
|
|
59
|
-
final_result = result
|
|
60
|
-
elif user_input.strip().lower().startswith("/mode"):
|
|
61
|
-
mode_parts = user_input.split(" ", maxsplit=2)
|
|
62
|
-
if len(mode_parts) > 1:
|
|
63
|
-
current_modes = mode_parts[1]
|
|
64
|
-
ctx.print(f"Current mode: {current_modes}", plain=True)
|
|
65
|
-
ctx.print("", plain=True)
|
|
66
|
-
continue
|
|
67
|
-
elif user_input.strip().lower() in ("/help", "/info"):
|
|
68
|
-
_show_info(ctx)
|
|
69
|
-
continue
|
|
55
|
+
previous_session_name: str | None = (
|
|
56
|
+
ctx.input.previous_session if is_first_time else ""
|
|
57
|
+
)
|
|
58
|
+
start_new: bool = ctx.input.start_new if is_first_time else False
|
|
59
|
+
if is_first_time and ctx.input.message.strip() != "":
|
|
60
|
+
user_input = ctx.input.message
|
|
70
61
|
else:
|
|
71
|
-
|
|
72
|
-
if multiline_mode:
|
|
62
|
+
# Get user input based on mode
|
|
63
|
+
if not multiline_mode:
|
|
64
|
+
ctx.print("š¬ >>", plain=True)
|
|
65
|
+
user_input = await llm_chat_trigger.wait(reader, ctx)
|
|
66
|
+
if not multiline_mode:
|
|
67
|
+
ctx.print("", plain=True)
|
|
68
|
+
# At this point, is_first_time has to be False
|
|
69
|
+
if is_first_time:
|
|
70
|
+
is_first_time = False
|
|
71
|
+
# Handle user input (including slash commands)
|
|
72
|
+
if multiline_mode:
|
|
73
|
+
if is_command_match(user_input, MULTILINE_END_CMD):
|
|
74
|
+
ctx.print("", plain=True)
|
|
75
|
+
multiline_mode = False
|
|
76
|
+
else:
|
|
77
|
+
user_inputs.append(user_input)
|
|
78
|
+
continue
|
|
79
|
+
else:
|
|
80
|
+
if is_command_match(user_input, QUIT_CMD):
|
|
81
|
+
should_end = True
|
|
82
|
+
elif is_command_match(user_input, MULTILINE_START_CMD):
|
|
83
|
+
multiline_mode = True
|
|
84
|
+
ctx.print("", plain=True)
|
|
85
|
+
continue
|
|
86
|
+
elif is_command_match(user_input, WORKFLOW_CMD):
|
|
87
|
+
current_workflows = get_new_workflows(current_workflows, user_input)
|
|
88
|
+
print_current_workflows(ctx, current_workflows)
|
|
89
|
+
continue
|
|
90
|
+
elif is_command_match(user_input, SAVE_CMD):
|
|
91
|
+
save_final_result(ctx, user_input, final_result)
|
|
92
|
+
continue
|
|
93
|
+
elif is_command_match(user_input, ATTACHMENT_CMD):
|
|
94
|
+
current_attachments = get_new_attachments(
|
|
95
|
+
current_attachments, user_input
|
|
96
|
+
)
|
|
97
|
+
print_current_attachments(ctx, current_attachments)
|
|
73
98
|
continue
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
|
|
99
|
+
elif is_command_match(user_input, YOLO_CMD):
|
|
100
|
+
current_yolo_mode = get_new_yolo_mode(current_yolo_mode, user_input)
|
|
101
|
+
print_current_yolo_mode(ctx, current_yolo_mode)
|
|
102
|
+
continue
|
|
103
|
+
elif is_command_match(user_input, RUN_CLI_CMD):
|
|
104
|
+
run_cli_command(ctx, user_input)
|
|
105
|
+
continue
|
|
106
|
+
elif is_command_match(user_input, HELP_CMD):
|
|
107
|
+
print_commands(ctx)
|
|
108
|
+
continue
|
|
109
|
+
else:
|
|
110
|
+
user_inputs.append(user_input)
|
|
111
|
+
# Trigger LLM
|
|
112
|
+
user_prompt = "\n".join(user_inputs)
|
|
113
|
+
user_inputs = []
|
|
114
|
+
result = await _trigger_ask_and_wait_for_result(
|
|
115
|
+
ctx=ctx,
|
|
116
|
+
user_prompt=user_prompt,
|
|
117
|
+
attach=current_attachments,
|
|
118
|
+
workflows=current_workflows,
|
|
119
|
+
yolo_mode=current_yolo_mode,
|
|
120
|
+
previous_session_name=previous_session_name,
|
|
121
|
+
start_new=start_new,
|
|
122
|
+
)
|
|
123
|
+
current_attachments = ""
|
|
124
|
+
final_result = final_result if result is None else result
|
|
125
|
+
if ctx.is_web_mode or not is_tty:
|
|
126
|
+
return final_result
|
|
81
127
|
return final_result
|
|
82
128
|
|
|
83
129
|
|
|
84
|
-
def
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
ctx: The context object for the task.
|
|
89
|
-
"""
|
|
90
|
-
ctx.print(
|
|
91
|
-
"\n".join(
|
|
92
|
-
[
|
|
93
|
-
_format_info_line("/bye", "Quit from chat session"),
|
|
94
|
-
_format_info_line("/multi", "Start multiline input"),
|
|
95
|
-
_format_info_line("/end", "End multiline input"),
|
|
96
|
-
_format_info_line("/modes", "Show current modes"),
|
|
97
|
-
_format_info_line("/modes <mode1,mode2,..>", "Set current modes"),
|
|
98
|
-
_format_info_line("/help", "Show this message"),
|
|
99
|
-
]
|
|
100
|
-
),
|
|
101
|
-
plain=True,
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def _format_info_line(command: str, description: str) -> str:
|
|
106
|
-
styled_command = stylize_bold_yellow(command.ljust(25))
|
|
107
|
-
styled_description = stylize_faint(description)
|
|
108
|
-
return f" {styled_command} {styled_description}"
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
async def _handle_initial_message(ctx: AnyContext) -> str:
|
|
112
|
-
"""Processes the initial message from the command line."""
|
|
113
|
-
if not ctx.input.message or ctx.input.message.strip() == "":
|
|
114
|
-
return ""
|
|
115
|
-
ctx.print("š¬ >>", plain=True)
|
|
116
|
-
ctx.print(ctx.input.message, plain=True)
|
|
117
|
-
ctx.print("", plain=True)
|
|
118
|
-
result = await _trigger_ask_and_wait_for_result(
|
|
119
|
-
ctx,
|
|
120
|
-
user_prompt=ctx.input.message,
|
|
121
|
-
modes=ctx.input.modes,
|
|
122
|
-
previous_session_name=ctx.input.previous_session,
|
|
123
|
-
start_new=ctx.input.start_new,
|
|
124
|
-
)
|
|
125
|
-
return result if result is not None else ""
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
async def _setup_input_reader(is_interactive: bool):
|
|
130
|
+
async def _setup_input_reader(
|
|
131
|
+
is_interactive: bool,
|
|
132
|
+
) -> "PromptSession[Any] | StreamReader":
|
|
129
133
|
"""Sets up and returns the appropriate asynchronous input reader."""
|
|
130
134
|
if is_interactive:
|
|
131
135
|
from prompt_toolkit import PromptSession
|
|
@@ -139,24 +143,12 @@ async def _setup_input_reader(is_interactive: bool):
|
|
|
139
143
|
return reader
|
|
140
144
|
|
|
141
145
|
|
|
142
|
-
async def _read_next_line(is_interactive: bool, reader, ctx: AnyContext) -> str:
|
|
143
|
-
"""Reads one line of input using the provided reader."""
|
|
144
|
-
if is_interactive:
|
|
145
|
-
return await reader.prompt_async()
|
|
146
|
-
|
|
147
|
-
line_bytes = await reader.readline()
|
|
148
|
-
if not line_bytes:
|
|
149
|
-
return "/bye" # Signal to exit
|
|
150
|
-
|
|
151
|
-
user_input = line_bytes.decode().strip()
|
|
152
|
-
ctx.print(user_input, plain=True)
|
|
153
|
-
return user_input
|
|
154
|
-
|
|
155
|
-
|
|
156
146
|
async def _trigger_ask_and_wait_for_result(
|
|
157
147
|
ctx: AnyContext,
|
|
158
148
|
user_prompt: str,
|
|
159
|
-
|
|
149
|
+
attach: str,
|
|
150
|
+
workflows: str,
|
|
151
|
+
yolo_mode: bool | str,
|
|
160
152
|
previous_session_name: str | None = None,
|
|
161
153
|
start_new: bool = False,
|
|
162
154
|
) -> str | None:
|
|
@@ -174,29 +166,17 @@ async def _trigger_ask_and_wait_for_result(
|
|
|
174
166
|
"""
|
|
175
167
|
if user_prompt.strip() == "":
|
|
176
168
|
return None
|
|
177
|
-
await _trigger_ask(
|
|
169
|
+
await _trigger_ask(
|
|
170
|
+
ctx, user_prompt, attach, workflows, yolo_mode, previous_session_name, start_new
|
|
171
|
+
)
|
|
178
172
|
result = await _wait_ask_result(ctx)
|
|
179
|
-
md_result =
|
|
173
|
+
md_result = render_markdown(result) if result is not None else ""
|
|
180
174
|
ctx.print("\nš¤ >>", plain=True)
|
|
181
175
|
ctx.print(md_result, plain=True)
|
|
182
176
|
ctx.print("", plain=True)
|
|
183
177
|
return result
|
|
184
178
|
|
|
185
179
|
|
|
186
|
-
def _render_markdown(markdown_text: str) -> str:
|
|
187
|
-
"""
|
|
188
|
-
Renders Markdown to a string, ensuring link URLs are visible.
|
|
189
|
-
"""
|
|
190
|
-
from rich.console import Console
|
|
191
|
-
from rich.markdown import Markdown
|
|
192
|
-
|
|
193
|
-
console = Console()
|
|
194
|
-
markdown = Markdown(markdown_text, hyperlinks=False)
|
|
195
|
-
with console.capture() as capture:
|
|
196
|
-
console.print(markdown)
|
|
197
|
-
return capture.get()
|
|
198
|
-
|
|
199
|
-
|
|
200
180
|
def get_llm_ask_input_mapping(callback_ctx: AnyContext):
|
|
201
181
|
"""
|
|
202
182
|
Generates the input mapping for the LLM ask task from the callback context.
|
|
@@ -219,14 +199,18 @@ def get_llm_ask_input_mapping(callback_ctx: AnyContext):
|
|
|
219
199
|
"start-new": data.get("start_new"),
|
|
220
200
|
"previous-session": data.get("previous_session_name"),
|
|
221
201
|
"message": data.get("message"),
|
|
222
|
-
"
|
|
202
|
+
"attach": data.get("attach"),
|
|
203
|
+
"workflows": data.get("workflows"),
|
|
204
|
+
"yolo": data.get("yolo"),
|
|
223
205
|
}
|
|
224
206
|
|
|
225
207
|
|
|
226
208
|
async def _trigger_ask(
|
|
227
209
|
ctx: AnyContext,
|
|
228
210
|
user_prompt: str,
|
|
229
|
-
|
|
211
|
+
attach: str,
|
|
212
|
+
workflows: str,
|
|
213
|
+
yolo_mode: bool | str,
|
|
230
214
|
previous_session_name: str | None = None,
|
|
231
215
|
start_new: bool = False,
|
|
232
216
|
):
|
|
@@ -246,7 +230,9 @@ async def _trigger_ask(
|
|
|
246
230
|
"previous_session_name": previous_session_name,
|
|
247
231
|
"start_new": start_new,
|
|
248
232
|
"message": user_prompt,
|
|
249
|
-
"
|
|
233
|
+
"attach": attach,
|
|
234
|
+
"workflows": workflows,
|
|
235
|
+
"yolo": yolo_mode,
|
|
250
236
|
}
|
|
251
237
|
)
|
|
252
238
|
|