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.
Files changed (50) hide show
  1. janito/__init__.py +1 -1
  2. janito/__main__.py +6 -204
  3. janito/callbacks.py +34 -132
  4. janito/cli/__init__.py +6 -0
  5. janito/cli/agent.py +400 -0
  6. janito/cli/app.py +94 -0
  7. janito/cli/commands.py +329 -0
  8. janito/cli/output.py +29 -0
  9. janito/cli/utils.py +22 -0
  10. janito/config.py +358 -121
  11. janito/data/instructions_template.txt +28 -0
  12. janito/token_report.py +154 -145
  13. janito/tools/__init__.py +38 -21
  14. janito/tools/bash/bash.py +84 -0
  15. janito/tools/bash/unix_persistent_bash.py +184 -0
  16. janito/tools/bash/win_persistent_bash.py +308 -0
  17. janito/tools/decorators.py +2 -13
  18. janito/tools/delete_file.py +27 -9
  19. janito/tools/fetch_webpage/__init__.py +34 -0
  20. janito/tools/fetch_webpage/chunking.py +76 -0
  21. janito/tools/fetch_webpage/core.py +155 -0
  22. janito/tools/fetch_webpage/extractors.py +276 -0
  23. janito/tools/fetch_webpage/news.py +137 -0
  24. janito/tools/fetch_webpage/utils.py +108 -0
  25. janito/tools/find_files.py +106 -44
  26. janito/tools/move_file.py +72 -0
  27. janito/tools/prompt_user.py +37 -6
  28. janito/tools/replace_file.py +31 -4
  29. janito/tools/rich_console.py +176 -0
  30. janito/tools/search_text.py +35 -22
  31. janito/tools/str_replace_editor/editor.py +7 -4
  32. janito/tools/str_replace_editor/handlers/__init__.py +16 -0
  33. janito/tools/str_replace_editor/handlers/create.py +60 -0
  34. janito/tools/str_replace_editor/handlers/insert.py +100 -0
  35. janito/tools/str_replace_editor/handlers/str_replace.py +94 -0
  36. janito/tools/str_replace_editor/handlers/undo.py +64 -0
  37. janito/tools/str_replace_editor/handlers/view.py +159 -0
  38. janito/tools/str_replace_editor/utils.py +0 -1
  39. janito/tools/usage_tracker.py +136 -0
  40. janito-0.13.0.dist-info/METADATA +300 -0
  41. janito-0.13.0.dist-info/RECORD +47 -0
  42. janito/chat_history.py +0 -117
  43. janito/data/instructions.txt +0 -4
  44. janito/tools/bash.py +0 -22
  45. janito/tools/str_replace_editor/handlers.py +0 -335
  46. janito-0.11.0.dist-info/METADATA +0 -86
  47. janito-0.11.0.dist-info/RECORD +0 -26
  48. {janito-0.11.0.dist-info → janito-0.13.0.dist-info}/WHEEL +0 -0
  49. {janito-0.11.0.dist-info → janito-0.13.0.dist-info}/entry_points.txt +0 -0
  50. {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]"