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.
Files changed (105) hide show
  1. zrb/__init__.py +2 -6
  2. zrb/attr/type.py +8 -8
  3. zrb/builtin/__init__.py +2 -0
  4. zrb/builtin/group.py +31 -15
  5. zrb/builtin/http.py +7 -8
  6. zrb/builtin/llm/attachment.py +40 -0
  7. zrb/builtin/llm/chat_session.py +130 -144
  8. zrb/builtin/llm/chat_session_cmd.py +226 -0
  9. zrb/builtin/llm/chat_trigger.py +73 -0
  10. zrb/builtin/llm/history.py +4 -4
  11. zrb/builtin/llm/llm_ask.py +218 -110
  12. zrb/builtin/llm/tool/api.py +74 -62
  13. zrb/builtin/llm/tool/cli.py +35 -16
  14. zrb/builtin/llm/tool/code.py +49 -47
  15. zrb/builtin/llm/tool/file.py +262 -251
  16. zrb/builtin/llm/tool/note.py +84 -0
  17. zrb/builtin/llm/tool/rag.py +25 -18
  18. zrb/builtin/llm/tool/sub_agent.py +29 -22
  19. zrb/builtin/llm/tool/web.py +135 -143
  20. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/entity/add_entity_util.py +7 -7
  21. zrb/builtin/project/add/fastapp/fastapp_template/my_app_name/_zrb/module/add_module_util.py +5 -5
  22. zrb/builtin/project/add/fastapp/fastapp_util.py +1 -1
  23. zrb/builtin/searxng/config/settings.yml +5671 -0
  24. zrb/builtin/searxng/start.py +21 -0
  25. zrb/builtin/setup/latex/ubuntu.py +1 -0
  26. zrb/builtin/setup/ubuntu.py +1 -1
  27. zrb/builtin/shell/autocomplete/bash.py +4 -3
  28. zrb/builtin/shell/autocomplete/zsh.py +4 -3
  29. zrb/config/config.py +255 -78
  30. zrb/config/default_prompt/file_extractor_system_prompt.md +109 -9
  31. zrb/config/default_prompt/interactive_system_prompt.md +24 -30
  32. zrb/config/default_prompt/persona.md +1 -1
  33. zrb/config/default_prompt/repo_extractor_system_prompt.md +31 -31
  34. zrb/config/default_prompt/repo_summarizer_system_prompt.md +27 -8
  35. zrb/config/default_prompt/summarization_prompt.md +8 -13
  36. zrb/config/default_prompt/system_prompt.md +36 -30
  37. zrb/config/llm_config.py +129 -24
  38. zrb/config/llm_context/config.py +127 -90
  39. zrb/config/llm_context/config_parser.py +1 -7
  40. zrb/config/llm_context/workflow.py +81 -0
  41. zrb/config/llm_rate_limitter.py +89 -45
  42. zrb/context/any_shared_context.py +7 -1
  43. zrb/context/context.py +8 -2
  44. zrb/context/shared_context.py +6 -8
  45. zrb/group/any_group.py +12 -5
  46. zrb/group/group.py +67 -3
  47. zrb/input/any_input.py +5 -1
  48. zrb/input/base_input.py +18 -6
  49. zrb/input/text_input.py +7 -24
  50. zrb/runner/cli.py +21 -20
  51. zrb/runner/common_util.py +24 -19
  52. zrb/runner/web_route/task_input_api_route.py +5 -5
  53. zrb/runner/web_route/task_session_api_route.py +1 -4
  54. zrb/runner/web_util/user.py +7 -3
  55. zrb/session/any_session.py +12 -6
  56. zrb/session/session.py +39 -18
  57. zrb/task/any_task.py +24 -3
  58. zrb/task/base/context.py +17 -9
  59. zrb/task/base/execution.py +15 -8
  60. zrb/task/base/lifecycle.py +8 -4
  61. zrb/task/base/monitoring.py +12 -7
  62. zrb/task/base_task.py +69 -5
  63. zrb/task/base_trigger.py +12 -5
  64. zrb/task/llm/agent.py +138 -52
  65. zrb/task/llm/config.py +45 -13
  66. zrb/task/llm/conversation_history.py +76 -6
  67. zrb/task/llm/conversation_history_model.py +0 -168
  68. zrb/task/llm/default_workflow/coding/workflow.md +41 -0
  69. zrb/task/llm/default_workflow/copywriting/workflow.md +68 -0
  70. zrb/task/llm/default_workflow/git/workflow.md +118 -0
  71. zrb/task/llm/default_workflow/golang/workflow.md +128 -0
  72. zrb/task/llm/default_workflow/html-css/workflow.md +135 -0
  73. zrb/task/llm/default_workflow/java/workflow.md +146 -0
  74. zrb/task/llm/default_workflow/javascript/workflow.md +158 -0
  75. zrb/task/llm/default_workflow/python/workflow.md +160 -0
  76. zrb/task/llm/default_workflow/researching/workflow.md +153 -0
  77. zrb/task/llm/default_workflow/rust/workflow.md +162 -0
  78. zrb/task/llm/default_workflow/shell/workflow.md +299 -0
  79. zrb/task/llm/file_replacement.py +206 -0
  80. zrb/task/llm/file_tool_model.py +57 -0
  81. zrb/task/llm/history_summarization.py +22 -35
  82. zrb/task/llm/history_summarization_tool.py +24 -0
  83. zrb/task/llm/print_node.py +182 -63
  84. zrb/task/llm/prompt.py +213 -153
  85. zrb/task/llm/tool_wrapper.py +210 -53
  86. zrb/task/llm/workflow.py +76 -0
  87. zrb/task/llm_task.py +98 -47
  88. zrb/task/make_task.py +2 -3
  89. zrb/task/rsync_task.py +25 -10
  90. zrb/task/scheduler.py +4 -4
  91. zrb/util/attr.py +50 -40
  92. zrb/util/cli/markdown.py +12 -0
  93. zrb/util/cli/text.py +30 -0
  94. zrb/util/file.py +27 -11
  95. zrb/util/{llm/prompt.py → markdown.py} +2 -3
  96. zrb/util/string/conversion.py +1 -1
  97. zrb/util/truncate.py +23 -0
  98. zrb/util/yaml.py +204 -0
  99. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/METADATA +40 -20
  100. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/RECORD +102 -79
  101. {zrb-1.13.1.dist-info → zrb-1.21.17.dist-info}/WHEEL +1 -1
  102. zrb/task/llm/default_workflow/coding.md +0 -24
  103. zrb/task/llm/default_workflow/copywriting.md +0 -17
  104. zrb/task/llm/default_workflow/researching.md +0 -18
  105. {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
- # Eager load CFG
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.any_shared_context import AnySharedContext
3
+ from zrb.context.any_context import AnyContext
4
4
 
5
5
  fstring = str
6
- AnyAttr = Any | fstring | Callable[[AnySharedContext], Any]
7
- StrAttr = str | fstring | Callable[[AnySharedContext], str]
8
- BoolAttr = bool | fstring | Callable[[AnySharedContext], bool]
9
- IntAttr = int | fstring | Callable[[AnySharedContext], int]
10
- FloatAttr = float | fstring | Callable[[AnySharedContext], float]
11
- StrDictAttr = dict[str, StrAttr] | Callable[[AnySharedContext], dict[str, Any]]
12
- StrListAttr = list[StrAttr] | Callable[[AnySharedContext], list[str]]
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
- base64_group = cli.add_group(Group(name="base64", description="šŸ“„ Base64 operations"))
5
- uuid_group = cli.add_group(Group(name="uuid", description="šŸ†” UUID operations"))
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 = cli.add_group(Group(name="ulid", description="šŸ”¢ ULID operations"))
11
- jwt_group = cli.add_group(Group(name="jwt", description="šŸ”’ JWT encode/decode"))
12
- http_group = cli.add_group(Group(name="http", description="🌐 HTTP request operations"))
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 = cli.add_group(Group(name="random", description="šŸ”€ Random operation"))
15
- git_group = cli.add_group(Group(name="git", description="🌱 Git related commands"))
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 = cli.add_group(Group(name="llm", description="šŸ¤– LLM operations"))
23
- md5_group = cli.add_group(Group(name="md5", description="šŸ”¢ Md5 operations"))
24
- python_group = cli.add_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 = cli.add_group(Group(name="todo", description="āœ… Todo management"))
39
+ todo_group = _maybe_add_group(Group(name="todo", description="āœ… Todo management"))
28
40
 
29
- shell_group = cli.add_group(
41
+ shell_group = _maybe_add_group(
30
42
  Group(name="shell", description="šŸ’¬ Shell related commands")
31
43
  )
32
- shell_autocomplete_group: Group = shell_group.add_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 = cli.add_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 = cli.add_group(Group(name="setup", description="šŸ”§ Setup"))
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
- OptionInput(
36
+ BoolInput(
36
37
  name="verify_ssl",
37
- default="true",
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.lower() == "true"
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
- OptionInput(
110
+ BoolInput(
111
111
  name="verify_ssl",
112
- default="true",
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.lower() == "false":
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)
@@ -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.style import stylize_bold_yellow, stylize_faint
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
- _show_info(ctx)
22
- final_result = await _handle_initial_message(ctx)
23
- if ctx.is_web_mode:
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
- current_modes = ctx.input.modes
29
- user_inputs = []
30
- while True:
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
- # Get user input based on mode
33
- if not multiline_mode:
34
- ctx.print("šŸ’¬ >>", plain=True)
35
- user_input = await _read_next_line(is_tty, reader, ctx)
36
- if not multiline_mode:
37
- ctx.print("", plain=True)
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
- user_inputs.append(user_input)
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
- user_prompt = "\n".join(user_inputs)
75
- user_inputs = []
76
- result = await _trigger_ask_and_wait_for_result(
77
- ctx, user_prompt, current_modes
78
- )
79
- if result is not None:
80
- final_result = result
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 _show_info(ctx: AnyContext):
85
- """
86
- Displays the available chat session commands to the user.
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
- modes: str,
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(ctx, user_prompt, modes, previous_session_name, start_new)
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 = _render_markdown(result) if result is not None else ""
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
- "modes": data.get("modes"),
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
- modes: str,
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
- "modes": modes,
233
+ "attach": attach,
234
+ "workflows": workflows,
235
+ "yolo": yolo_mode,
250
236
  }
251
237
  )
252
238