yaicli 0.3.3__py3-none-any.whl → 0.5.0__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 +6 -3
- yaicli/chat.py +396 -0
- yaicli/cli.py +251 -251
- yaicli/client.py +385 -0
- yaicli/config.py +32 -20
- yaicli/console.py +2 -2
- yaicli/const.py +46 -21
- yaicli/entry.py +68 -39
- 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.3.3.dist-info → yaicli-0.5.0.dist-info}/METADATA +172 -132
- yaicli-0.5.0.dist-info/RECORD +24 -0
- {yaicli-0.3.3.dist-info → yaicli-0.5.0.dist-info}/entry_points.txt +1 -1
- yaicli/api.py +0 -316
- yaicli/chat_manager.py +0 -290
- yaicli/roles.py +0 -248
- yaicli-0.3.3.dist-info/RECORD +0 -20
- {yaicli-0.3.3.dist-info → yaicli-0.5.0.dist-info}/WHEEL +0 -0
- {yaicli-0.3.3.dist-info → yaicli-0.5.0.dist-info}/licenses/LICENSE +0 -0
yaicli/roles.py
DELETED
@@ -1,248 +0,0 @@
|
|
1
|
-
import json
|
2
|
-
from pathlib import Path
|
3
|
-
from typing import Any, Dict, Optional, Union
|
4
|
-
|
5
|
-
import typer
|
6
|
-
from rich.console import Console
|
7
|
-
from rich.prompt import Prompt
|
8
|
-
from rich.table import Table
|
9
|
-
|
10
|
-
from yaicli.config import cfg
|
11
|
-
from yaicli.console import get_console
|
12
|
-
from yaicli.const import DEFAULT_ROLES, ROLES_DIR, DefaultRoleNames
|
13
|
-
from yaicli.exceptions import RoleAlreadyExistsError, RoleCreationError
|
14
|
-
from yaicli.utils import detect_os, detect_shell, option_callback
|
15
|
-
|
16
|
-
|
17
|
-
class Role:
|
18
|
-
def __init__(
|
19
|
-
self, name: str, prompt: str, variables: Optional[Dict[str, Any]] = None, filepath: Optional[str] = None
|
20
|
-
):
|
21
|
-
self.name = name
|
22
|
-
self.prompt = prompt
|
23
|
-
if not variables:
|
24
|
-
variables = {"_os": detect_os(cfg), "_shell": detect_shell(cfg)}
|
25
|
-
self.variables = variables
|
26
|
-
self.filepath = filepath
|
27
|
-
|
28
|
-
self.prompt = self.prompt.format(**self.variables)
|
29
|
-
|
30
|
-
def to_dict(self) -> Dict[str, Any]:
|
31
|
-
"""Convert Role to dictionary for serialization"""
|
32
|
-
return {
|
33
|
-
"name": self.name,
|
34
|
-
"prompt": self.prompt,
|
35
|
-
}
|
36
|
-
|
37
|
-
@classmethod
|
38
|
-
def from_dict(cls, role_id: str, data: Dict[str, Any], filepath: Optional[str] = None) -> "Role":
|
39
|
-
"""Create Role object from dictionary"""
|
40
|
-
return cls(
|
41
|
-
name=data.get("name", role_id),
|
42
|
-
prompt=data.get("prompt", ""),
|
43
|
-
variables=data.get("variables", {}),
|
44
|
-
filepath=filepath,
|
45
|
-
)
|
46
|
-
|
47
|
-
def __str__(self):
|
48
|
-
return f"Role(name={self.name}, prompt={self.prompt[:30]}...)"
|
49
|
-
|
50
|
-
|
51
|
-
class RoleManager:
|
52
|
-
roles_dir: Path = ROLES_DIR
|
53
|
-
console: Console = get_console()
|
54
|
-
|
55
|
-
def __init__(self):
|
56
|
-
self.roles: Dict[str, Role] = self._load_roles()
|
57
|
-
|
58
|
-
def _load_roles(self) -> Dict[str, Role]:
|
59
|
-
"""Load all role configurations"""
|
60
|
-
roles = {}
|
61
|
-
self.roles_dir.mkdir(parents=True, exist_ok=True)
|
62
|
-
|
63
|
-
# Check if any role files exist
|
64
|
-
role_files: list[Path] = list(self.roles_dir.glob("*.json"))
|
65
|
-
|
66
|
-
if not role_files:
|
67
|
-
# Fast path: no existing roles, just create defaults
|
68
|
-
for role_id, role_config in DEFAULT_ROLES.items():
|
69
|
-
role_file = self.roles_dir / f"{role_id}.json"
|
70
|
-
filepath = str(role_file)
|
71
|
-
roles[role_id] = Role.from_dict(role_id, role_config, filepath)
|
72
|
-
with role_file.open("w", encoding="utf-8") as f:
|
73
|
-
json.dump(role_config, f, indent=2)
|
74
|
-
return roles
|
75
|
-
|
76
|
-
# Load existing role files
|
77
|
-
for role_file in role_files:
|
78
|
-
role_id = role_file.stem
|
79
|
-
filepath = str(role_file)
|
80
|
-
try:
|
81
|
-
with role_file.open("r", encoding="utf-8") as f:
|
82
|
-
role_data = json.load(f)
|
83
|
-
roles[role_id] = Role.from_dict(role_id, role_data, filepath)
|
84
|
-
except Exception as e:
|
85
|
-
self.console.print(f"Error loading role {role_id}: {e}", style="red")
|
86
|
-
|
87
|
-
# Ensure default roles exist
|
88
|
-
for role_id, role_config in DEFAULT_ROLES.items():
|
89
|
-
if role_id not in roles:
|
90
|
-
role_file = self.roles_dir / f"{role_id}.json"
|
91
|
-
filepath = str(role_file)
|
92
|
-
roles[role_id] = Role.from_dict(role_id, role_config, filepath)
|
93
|
-
with role_file.open("w", encoding="utf-8") as f:
|
94
|
-
json.dump(role_config, f, indent=2)
|
95
|
-
|
96
|
-
return roles
|
97
|
-
|
98
|
-
@classmethod
|
99
|
-
@option_callback
|
100
|
-
def print_list_option(cls, _: Any):
|
101
|
-
"""Print the list of roles.
|
102
|
-
This method is a cli option callback.
|
103
|
-
"""
|
104
|
-
table = Table(show_header=True, show_footer=False)
|
105
|
-
table.add_column("Name", style="dim")
|
106
|
-
table.add_column("Filepath", style="dim")
|
107
|
-
for file in sorted(cls.roles_dir.glob("*.json"), key=lambda f: f.stat().st_mtime):
|
108
|
-
table.add_row(file.stem, str(file))
|
109
|
-
cls.console.print(table)
|
110
|
-
cls.console.print("Use `ai --show-role <name>` to view a role.", style="dim")
|
111
|
-
|
112
|
-
def list_roles(self) -> list:
|
113
|
-
"""List all available roles info"""
|
114
|
-
roles_list = []
|
115
|
-
for role_id, role in sorted(self.roles.items()):
|
116
|
-
roles_list.append(
|
117
|
-
{
|
118
|
-
"id": role_id,
|
119
|
-
"name": role.name,
|
120
|
-
"prompt": role.prompt,
|
121
|
-
"is_default": role_id in DEFAULT_ROLES,
|
122
|
-
"filepath": role.filepath,
|
123
|
-
}
|
124
|
-
)
|
125
|
-
return roles_list
|
126
|
-
|
127
|
-
@classmethod
|
128
|
-
@option_callback
|
129
|
-
def show_role_option(cls, name: str):
|
130
|
-
"""Show a role's prompt.
|
131
|
-
This method is a cli option callback.
|
132
|
-
"""
|
133
|
-
self = cls()
|
134
|
-
role = self.get_role(name)
|
135
|
-
if not role:
|
136
|
-
self.console.print(f"Role '{name}' does not exist", style="red")
|
137
|
-
return
|
138
|
-
self.console.print(role.prompt)
|
139
|
-
|
140
|
-
def get_role(self, role_id: str) -> Optional[Role]:
|
141
|
-
"""Get role by ID"""
|
142
|
-
return self.roles.get(role_id)
|
143
|
-
|
144
|
-
@classmethod
|
145
|
-
def check_id_ok(cls, role_id: str):
|
146
|
-
"""Check if role exists by ID.
|
147
|
-
This method is a cli option callback.
|
148
|
-
If role does not exist, exit with error.
|
149
|
-
"""
|
150
|
-
if not role_id:
|
151
|
-
return role_id
|
152
|
-
self = cls()
|
153
|
-
if not self.role_exists(role_id):
|
154
|
-
self.console.print(f"Role '{role_id}' does not exist", style="red")
|
155
|
-
raise typer.Abort()
|
156
|
-
return role_id
|
157
|
-
|
158
|
-
def role_exists(self, role_id: str) -> bool:
|
159
|
-
"""Check if role exists"""
|
160
|
-
return role_id in self.roles
|
161
|
-
|
162
|
-
def save_role(self, role_id: str, role: Role) -> None:
|
163
|
-
"""Save role configuration"""
|
164
|
-
try:
|
165
|
-
self.roles[role_id] = role
|
166
|
-
role_file = self.roles_dir / f"{role_id}.json"
|
167
|
-
role.filepath = str(role_file)
|
168
|
-
with role_file.open("w", encoding="utf-8") as f:
|
169
|
-
json.dump(role.to_dict(), f, indent=2)
|
170
|
-
except Exception as e:
|
171
|
-
raise RoleCreationError(f"RoleCreationError {e}") from e
|
172
|
-
|
173
|
-
@classmethod
|
174
|
-
@option_callback
|
175
|
-
def create_role_option(cls, name: str):
|
176
|
-
"""Create a new role and save it to file.
|
177
|
-
This method is a cli option callback.
|
178
|
-
"""
|
179
|
-
self = cls()
|
180
|
-
if name in self.roles:
|
181
|
-
self.console.print(f"Role '{name}' already exists", style="yellow")
|
182
|
-
return
|
183
|
-
description = Prompt.ask("Enter role description")
|
184
|
-
|
185
|
-
# Format the prompt as "You are {role_id}, {description}"
|
186
|
-
prompt = f"You are {name}, {description}"
|
187
|
-
|
188
|
-
role = Role(name=name, prompt=prompt)
|
189
|
-
self.create_role(name, role)
|
190
|
-
self.console.print(f"Role '{name}' created successfully", style="green")
|
191
|
-
|
192
|
-
def create_role(self, role_id: str, role: Union[Role, Dict[str, Any]]) -> None:
|
193
|
-
"""Create a new role and save it to file"""
|
194
|
-
if role_id in self.roles:
|
195
|
-
raise RoleAlreadyExistsError(f"Role '{role_id}' already exists")
|
196
|
-
if isinstance(role, dict):
|
197
|
-
if "name" not in role or "prompt" not in role:
|
198
|
-
raise RoleCreationError("Role must have 'name' and 'prompt' keys")
|
199
|
-
# Convert dict to Role object
|
200
|
-
role = Role.from_dict(role_id, role)
|
201
|
-
self.save_role(role_id, role)
|
202
|
-
|
203
|
-
@classmethod
|
204
|
-
@option_callback
|
205
|
-
def delete_role_option(cls, name: str):
|
206
|
-
"""Delete a role and its file.
|
207
|
-
This method is a cli option callback.
|
208
|
-
"""
|
209
|
-
self = cls()
|
210
|
-
if self.delete_role(name):
|
211
|
-
self.console.print(f"Role '{name}' deleted successfully", style="green")
|
212
|
-
|
213
|
-
def delete_role(self, role_id: str) -> bool:
|
214
|
-
"""Delete a role and its file"""
|
215
|
-
if role_id not in self.roles:
|
216
|
-
self.console.print(f"Role '{role_id}' does not exist", style="red")
|
217
|
-
return False
|
218
|
-
|
219
|
-
# Don't allow deleting default roles
|
220
|
-
if role_id in DEFAULT_ROLES:
|
221
|
-
self.console.print(f"Cannot delete default role: '{role_id}'", style="red")
|
222
|
-
return False
|
223
|
-
|
224
|
-
try:
|
225
|
-
role = self.roles[role_id]
|
226
|
-
if role.filepath:
|
227
|
-
Path(role.filepath).unlink(missing_ok=True)
|
228
|
-
del self.roles[role_id]
|
229
|
-
return True
|
230
|
-
except Exception as e:
|
231
|
-
self.console.print(f"Error deleting role: {e}", style="red")
|
232
|
-
return False
|
233
|
-
|
234
|
-
def get_system_prompt(self, role_id: str) -> str:
|
235
|
-
"""Get prompt from file by role ID"""
|
236
|
-
role = self.get_role(role_id)
|
237
|
-
if not role:
|
238
|
-
# Fall back to default role if specified role doesn't exist
|
239
|
-
self.console.print(f"Role {role_id} not found, using default role", style="yellow")
|
240
|
-
role = self.get_role(DefaultRoleNames.DEFAULT)
|
241
|
-
if not role:
|
242
|
-
# Last resort fallback
|
243
|
-
default_config = DEFAULT_ROLES[DefaultRoleNames.DEFAULT]
|
244
|
-
role = Role.from_dict(DefaultRoleNames.DEFAULT, default_config)
|
245
|
-
|
246
|
-
# Create a copy of the role with system variables
|
247
|
-
system_role = Role(name=role.name, prompt=role.prompt)
|
248
|
-
return system_role.prompt
|
yaicli-0.3.3.dist-info/RECORD
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
pyproject.toml,sha256=gRdPPzuSEyfEEyHQ4TuoHqxrrkFhWGC9BXWY4XuOb7E,1519
|
2
|
-
yaicli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
-
yaicli/api.py,sha256=9kRozzxBKduQsda3acnxzvOD9wRLL0cH182L4ddHY8E,13666
|
4
|
-
yaicli/chat_manager.py,sha256=I7BAMz91FLYT6x69wbomtAGLx0WsoTwS4Wo0MgP6P9I,10644
|
5
|
-
yaicli/cli.py,sha256=mw4aeDAEcD0KvbbOxPuripqCY17vEmIeuT2ZcWjK92o,22795
|
6
|
-
yaicli/config.py,sha256=xtzgXApM93zCqSUxmVSBdph0co_NKfEUU3hWtPe8qvM,6236
|
7
|
-
yaicli/console.py,sha256=291F4hGksJtxYpg_mehepCIJ-eB2MaDNIyv1JAMgJ1Y,1985
|
8
|
-
yaicli/const.py,sha256=iOQNG6M4EBmKgbwZdNqRsHrcQ7Od1nKOyLAqUhfMEBM,7020
|
9
|
-
yaicli/entry.py,sha256=Yp0Z--x-7dowrz-h8hJJ4_BoCzuDjS11NcM8YgFzUoY,7460
|
10
|
-
yaicli/exceptions.py,sha256=ndedSdE0uaxxHrWN944BkbhMfRMSMxGDfmqmCKCGJco,924
|
11
|
-
yaicli/history.py,sha256=s-57X9FMsaQHF7XySq1gGH_jpd_cHHTYafYu2ECuG6M,2472
|
12
|
-
yaicli/printer.py,sha256=nXpralD5qZJQga3OTdEPhj22g7UoF-4mJbZeOtWXojo,12430
|
13
|
-
yaicli/render.py,sha256=mB1OT9859_PTwI9f-KY802lPaeQXKRw6ls_5jN21jWc,511
|
14
|
-
yaicli/roles.py,sha256=bhXpLnGTPRZp3-K1Tt6ppTsuG2v9S0RAXikfMFhDs_U,9144
|
15
|
-
yaicli/utils.py,sha256=MLvb-C5n19AD9Z1nW4Z3Z43ZKNH8STxQmNDnL7mq26E,4490
|
16
|
-
yaicli-0.3.3.dist-info/METADATA,sha256=CdEkOsFz76sEp75xvEf6lVFNAx7U7ff_yylLP-0ETRc,45320
|
17
|
-
yaicli-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
18
|
-
yaicli-0.3.3.dist-info/entry_points.txt,sha256=iMhGm3btBaqrknQoF6WCg5sdx69ZyNSC73tRpCcbcLw,63
|
19
|
-
yaicli-0.3.3.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
20
|
-
yaicli-0.3.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|