yaicli 0.4.0__py3-none-any.whl → 0.5.1__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.
- pyproject.toml +5 -3
- yaicli/chat.py +396 -0
- yaicli/cli.py +250 -251
- yaicli/client.py +385 -0
- yaicli/config.py +31 -24
- yaicli/console.py +2 -2
- yaicli/const.py +28 -2
- yaicli/entry.py +68 -40
- yaicli/exceptions.py +8 -36
- yaicli/functions/__init__.py +39 -0
- yaicli/functions/buildin/execute_shell_command.py +47 -0
- yaicli/printer.py +145 -225
- yaicli/render.py +1 -1
- yaicli/role.py +231 -0
- yaicli/schemas.py +31 -0
- yaicli/tools.py +103 -0
- yaicli/utils.py +5 -2
- {yaicli-0.4.0.dist-info → yaicli-0.5.1.dist-info}/METADATA +166 -87
- yaicli-0.5.1.dist-info/RECORD +24 -0
- {yaicli-0.4.0.dist-info → yaicli-0.5.1.dist-info}/entry_points.txt +1 -1
- yaicli/chat_manager.py +0 -290
- yaicli/providers/__init__.py +0 -34
- yaicli/providers/base.py +0 -51
- yaicli/providers/cohere.py +0 -136
- yaicli/providers/openai.py +0 -176
- yaicli/roles.py +0 -276
- yaicli-0.4.0.dist-info/RECORD +0 -23
- {yaicli-0.4.0.dist-info → yaicli-0.5.1.dist-info}/WHEEL +0 -0
- {yaicli-0.4.0.dist-info → yaicli-0.5.1.dist-info}/licenses/LICENSE +0 -0
yaicli/entry.py
CHANGED
@@ -3,15 +3,15 @@ from typing import Annotated, Any, Optional
|
|
3
3
|
|
4
4
|
import typer
|
5
5
|
|
6
|
-
from
|
7
|
-
from
|
8
|
-
from
|
9
|
-
from
|
10
|
-
from
|
6
|
+
from .chat import FileChatManager
|
7
|
+
from .config import cfg
|
8
|
+
from .const import DEFAULT_CONFIG_INI, DefaultRoleNames, JustifyEnum
|
9
|
+
from .functions import install_functions, print_functions
|
10
|
+
from .role import RoleManager
|
11
11
|
|
12
12
|
app = typer.Typer(
|
13
13
|
name="yaicli",
|
14
|
-
help="YAICLI -
|
14
|
+
help="YAICLI - Your AI assistant in the command line.",
|
15
15
|
context_settings={"help_option_names": ["-h", "--help"]},
|
16
16
|
pretty_exceptions_enable=False, # Let the CLI handle errors gracefully
|
17
17
|
rich_markup_mode="rich", # Render rich text in help messages
|
@@ -67,12 +67,19 @@ def main(
|
|
67
67
|
max_tokens: int = typer.Option( # noqa: F841
|
68
68
|
cfg["MAX_TOKENS"],
|
69
69
|
"--max-tokens",
|
70
|
-
"-M",
|
71
70
|
help="Specify the max tokens to use.",
|
72
71
|
rich_help_panel="LLM Options",
|
73
72
|
min=1,
|
74
73
|
callback=override_config,
|
75
74
|
),
|
75
|
+
stream: bool = typer.Option( # noqa: F841
|
76
|
+
cfg["STREAM"],
|
77
|
+
"--stream/--no-stream",
|
78
|
+
help=f"Specify whether to stream the response. [dim](default: {'stream' if cfg['STREAM'] else 'no-stream'})[/dim]",
|
79
|
+
rich_help_panel="LLM Options",
|
80
|
+
show_default=False,
|
81
|
+
callback=override_config,
|
82
|
+
),
|
76
83
|
# ------------------- Role Options -------------------
|
77
84
|
role: str = typer.Option(
|
78
85
|
DefaultRoleNames.DEFAULT,
|
@@ -118,7 +125,7 @@ def main(
|
|
118
125
|
help="Start in interactive chat mode.",
|
119
126
|
rich_help_panel="Chat Options",
|
120
127
|
),
|
121
|
-
# ------------------- Shell Options -------------------
|
128
|
+
# # ------------------- Shell Options -------------------
|
122
129
|
shell: bool = typer.Option(
|
123
130
|
False,
|
124
131
|
"--shell",
|
@@ -126,7 +133,7 @@ def main(
|
|
126
133
|
help="Generate and optionally execute a shell command (non-interactive).",
|
127
134
|
rich_help_panel="Shell Options",
|
128
135
|
),
|
129
|
-
# ------------------- Code Options -------------------
|
136
|
+
# # ------------------- Code Options -------------------
|
130
137
|
code: bool = typer.Option(
|
131
138
|
False,
|
132
139
|
"--code",
|
@@ -157,7 +164,8 @@ def main(
|
|
157
164
|
),
|
158
165
|
show_reasoning: bool = typer.Option( # noqa: F841
|
159
166
|
cfg["SHOW_REASONING"],
|
160
|
-
|
167
|
+
"--show-reasoning/--hide-reasoning",
|
168
|
+
help=f"Show reasoning content from the LLM. [dim](default: {'show' if cfg['SHOW_REASONING'] else 'hide'})[/dim]",
|
161
169
|
rich_help_panel="Other Options",
|
162
170
|
show_default=False,
|
163
171
|
callback=override_config,
|
@@ -170,6 +178,37 @@ def main(
|
|
170
178
|
rich_help_panel="Other Options",
|
171
179
|
callback=override_config,
|
172
180
|
),
|
181
|
+
# ------------------- Function Options -------------------
|
182
|
+
install_functions: bool = typer.Option( # noqa: F841
|
183
|
+
False,
|
184
|
+
"--install-functions",
|
185
|
+
help="Install default functions.",
|
186
|
+
rich_help_panel="Function Options",
|
187
|
+
callback=install_functions,
|
188
|
+
),
|
189
|
+
list_functions: bool = typer.Option( # noqa: F841
|
190
|
+
False,
|
191
|
+
"--list-functions",
|
192
|
+
help="List all available functions.",
|
193
|
+
rich_help_panel="Function Options",
|
194
|
+
callback=print_functions,
|
195
|
+
),
|
196
|
+
enable_functions: bool = typer.Option( # noqa: F841
|
197
|
+
cfg["ENABLE_FUNCTIONS"],
|
198
|
+
"--enable-functions/--disable-functions",
|
199
|
+
help=f"Enable/disable function calling in API requests [dim](default: {'enabled' if cfg['ENABLE_FUNCTIONS'] else 'disabled'})[/dim]",
|
200
|
+
rich_help_panel="Function Options",
|
201
|
+
show_default=False,
|
202
|
+
callback=override_config,
|
203
|
+
),
|
204
|
+
show_function_output: bool = typer.Option( # noqa: F841
|
205
|
+
cfg["SHOW_FUNCTION_OUTPUT"],
|
206
|
+
"--show-function-output/--hide-function-output",
|
207
|
+
help=f"Show the output of functions [dim](default: {'show' if cfg['SHOW_FUNCTION_OUTPUT'] else 'hide'})[/dim]",
|
208
|
+
rich_help_panel="Function Options",
|
209
|
+
show_default=False,
|
210
|
+
callback=override_config,
|
211
|
+
),
|
173
212
|
):
|
174
213
|
"""YAICLI: Your AI assistant in the command line.
|
175
214
|
|
@@ -179,7 +218,7 @@ def main(
|
|
179
218
|
print(DEFAULT_CONFIG_INI)
|
180
219
|
raise typer.Exit()
|
181
220
|
|
182
|
-
# Combine prompt argument with stdin content if available
|
221
|
+
# # Combine prompt argument with stdin content if available
|
183
222
|
final_prompt = prompt
|
184
223
|
if not sys.stdin.isatty():
|
185
224
|
stdin_content = sys.stdin.read().strip()
|
@@ -194,40 +233,29 @@ def main(
|
|
194
233
|
if chat:
|
195
234
|
print("Warning: --chat is ignored when stdin was redirected.")
|
196
235
|
chat = False
|
236
|
+
if not any([final_prompt, chat]):
|
237
|
+
print(ctx.get_help())
|
238
|
+
return
|
197
239
|
|
198
|
-
#
|
199
|
-
if not any([final_prompt, chat, list_chats, list_roles, create_role]):
|
200
|
-
# If no prompt, not starting chat, and not listing chats or roles, show help
|
201
|
-
typer.echo(ctx.get_help())
|
202
|
-
raise typer.Exit()
|
203
|
-
|
204
|
-
# Use build-in role for --shell or --code mode
|
240
|
+
# # Use build-in role for --shell or --code mode
|
205
241
|
if role and role != DefaultRoleNames.DEFAULT and (shell or code):
|
206
242
|
print("Warning: --role is ignored when --shell or --code is used.")
|
207
243
|
role = DefaultRoleNames.DEFAULT
|
208
244
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
except Exception as e:
|
224
|
-
# Catch potential errors during CLI initialization or run
|
225
|
-
print(f"An error occurred: {e}")
|
226
|
-
if verbose:
|
227
|
-
import traceback
|
228
|
-
|
229
|
-
traceback.print_exc()
|
230
|
-
raise typer.Exit(code=1)
|
245
|
+
from yaicli.cli import CLI
|
246
|
+
|
247
|
+
role = CLI.evaluate_role_name(code, shell, role)
|
248
|
+
|
249
|
+
# Instantiate the main CLI class with the specified role
|
250
|
+
cli = CLI(verbose=verbose, role=role)
|
251
|
+
|
252
|
+
# Run the appropriate mode
|
253
|
+
cli.run(
|
254
|
+
chat=chat,
|
255
|
+
shell=shell,
|
256
|
+
code=code,
|
257
|
+
user_input=final_prompt,
|
258
|
+
)
|
231
259
|
|
232
260
|
|
233
261
|
if __name__ == "__main__":
|
yaicli/exceptions.py
CHANGED
@@ -1,46 +1,18 @@
|
|
1
|
-
class
|
2
|
-
"""Base exception for
|
1
|
+
class YaicliError(Exception):
|
2
|
+
"""Base exception for yaicli"""
|
3
3
|
|
4
4
|
def __init__(self, message: str):
|
5
5
|
self.message = message
|
6
6
|
super().__init__(self.message)
|
7
7
|
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
class RoleNotFoundError(YAICLIException):
|
12
|
-
"""Exception raised when a role is not found"""
|
9
|
+
class ChatSaveError(YaicliError):
|
10
|
+
"""Error saving chat"""
|
13
11
|
|
14
|
-
pass
|
15
12
|
|
13
|
+
class ChatLoadError(YaicliError):
|
14
|
+
"""Error loading chat"""
|
16
15
|
|
17
|
-
class RoleAlreadyExistsError(YAICLIException):
|
18
|
-
"""Exception raised when a role already exists"""
|
19
16
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
class RoleCreationError(YAICLIException):
|
24
|
-
"""Exception raised when a role creation fails"""
|
25
|
-
|
26
|
-
pass
|
27
|
-
|
28
|
-
|
29
|
-
###################################
|
30
|
-
# Chat exceptions
|
31
|
-
class ChatNotFoundError(YAICLIException):
|
32
|
-
"""Exception raised when a chat is not found"""
|
33
|
-
|
34
|
-
pass
|
35
|
-
|
36
|
-
|
37
|
-
class ChatSaveError(YAICLIException):
|
38
|
-
"""Exception raised when a chat save fails"""
|
39
|
-
|
40
|
-
pass
|
41
|
-
|
42
|
-
|
43
|
-
class ChatDeleteError(YAICLIException):
|
44
|
-
"""Exception raised when a chat delete fails"""
|
45
|
-
|
46
|
-
pass
|
17
|
+
class ChatDeleteError(YaicliError):
|
18
|
+
"""Error deleting chat"""
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import shutil
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import Any
|
4
|
+
|
5
|
+
from ..console import get_console
|
6
|
+
from ..const import FUNCTIONS_DIR
|
7
|
+
from ..utils import option_callback
|
8
|
+
|
9
|
+
console = get_console()
|
10
|
+
|
11
|
+
|
12
|
+
@option_callback
|
13
|
+
def install_functions(cls, _: Any) -> None:
|
14
|
+
"""Install buildin functions"""
|
15
|
+
cur_dir = Path(__file__).absolute().parent
|
16
|
+
buildin_dir = cur_dir / "buildin"
|
17
|
+
buildin_funcs = [Path(path) for path in buildin_dir.glob("*.py")]
|
18
|
+
console.print("Installing buildin functions...")
|
19
|
+
if not FUNCTIONS_DIR.exists():
|
20
|
+
FUNCTIONS_DIR.mkdir(parents=True)
|
21
|
+
for file in buildin_funcs:
|
22
|
+
if (FUNCTIONS_DIR / file.name).exists():
|
23
|
+
# Skip if function already exists
|
24
|
+
console.print(f"Function {file.name} already exists, skipping.")
|
25
|
+
continue
|
26
|
+
shutil.copy(file, FUNCTIONS_DIR, follow_symlinks=True)
|
27
|
+
console.print(f"Installed {FUNCTIONS_DIR}/{file.name}")
|
28
|
+
|
29
|
+
|
30
|
+
@option_callback
|
31
|
+
def print_functions(cls, _: Any) -> None:
|
32
|
+
"""List all available buildin functions"""
|
33
|
+
if not FUNCTIONS_DIR.exists():
|
34
|
+
console.print("No installed functions found.")
|
35
|
+
return
|
36
|
+
for file in FUNCTIONS_DIR.glob("*.py"):
|
37
|
+
if file.name.startswith("_"):
|
38
|
+
continue
|
39
|
+
console.print(file)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import subprocess
|
2
|
+
|
3
|
+
from instructor import OpenAISchema
|
4
|
+
from pydantic import Field
|
5
|
+
|
6
|
+
|
7
|
+
class Function(OpenAISchema):
|
8
|
+
"""
|
9
|
+
Execute a shell command and return the output (result).
|
10
|
+
"""
|
11
|
+
|
12
|
+
shell_command: str = Field(
|
13
|
+
...,
|
14
|
+
json_schema_extra={
|
15
|
+
"example": "ls -la",
|
16
|
+
},
|
17
|
+
description="Shell command to execute.",
|
18
|
+
)
|
19
|
+
|
20
|
+
class Config:
|
21
|
+
title = "execute_shell_command"
|
22
|
+
|
23
|
+
@classmethod
|
24
|
+
def execute(cls, shell_command: str) -> str:
|
25
|
+
"""
|
26
|
+
Execute a shell command and return the output (result).
|
27
|
+
|
28
|
+
Args:
|
29
|
+
shell_command (str): shell command to execute.
|
30
|
+
|
31
|
+
Returns:
|
32
|
+
str: exit code and output string.
|
33
|
+
"""
|
34
|
+
# Optional security check
|
35
|
+
dangerous_commands = ["rm -rf", "mkfs", "dd"]
|
36
|
+
if any(cmd in shell_command for cmd in dangerous_commands):
|
37
|
+
return "Error: Dangerous command detected."
|
38
|
+
|
39
|
+
try:
|
40
|
+
process = subprocess.Popen(
|
41
|
+
shell_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True
|
42
|
+
)
|
43
|
+
output, _ = process.communicate()
|
44
|
+
exit_code = process.returncode
|
45
|
+
return f"Exit code: {exit_code}, Output:\n{output}"
|
46
|
+
except Exception as e:
|
47
|
+
return f"Error: {str(e)}"
|