janito 0.12.0__py3-none-any.whl → 0.14.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 (40) hide show
  1. janito/__init__.py +1 -1
  2. janito/cli/agent/__init__.py +7 -0
  3. janito/cli/agent/conversation.py +149 -0
  4. janito/cli/agent/initialization.py +172 -0
  5. janito/cli/agent/query.py +108 -0
  6. janito/cli/agent.py +7 -282
  7. janito/cli/app.py +105 -9
  8. janito/cli/commands/__init__.py +12 -0
  9. janito/cli/commands/config.py +242 -0
  10. janito/cli/commands/history.py +119 -0
  11. janito/cli/commands/profile.py +72 -0
  12. janito/cli/commands/validation.py +24 -0
  13. janito/cli/commands/workspace.py +31 -0
  14. janito/cli/commands.py +9 -326
  15. janito/config.py +37 -0
  16. janito/data/instructions_template.txt +9 -5
  17. janito/tools/__init__.py +8 -2
  18. janito/tools/bash/bash.py +3 -1
  19. janito/tools/bash/unix_persistent_bash.py +183 -181
  20. janito/tools/bash/win_persistent_bash.py +4 -2
  21. janito/tools/fetch_webpage/__init__.py +22 -33
  22. janito/tools/fetch_webpage/core.py +182 -155
  23. janito/tools/rich_console.py +46 -9
  24. janito/tools/search_text.py +225 -238
  25. janito/tools/str_replace_editor/handlers/str_replace.py +3 -1
  26. janito/tools/str_replace_editor/handlers/view.py +14 -8
  27. janito/tools/think.py +37 -0
  28. janito/tools/usage_tracker.py +1 -0
  29. janito-0.14.0.dist-info/METADATA +396 -0
  30. janito-0.14.0.dist-info/RECORD +53 -0
  31. janito/test_file.py +0 -4
  32. janito/tools/fetch_webpage/chunking.py +0 -76
  33. janito/tools/fetch_webpage/extractors.py +0 -276
  34. janito/tools/fetch_webpage/news.py +0 -137
  35. janito/tools/fetch_webpage/utils.py +0 -108
  36. janito-0.12.0.dist-info/METADATA +0 -203
  37. janito-0.12.0.dist-info/RECORD +0 -47
  38. {janito-0.12.0.dist-info → janito-0.14.0.dist-info}/WHEEL +0 -0
  39. {janito-0.12.0.dist-info → janito-0.14.0.dist-info}/entry_points.txt +0 -0
  40. {janito-0.12.0.dist-info → janito-0.14.0.dist-info}/licenses/LICENSE +0 -0
janito/cli/commands.py CHANGED
@@ -1,329 +1,12 @@
1
1
  """
2
2
  Command handling logic for Janito CLI.
3
+ This module serves as a compatibility layer for the reorganized commands module.
3
4
  """
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: bool = False
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: Whether to continue the previous 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
5
+ # Re-export the functions from the new module structure
6
+ from janito.cli.commands import handle_config_commands, validate_parameters, handle_history
7
+
8
+ __all__ = [
9
+ "handle_config_commands",
10
+ "validate_parameters",
11
+ "handle_history",
12
+ ]
janito/config.py CHANGED
@@ -53,6 +53,8 @@ class Config:
53
53
  cls._instance._verbose = False
54
54
  # Chat history context feature has been removed
55
55
  cls._instance._ask_mode = False
56
+ cls._instance._trust_mode = False # New trust mode setting
57
+ cls._instance._no_tools = False # New no-tools mode setting
56
58
  # Set technical profile as default
57
59
  profile_data = PROFILES["technical"]
58
60
  cls._instance._temperature = profile_data["temperature"]
@@ -74,6 +76,8 @@ class Config:
74
76
  self._verbose = config_data["debug_mode"]
75
77
  if "ask_mode" in config_data:
76
78
  self._ask_mode = config_data["ask_mode"]
79
+ if "trust_mode" in config_data:
80
+ self._trust_mode = config_data["trust_mode"]
77
81
  if "temperature" in config_data:
78
82
  self._temperature = config_data["temperature"]
79
83
  if "profile" in config_data:
@@ -95,6 +99,7 @@ class Config:
95
99
  # Chat history context feature has been removed
96
100
  "verbose": self._verbose,
97
101
  "ask_mode": self._ask_mode,
102
+ # trust_mode is not saved as it's a per-session setting
98
103
  "temperature": self._temperature,
99
104
  "role": self._role
100
105
  }
@@ -265,6 +270,36 @@ class Config:
265
270
  self._ask_mode = value
266
271
  self._save_config()
267
272
 
273
+ @property
274
+ def trust_mode(self) -> bool:
275
+ """Get the trust mode status."""
276
+ return self._trust_mode
277
+
278
+ @trust_mode.setter
279
+ def trust_mode(self, value: bool) -> None:
280
+ """Set the trust mode status.
281
+
282
+ Note: This setting is not persisted to config file
283
+ as it's meant to be a per-session setting.
284
+ """
285
+ self._trust_mode = value
286
+ # Don't save to config file - this is a per-session setting
287
+
288
+ @property
289
+ def no_tools(self) -> bool:
290
+ """Get the no-tools mode status."""
291
+ return self._no_tools
292
+
293
+ @no_tools.setter
294
+ def no_tools(self, value: bool) -> None:
295
+ """Set the no-tools mode status.
296
+
297
+ Note: This setting is not persisted to config file
298
+ as it's meant to be a per-session setting.
299
+ """
300
+ self._no_tools = value
301
+ # Don't save to config file - this is a per-session setting
302
+
268
303
  @property
