janito 0.11.0__py3-none-any.whl → 0.13.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.
- janito/__init__.py +1 -1
- janito/__main__.py +6 -204
- janito/callbacks.py +34 -132
- janito/cli/__init__.py +6 -0
- janito/cli/agent.py +400 -0
- janito/cli/app.py +94 -0
- janito/cli/commands.py +329 -0
- janito/cli/output.py +29 -0
- janito/cli/utils.py +22 -0
- janito/config.py +358 -121
- janito/data/instructions_template.txt +28 -0
- janito/token_report.py +154 -145
- janito/tools/__init__.py +38 -21
- janito/tools/bash/bash.py +84 -0
- janito/tools/bash/unix_persistent_bash.py +184 -0
- janito/tools/bash/win_persistent_bash.py +308 -0
- janito/tools/decorators.py +2 -13
- janito/tools/delete_file.py +27 -9
- janito/tools/fetch_webpage/__init__.py +34 -0
- janito/tools/fetch_webpage/chunking.py +76 -0
- janito/tools/fetch_webpage/core.py +155 -0
- janito/tools/fetch_webpage/extractors.py +276 -0
- janito/tools/fetch_webpage/news.py +137 -0
- janito/tools/fetch_webpage/utils.py +108 -0
- janito/tools/find_files.py +106 -44
- janito/tools/move_file.py +72 -0
- janito/tools/prompt_user.py +37 -6
- janito/tools/replace_file.py +31 -4
- janito/tools/rich_console.py +176 -0
- janito/tools/search_text.py +35 -22
- janito/tools/str_replace_editor/editor.py +7 -4
- janito/tools/str_replace_editor/handlers/__init__.py +16 -0
- janito/tools/str_replace_editor/handlers/create.py +60 -0
- janito/tools/str_replace_editor/handlers/insert.py +100 -0
- janito/tools/str_replace_editor/handlers/str_replace.py +94 -0
- janito/tools/str_replace_editor/handlers/undo.py +64 -0
- janito/tools/str_replace_editor/handlers/view.py +159 -0
- janito/tools/str_replace_editor/utils.py +0 -1
- janito/tools/usage_tracker.py +136 -0
- janito-0.13.0.dist-info/METADATA +300 -0
- janito-0.13.0.dist-info/RECORD +47 -0
- janito/chat_history.py +0 -117
- janito/data/instructions.txt +0 -4
- janito/tools/bash.py +0 -22
- janito/tools/str_replace_editor/handlers.py +0 -335
- janito-0.11.0.dist-info/METADATA +0 -86
- janito-0.11.0.dist-info/RECORD +0 -26
- {janito-0.11.0.dist-info → janito-0.13.0.dist-info}/WHEEL +0 -0
- {janito-0.11.0.dist-info → janito-0.13.0.dist-info}/entry_points.txt +0 -0
- {janito-0.11.0.dist-info → janito-0.13.0.dist-info}/licenses/LICENSE +0 -0
janito/cli/commands.py
ADDED
@@ -0,0 +1,329 @@
|
|
1
|
+
"""
|
2
|
+
Command handling logic for Janito CLI.
|
3
|
+
"""
|
4
|
+
import sys
|
5
|
+
import os
|
6
|
+
from typing import Optional, Tuple, Any
|
7
|
+
from pathlib import Path
|
8
|
+
import typer
|
9
|
+
from rich.console import Console
|
10
|
+
|
11
|
+
from janito.config import get_config, Config
|
12
|
+
|
13
|
+
console = Console()
|
14
|
+
|
15
|
+
def validate_parameters(temperature: float) -> None:
|
16
|
+
"""
|
17
|
+
Validate temperature parameter.
|
18
|
+
|
19
|
+
Args:
|
20
|
+
temperature: Temperature value for model generation
|
21
|
+
"""
|
22
|
+
try:
|
23
|
+
if temperature < 0.0 or temperature > 1.0:
|
24
|
+
raise ValueError("Temperature must be between 0.0 and 1.0")
|
25
|
+
|
26
|
+
# We'll use this value directly in the agent initialization but we don't save it to config
|
27
|
+
# Temperature display is hidden
|
28
|
+
except ValueError as e:
|
29
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
30
|
+
sys.exit(1)
|
31
|
+
|
32
|
+
def handle_reset_config(reset_config: bool, ctx: typer.Context, query: Optional[str]) -> bool:
|
33
|
+
"""
|
34
|
+
Handle the --reset-config parameter.
|
35
|
+
|
36
|
+
Args:
|
37
|
+
reset_config: Whether to reset the configuration
|
38
|
+
ctx: Typer context
|
39
|
+
query: Query string
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
bool: True if the program should exit after this operation
|
43
|
+
"""
|
44
|
+
if reset_config:
|
45
|
+
try:
|
46
|
+
config_path = Path(get_config().workspace_dir) / ".janito" / "config.json"
|
47
|
+
if get_config().reset_config():
|
48
|
+
console.print(f"[bold green]✅ Configuration file removed: {config_path}[/bold green]")
|
49
|
+
else:
|
50
|
+
console.print(f"[bold yellow]⚠️ Configuration file does not exist: {config_path}[/bold yellow]")
|
51
|
+
except Exception as e:
|
52
|
+
console.print(f"[bold red]Error removing configuration file:[/bold red] {str(e)}")
|
53
|
+
|
54
|
+
# Exit after resetting config if no other operation is requested
|
55
|
+
return ctx.invoked_subcommand is None and not query
|
56
|
+
|
57
|
+
return False
|
58
|
+
|
59
|
+
def handle_workspace(workspace: Optional[str]) -> bool:
|
60
|
+
"""
|
61
|
+
Handle the --workspace parameter.
|
62
|
+
|
63
|
+
Args:
|
64
|
+
workspace: Workspace directory path
|
65
|
+
|
66
|
+
Returns:
|
67
|
+
bool: True if the program should exit after this operation
|
68
|
+
"""
|
69
|
+
if workspace:
|
70
|
+
try:
|
71
|
+
console.print(f"[bold]📂 Setting workspace directory to: {workspace}[/bold]")
|
72
|
+
get_config().workspace_dir = workspace
|
73
|
+
console.print(f"[bold green]✅ Workspace directory set to: {get_config().workspace_dir}[/bold green]")
|
74
|
+
except ValueError as e:
|
75
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
76
|
+
sys.exit(1)
|
77
|
+
|
78
|
+
return False
|
79
|
+
|
80
|
+
def handle_show_config(show_config: bool, ctx: typer.Context, query: Optional[str]) -> bool:
|
81
|
+
"""
|
82
|
+
Handle the --show-config parameter.
|
83
|
+
|
84
|
+
Args:
|
85
|
+
show_config: Whether to show the configuration
|
86
|
+
ctx: Typer context
|
87
|
+
query: Query string
|
88
|
+
|
89
|
+
Returns:
|
90
|
+
bool: True if the program should exit after this operation
|
91
|
+
"""
|
92
|
+
if show_config:
|
93
|
+
config = get_config()
|
94
|
+
console.print("[bold blue]⚙️ Current Configuration:[/bold blue]")
|
95
|
+
console.print(f"[bold]📁 Local Configuration File:[/bold] .janito/config.json")
|
96
|
+
console.print(f"[bold]🏠 Global Configuration File:[/bold] {Path.home() / '.janito' / 'config.json'}")
|
97
|
+
|
98
|
+
# Show API key status
|
99
|
+
api_key_global = Config.get_api_key()
|
100
|
+
api_key_env = os.environ.get("ANTHROPIC_API_KEY")
|
101
|
+
if api_key_global:
|
102
|
+
console.print(f"[bold]🔑 API Key:[/bold] [green]Set in global config[/green]")
|
103
|
+
elif api_key_env:
|
104
|
+
console.print(f"[bold]🔑 API Key:[/bold] [yellow]Set in environment variable[/yellow]")
|
105
|
+
else:
|
106
|
+
console.print(f"[bold]🔑 API Key:[/bold] [red]Not set[/red]")
|
107
|
+
|
108
|
+
console.print(f"[bold]🔊 Verbose Mode:[/bold] {'Enabled' if config.verbose else 'Disabled'}")
|
109
|
+
console.print(f"[bold]❓ Ask Mode:[/bold] {'Enabled' if config.ask_mode else 'Disabled'}")
|
110
|
+
|
111
|
+
console.print(f"[bold]👤 Role:[/bold] {config.role}")
|
112
|
+
|
113
|
+
# Show profile information if one is set
|
114
|
+
if config.profile:
|
115
|
+
profile_data = config.get_available_profiles()[config.profile]
|
116
|
+
console.print(f"[bold]📋 Active Profile:[/bold] {config.profile} - {profile_data['description']}")
|
117
|
+
|
118
|
+
# Show available profiles
|
119
|
+
profiles = config.get_available_profiles()
|
120
|
+
if profiles:
|
121
|
+
console.print("\n[bold blue]📋 Available Parameter Profiles:[/bold blue]")
|
122
|
+
for name, data in profiles.items():
|
123
|
+
console.print(f"[bold]🔹 {name}[/bold] - {data['description']}")
|
124
|
+
|
125
|
+
# Exit if this was the only operation requested
|
126
|
+
return ctx.invoked_subcommand is None and not query
|
127
|
+
|
128
|
+
return False
|
129
|
+
|
130
|
+
def handle_profile(profile: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
|
131
|
+
"""
|
132
|
+
Handle the --profile parameter.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
profile: Profile name
|
136
|
+
ctx: Typer context
|
137
|
+
query: Query string
|
138
|
+
|
139
|
+
Returns:
|
140
|
+
bool: True if the program should exit after this operation
|
141
|
+
"""
|
142
|
+
if profile is not None:
|
143
|
+
try:
|
144
|
+
# Apply profile without saving to config
|
145
|
+
config = get_config()
|
146
|
+
profile_data = config.get_available_profiles()[profile.lower()]
|
147
|
+
|
148
|
+
# Set values directly without saving
|
149
|
+
config._temperature = profile_data["temperature"]
|
150
|
+
config._profile = profile.lower()
|
151
|
+
|
152
|
+
console.print(f"[bold green]✅ Profile '{profile.lower()}' applied for this session only[/bold green]")
|
153
|
+
console.print(f"[dim]📝 Description: {profile_data['description']}[/dim]")
|
154
|
+
|
155
|
+
# Exit after applying profile if no other operation is requested
|
156
|
+
return ctx.invoked_subcommand is None and not query
|
157
|
+
except ValueError as e:
|
158
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
159
|
+
sys.exit(1)
|
160
|
+
|
161
|
+
return False
|
162
|
+
|
163
|
+
def handle_role(role: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
|
164
|
+
"""
|
165
|
+
Handle the --role parameter.
|
166
|
+
|
167
|
+
Args:
|
168
|
+
role: Role name
|
169
|
+
ctx: Typer context
|
170
|
+
query: Query string
|
171
|
+
|
172
|
+
Returns:
|
173
|
+
bool: True if the program should exit after this operation
|
174
|
+
"""
|
175
|
+
if role is not None:
|
176
|
+
try:
|
177
|
+
# Set role directly without saving to config
|
178
|
+
config = get_config()
|
179
|
+
config._role = role
|
180
|
+
|
181
|
+
console.print(f"[bold green]✅ Role '{role}' applied for this session only[/bold green]")
|
182
|
+
|
183
|
+
# Exit after applying role if no other operation is requested
|
184
|
+
return ctx.invoked_subcommand is None and not query
|
185
|
+
except Exception as e:
|
186
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
187
|
+
sys.exit(1)
|
188
|
+
|
189
|
+
return False
|
190
|
+
|
191
|
+
def handle_set_api_key(set_api_key: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
|
192
|
+
"""
|
193
|
+
Handle the --set-api-key parameter.
|
194
|
+
|
195
|
+
Args:
|
196
|
+
set_api_key: API key
|
197
|
+
ctx: Typer context
|
198
|
+
query: Query string
|
199
|
+
|
200
|
+
Returns:
|
201
|
+
bool: True if the program should exit after this operation
|
202
|
+
"""
|
203
|
+
if set_api_key is not None:
|
204
|
+
try:
|
205
|
+
Config.set_api_key(set_api_key)
|
206
|
+
console.print(f"[bold green]✅ API key saved to global configuration[/bold green]")
|
207
|
+
console.print(f"[dim]📁 Location: {Path.home() / '.janito' / 'config.json'}[/dim]")
|
208
|
+
|
209
|
+
# Exit after setting API key if no other operation is requested
|
210
|
+
return ctx.invoked_subcommand is None and not query
|
211
|
+
except Exception as e:
|
212
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
213
|
+
sys.exit(1)
|
214
|
+
|
215
|
+
return False
|
216
|
+
|
217
|
+
def handle_set_config(config_str: Optional[str], ctx: typer.Context, query: Optional[str]) -> bool:
|
218
|
+
"""
|
219
|
+
Handle the --set-config parameter.
|
220
|
+
|
221
|
+
Args:
|
222
|
+
config_str: Configuration string in format 'key=value'
|
223
|
+
ctx: Typer context
|
224
|
+
query: Query string
|
225
|
+
|
226
|
+
Returns:
|
227
|
+
bool: True if the program should exit after this operation
|
228
|
+
"""
|
229
|
+
if config_str is not None:
|
230
|
+
try:
|
231
|
+
# Parse the config string
|
232
|
+
config_parts = config_str.split("=", 1)
|
233
|
+
if len(config_parts) != 2:
|
234
|
+
console.print(f"[bold red]Error:[/bold red] Invalid configuration format. Use 'key=value' format.")
|
235
|
+
return ctx.invoked_subcommand is None and not query
|
236
|
+
|
237
|
+
key = config_parts[0].strip()
|
238
|
+
value = config_parts[1].strip()
|
239
|
+
|
240
|
+
# Remove quotes if present
|
241
|
+
if (value.startswith("'") and value.endswith("'")) or \
|
242
|
+
(value.startswith('"') and value.endswith('"')):
|
243
|
+
value = value[1:-1]
|
244
|
+
|
245
|
+
if key == "profile":
|
246
|
+
try:
|
247
|
+
get_config().set_profile(value)
|
248
|
+
profile_data = get_config().get_available_profiles()[value.lower()]
|
249
|
+
console.print(f"[bold green]✅ Profile set to '{value.lower()}'[/bold green]")
|
250
|
+
console.print(f"[dim]📝 Description: {profile_data['description']}[/dim]")
|
251
|
+
except ValueError as e:
|
252
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
253
|
+
elif key == "temperature":
|
254
|
+
try:
|
255
|
+
temp_value = float(value)
|
256
|
+
if temp_value < 0.0 or temp_value > 1.0:
|
257
|
+
console.print("[bold red]Error:[/bold red] Temperature must be between 0.0 and 1.0")
|
258
|
+
return ctx.invoked_subcommand is None and not query
|
259
|
+
|
260
|
+
get_config().temperature = temp_value
|
261
|
+
console.print(f"[bold green]✅ Temperature set to {temp_value} and saved to configuration[/bold green]")
|
262
|
+
except ValueError:
|
263
|
+
console.print(f"[bold red]Error:[/bold red] Invalid temperature value: {value}. Must be a float between 0.0 and 1.0.")
|
264
|
+
# top_k and top_p are now only accessible through profiles
|
265
|
+
elif key == "role":
|
266
|
+
get_config().role = value
|
267
|
+
console.print(f"[bold green]✅ Role set to '{value}' and saved to configuration[/bold green]")
|
268
|
+
else:
|
269
|
+
console.print(f"[bold yellow]Warning:[/bold yellow] Unsupported configuration key: {key}")
|
270
|
+
|
271
|
+
# Exit after applying config changes if no other operation is requested
|
272
|
+
return ctx.invoked_subcommand is None and not query
|
273
|
+
except Exception as e:
|
274
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
275
|
+
|
276
|
+
return False
|
277
|
+
|
278
|
+
def handle_config_commands(
|
279
|
+
ctx: typer.Context,
|
280
|
+
reset_config: bool,
|
281
|
+
workspace: Optional[str],
|
282
|
+
show_config: bool,
|
283
|
+
profile: Optional[str],
|
284
|
+
role: Optional[str],
|
285
|
+
set_api_key: Optional[str],
|
286
|
+
config_str: Optional[str],
|
287
|
+
query: Optional[str],
|
288
|
+
continue_conversation: Optional[str] = None
|
289
|
+
) -> bool:
|
290
|
+
"""
|
291
|
+
Handle all configuration-related commands.
|
292
|
+
|
293
|
+
Args:
|
294
|
+
ctx: Typer context
|
295
|
+
reset_config: Whether to reset the configuration
|
296
|
+
workspace: Workspace directory path
|
297
|
+
show_config: Whether to show the configuration
|
298
|
+
profile: Profile name
|
299
|
+
role: Role name
|
300
|
+
set_api_key: API key
|
301
|
+
config_str: Configuration string in format 'key=value'
|
302
|
+
query: Query string
|
303
|
+
continue_conversation: Optional message ID to continue a specific conversation
|
304
|
+
|
305
|
+
Returns:
|
306
|
+
bool: True if the program should exit after these operations
|
307
|
+
"""
|
308
|
+
# Handle each command and check if we should exit after it
|
309
|
+
if handle_reset_config(reset_config, ctx, query):
|
310
|
+
return True
|
311
|
+
|
312
|
+
handle_workspace(workspace)
|
313
|
+
|
314
|
+
if handle_show_config(show_config, ctx, query):
|
315
|
+
return True
|
316
|
+
|
317
|
+
if handle_profile(profile, ctx, query):
|
318
|
+
return True
|
319
|
+
|
320
|
+
if handle_role(role, ctx, query):
|
321
|
+
return True
|
322
|
+
|
323
|
+
if handle_set_api_key(set_api_key, ctx, query):
|
324
|
+
return True
|
325
|
+
|
326
|
+
if handle_set_config(config_str, ctx, query):
|
327
|
+
return True
|
328
|
+
|
329
|
+
return False
|
janito/cli/output.py
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
"""
|
2
|
+
Output formatting and display for Janito CLI.
|
3
|
+
"""
|
4
|
+
from rich.console import Console
|
5
|
+
from janito.config import get_config
|
6
|
+
|
7
|
+
console = Console()
|
8
|
+
|
9
|
+
def display_generation_params(
|
10
|
+
temp_to_use: float,
|
11
|
+
profile_data: dict = None,
|
12
|
+
temperature: float = 0.0
|
13
|
+
) -> None:
|
14
|
+
"""
|
15
|
+
Display generation parameters in verbose mode.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
temp_to_use: The temperature value being used
|
19
|
+
profile_data: The profile data if a profile is being used
|
20
|
+
temperature: The temperature value from command line
|
21
|
+
"""
|
22
|
+
# Show profile information if one is active
|
23
|
+
config = get_config()
|
24
|
+
if config.profile:
|
25
|
+
if not profile_data:
|
26
|
+
profile_data = config.get_available_profiles()[config.profile]
|
27
|
+
console.print(f"[dim]👤 Using profile: {config.profile} - {profile_data['description']}[/dim]")
|
28
|
+
|
29
|
+
# Temperature, top_k, and top_p information is hidden
|
janito/cli/utils.py
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
"""
|
2
|
+
Utility functions for the CLI module.
|
3
|
+
"""
|
4
|
+
import platform
|
5
|
+
from rich.console import Console
|
6
|
+
|
7
|
+
console = Console()
|
8
|
+
|
9
|
+
def get_stdin_termination_hint():
|
10
|
+
"""
|
11
|
+
Returns a user-friendly message about how to terminate stdin input
|
12
|
+
based on the current platform.
|
13
|
+
|
14
|
+
Returns:
|
15
|
+
str: A message with the key sequence to terminate stdin input
|
16
|
+
"""
|
17
|
+
system = platform.system()
|
18
|
+
|
19
|
+
if system == "Windows":
|
20
|
+
return "[bold yellow]Press Ctrl+Z followed by Enter to terminate input[/bold yellow]"
|
21
|
+
else: # Unix-like systems (Linux, macOS)
|
22
|
+
return "[bold yellow]Press Ctrl+D to terminate input[/bold yellow]"
|