269
304
  def temperature(self) -> float:
270
305
  """Get the temperature value for model generation."""
@@ -323,6 +358,8 @@ class Config:
323
358
  self._verbose = False
324
359
  # Chat history context feature has been removed
325
360
  self._ask_mode = False
361
+ self._trust_mode = False
362
+ self._no_tools = False
326
363
  # Set technical profile as default
327
364
  profile_data = PROFILES["technical"]
328
365
  self._temperature = profile_data["temperature"]
@@ -1,27 +1,31 @@
1
1
  You are a {{ role }}, using the name Janito .
2
2
  You will be assisting an user using a computer system on a {{ platform }} platform.
3
3
  You can find more about the current project using the tools in the workspace directory.
4
- If the question is related to the project, use the tools using the relative path "." .
4
+ If the question is related to the project, use the tools using the relative path, filename instead of /filename.
5
5
 
6
6
  If creating or editing files with a large number of lines, organize them into smaller files.
7
7
  If creating or editing files in an existing directory check surrounding files for the used patterns.
8
8
 
9
- # Structure Discovery (.janito/docs/STRUCTURE.md)
10
- Always start exploring the project by viewing for the file .janito/docs/STRUCTURE.md.
9
+ # Structure Discovery (docs/STRUCTURE.md from current directory)
10
+ Always start exploring the project by viewing for the file docs/STRUCTURE.md.
11
11
  Do not track files or directories wich are in .gitignore in the structure.
12
12
  At the end of responding to the user, update the structure file based on the files and directories you have interacted with,
13
13
  be precise focusing on the most important files and directories, avoid adding extra information like architecture or design patterns.
14
14
 
15
-
16
15
  # Tools
17
16
  The bash tool does not support commands which will require user input.
17
+ Use the bash tool to get the current date or time when needed.
18
18
  Prefer the str_replace_editor tool to view directories and file contents.
19
19
 
20
20
  </IMPORTANT>
21
- Call the tool user_prompt when:
21
+ Call the user_prompt tool when:
22
22
  - There are multiple options to apply a certain change
23
23
  - The next operation risk is moderated or high
24
24
  - The implementation plan is complex, requiring a review
25
25
  Proceed according to the user answer.
26
26
  <IMPORTANT/>
27
27
 
28
+ When changing code in Python files, be mindful about the need to review the imports specially when new type hints are used (eg. Optional, Tuple, List, Dict, etc).
29
+ After performing changes to a project in interfaces which are exposed to the user, respond to the user with a short summary on how to verify the changes. eg. "run cmd xpto", prefer to provide a command to run instead of a description.
30
+ When displaying commands in instructions to the user, consider their platform.
31
+ When creating html pages which refer to images that should be manually placed by the user, instead of broken links provide a frame with a placeholder image.
janito/tools/__init__.py CHANGED
@@ -10,11 +10,12 @@ from .replace_file import replace_file
10
10
  from .prompt_user import prompt_user
11
11
  from .move_file import move_file
12
12
  from janito.tools.fetch_webpage import fetch_webpage
13
+ from .think import think
13
14
  from .usage_tracker import get_tracker, reset_tracker, print_usage_stats
14
15
  from janito.config import get_config
15
16
 
16
17
  __all__ = ["str_replace_editor", "find_files", "delete_file", "search_text", "replace_file",
17
- "prompt_user", "move_file", "fetch_webpage", "get_tools",
18
+ "prompt_user", "move_file", "fetch_webpage", "think", "get_tools",
18
19
  "get_tracker", "reset_tracker", "print_usage_stats"]
19
20
 
20
21
  def get_tools():
@@ -23,10 +24,15 @@ def get_tools():
23
24
 
24
25
  Returns:
25
26
  List of tool functions (excluding str_replace_editor which is passed separately)
27
+ If no_tools mode is enabled, returns an empty list
26
28
  If ask_mode is enabled, only returns tools that don't perform changes
27
29
  """
30
+ # If no_tools mode is enabled, return an empty list
31
+ if get_config().no_tools:
32
+ return []
33
+
28
34
  # Tools that only read or view but don't modify anything
29
- read_only_tools = [find_files, search_text, prompt_user, fetch_webpage]
35
+ read_only_tools = [find_files, search_text, prompt_user, fetch_webpage, think]
30
36
 
31
37
  # Tools that modify the filesystem
32
38
  write_tools = [delete_file, replace_file, move_file]
janito/tools/bash/bash.py CHANGED
@@ -34,7 +34,9 @@ def bash_tool(command: str, restart: Optional[bool] = False) -> Tuple[str, bool]
34
34
  # Import console for printing output in real-time
35
35
  from janito.tools.rich_console import console, print_info
36
36
 
37
- print_info(f"{command}", "Bash Run")
37
+ # Only print command if not in trust mode
38
+ if not get_config().trust_mode:
39
+ print_info(f"{command}", "Bash Run")
38
40
  global _bash_session
39
41
 
40
42
  # Check if in ask mode and if the command might modify files