janito 0.13.0__py3-none-any.whl → 0.15.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/cli/agent/__init__.py +7 -0
- janito/cli/agent/conversation.py +149 -0
- janito/cli/agent/initialization.py +168 -0
- janito/cli/agent/query.py +112 -0
- janito/cli/agent.py +7 -395
- janito/cli/app.py +103 -19
- janito/cli/commands/__init__.py +12 -0
- janito/cli/commands/config.py +30 -0
- janito/cli/commands/history.py +119 -0
- janito/cli/commands/profile.py +93 -0
- janito/cli/commands/validation.py +24 -0
- janito/cli/commands/workspace.py +31 -0
- janito/cli/commands.py +9 -326
- janito/config/README.md +104 -0
- janito/config/__init__.py +16 -0
- janito/config/cli/__init__.py +28 -0
- janito/config/cli/commands.py +397 -0
- janito/config/cli/validators.py +77 -0
- janito/config/core/__init__.py +23 -0
- janito/config/core/file_operations.py +90 -0
- janito/config/core/properties.py +316 -0
- janito/config/core/singleton.py +282 -0
- janito/config/profiles/__init__.py +8 -0
- janito/config/profiles/definitions.py +38 -0
- janito/config/profiles/manager.py +80 -0
- janito/data/instructions_template.txt +12 -6
- janito/tools/__init__.py +8 -2
- janito/tools/bash/bash.py +80 -7
- janito/tools/bash/unix_persistent_bash.py +32 -1
- janito/tools/bash/win_persistent_bash.py +34 -1
- janito/tools/fetch_webpage/__init__.py +22 -33
- janito/tools/fetch_webpage/core.py +182 -155
- janito/tools/move_file.py +1 -1
- janito/tools/search_text.py +225 -239
- janito/tools/str_replace_editor/handlers/view.py +14 -8
- janito/tools/think.py +37 -0
- janito/tools/usage_tracker.py +1 -0
- {janito-0.13.0.dist-info → janito-0.15.0.dist-info}/METADATA +204 -23
- janito-0.15.0.dist-info/RECORD +64 -0
- janito/config.py +0 -358
- janito/test_file.py +0 -4
- janito/tools/fetch_webpage/chunking.py +0 -76
- janito/tools/fetch_webpage/extractors.py +0 -276
- janito/tools/fetch_webpage/news.py +0 -137
- janito/tools/fetch_webpage/utils.py +0 -108
- janito-0.13.0.dist-info/RECORD +0 -47
- {janito-0.13.0.dist-info → janito-0.15.0.dist-info}/WHEEL +0 -0
- {janito-0.13.0.dist-info → janito-0.15.0.dist-info}/entry_points.txt +0 -0
- {janito-0.13.0.dist-info → janito-0.15.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,119 @@
|
|
1
|
+
"""
|
2
|
+
History management functions for Janito CLI.
|
3
|
+
"""
|
4
|
+
import sys
|
5
|
+
import json
|
6
|
+
import datetime
|
7
|
+
from pathlib import Path
|
8
|
+
from typing import Optional, List, Dict, Any
|
9
|
+
import typer
|
10
|
+
from rich.console import Console
|
11
|
+
from rich.table import Table
|
12
|
+
|
13
|
+
from janito.config import get_config
|
14
|
+
|
15
|
+
console = Console()
|
16
|
+
|
17
|
+
def handle_history(history_flag: bool, history_count: Optional[int], ctx: typer.Context, query: Optional[str]) -> bool:
|
18
|
+
"""
|
19
|
+
Handle the --history parameter to display conversation history.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
history_flag: Whether to show history (--history flag)
|
23
|
+
history_count: Number of history entries to display (value after --history)
|
24
|
+
ctx: Typer context
|
25
|
+
query: Query string
|
26
|
+
|
27
|
+
Returns:
|
28
|
+
bool: True if the program should exit after this operation
|
29
|
+
"""
|
30
|
+
# Check if --history was used
|
31
|
+
if history_flag:
|
32
|
+
try:
|
33
|
+
# If --history is used with a count value passed from app.py, use that
|
34
|
+
# If no count is specified, default to 20
|
35
|
+
count = 20 if history_count is None else history_count
|
36
|
+
|
37
|
+
# Get the workspace directory
|
38
|
+
workspace_dir = Path(get_config().workspace_dir)
|
39
|
+
janito_dir = workspace_dir / ".janito"
|
40
|
+
messages_dir = janito_dir / "last_messages"
|
41
|
+
|
42
|
+
if not messages_dir.exists() or not any(messages_dir.iterdir()):
|
43
|
+
console.print("[bold yellow]⚠️ No conversation history found[/bold yellow]")
|
44
|
+
return True # Always exit after displaying history
|
45
|
+
|
46
|
+
# Find all message files and sort by timestamp (newest first)
|
47
|
+
message_files = [f for f in messages_dir.iterdir() if f.is_file() and f.suffix == '.json']
|
48
|
+
message_files.sort(key=lambda x: x.stem, reverse=True)
|
49
|
+
|
50
|
+
# Limit to the requested number of entries
|
51
|
+
message_files = message_files[:count]
|
52
|
+
|
53
|
+
# Create a table for the history
|
54
|
+
table = Table(title=f"Conversation History (Last {min(count, len(message_files))} Entries)")
|
55
|
+
table.add_column("ID", style="cyan")
|
56
|
+
table.add_column("Date", style="green")
|
57
|
+
table.add_column("Time", style="green")
|
58
|
+
table.add_column("First Query", style="yellow")
|
59
|
+
|
60
|
+
# Add rows to the table
|
61
|
+
for file in message_files:
|
62
|
+
try:
|
63
|
+
with open(file, "r", encoding="utf-8") as f:
|
64
|
+
message_object = json.load(f)
|
65
|
+
|
66
|
+
# Extract message ID and timestamp
|
67
|
+
message_id = message_object.get("id", file.stem)
|
68
|
+
|
69
|
+
# Parse timestamp
|
70
|
+
timestamp_str = message_object.get("timestamp")
|
71
|
+
if timestamp_str:
|
72
|
+
timestamp = datetime.datetime.fromisoformat(timestamp_str)
|
73
|
+
date_str = timestamp.strftime("%Y-%m-%d")
|
74
|
+
time_str = timestamp.strftime("%H:%M:%S")
|
75
|
+
else:
|
76
|
+
# Fallback to file name which is a timestamp
|
77
|
+
timestamp_str = file.stem
|
78
|
+
date_str = timestamp_str[:8] # YYYYMMDD
|
79
|
+
time_str = timestamp_str[8:] # HHMMSS
|
80
|
+
|
81
|
+
# Format the date and time
|
82
|
+
if len(date_str) == 8:
|
83
|
+
date_str = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
|
84
|
+
if len(time_str) == 6:
|
85
|
+
time_str = f"{time_str[:2]}:{time_str[2:4]}:{time_str[4:6]}"
|
86
|
+
|
87
|
+
# Extract the first user message
|
88
|
+
messages = message_object.get("messages", [])
|
89
|
+
first_query = "N/A"
|
90
|
+
for msg in messages:
|
91
|
+
if msg.get("role") == "user":
|
92
|
+
first_query = msg.get("content", "N/A")
|
93
|
+
# Truncate long queries
|
94
|
+
if len(first_query) > 60:
|
95
|
+
first_query = first_query[:57] + "..."
|
96
|
+
break
|
97
|
+
|
98
|
+
table.add_row(message_id, date_str, time_str, first_query)
|
99
|
+
except Exception as e:
|
100
|
+
table.add_row(file.stem, "Error", "Error", f"Failed to parse: {str(e)}")
|
101
|
+
|
102
|
+
console.print(table)
|
103
|
+
|
104
|
+
# Display information about how to continue conversations
|
105
|
+
console.print("\n[bold blue]💡 To continue a conversation:[/bold blue]")
|
106
|
+
script_name = "janito"
|
107
|
+
if sys.argv[0].endswith(('janito', 'janito.exe')):
|
108
|
+
console.print(f" {script_name} --continue <ID> <request>")
|
109
|
+
else:
|
110
|
+
console.print(f" python -m janito --continue <ID> <request>")
|
111
|
+
|
112
|
+
# If --history flag is used, always exit regardless of whether a query is provided
|
113
|
+
return True
|
114
|
+
|
115
|
+
except Exception as e:
|
116
|
+
console.print(f"[bold red]Error displaying history:[/bold red] {str(e)}")
|
117
|
+
return True # Exit on error
|
118
|
+
|
119
|
+
return False
|
@@ -0,0 +1,93 @@
|
|
1
|
+
"""
|
2
|
+
Profile and role management functions for Janito CLI.
|
3
|
+
"""
|
4
|
+
import sys
|
5
|
+
from typing import Optional
|
6
|
+
import typer
|
7
|
+
from rich.console import Console
|
8
|
+
|
9
|
+
from janito.config import Config
|
10
|
+
|
11
|
+
console = Console()
|
12
|
+
|
13
|
+
def handle_profile(profile: Optional[str], ctx: typer.Context, query: Optional[str], config_type: str = "session") -> bool:
|
14
|
+
"""
|
15
|
+
Handle the --profile parameter.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
profile: Profile name
|
19
|
+
ctx: Typer context
|
20
|
+
query: Query string
|
21
|
+
config_type: Type of configuration to update ("session", "local", or "global")
|
22
|
+
|
23
|
+
Returns:
|
24
|
+
bool: True if the program should exit after this operation
|
25
|
+
"""
|
26
|
+
if profile is not None:
|
27
|
+
try:
|
28
|
+
# Apply profile
|
29
|
+
config = Config()
|
30
|
+
profile_data = config.get_available_profiles()[profile.lower()]
|
31
|
+
|
32
|
+
if config_type == "session":
|
33
|
+
# Set values directly without saving
|
34
|
+
config._temperature = profile_data["temperature"]
|
35
|
+
config._profile = profile.lower()
|
36
|
+
console.print(f"[bold green]✅ Profile '{profile.lower()}' applied for this session only[/bold green]")
|
37
|
+
elif config_type in ["local", "global"]:
|
38
|
+
# Set profile in the specified configuration
|
39
|
+
config.set_profile(profile.lower(), config_type)
|
40
|
+
console.print(f"[bold green]✅ Profile '{profile.lower()}' set in {config_type} configuration[/bold green]")
|
41
|
+
else:
|
42
|
+
console.print(f"[bold red]Error:[/bold red] Invalid config_type: {config_type}")
|
43
|
+
return ctx.invoked_subcommand is None and not query
|
44
|
+
|
45
|
+
console.print(f"[dim]📝 Description: {profile_data['description']}[/dim]")
|
46
|
+
|
47
|
+
# Exit after applying profile if no other operation is requested
|
48
|
+
return ctx.invoked_subcommand is None and not query
|
49
|
+
except ValueError as e:
|
50
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
51
|
+
sys.exit(1)
|
52
|
+
|
53
|
+
return False
|
54
|
+
|
55
|
+
def handle_role(role: Optional[str], ctx: typer.Context, query: Optional[str], config_type: str = "session") -> bool:
|
56
|
+
"""
|
57
|
+
Handle the --role parameter.
|
58
|
+
|
59
|
+
Args:
|
60
|
+
role: Role name
|
61
|
+
ctx: Typer context
|
62
|
+
query: Query string
|
63
|
+
config_type: Type of configuration to update ("session", "local", or "global")
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
bool: True if the program should exit after this operation
|
67
|
+
"""
|
68
|
+
if role is not None:
|
69
|
+
try:
|
70
|
+
config = Config()
|
71
|
+
|
72
|
+
if config_type == "session":
|
73
|
+
# Set role directly without saving
|
74
|
+
config._role = role
|
75
|
+
console.print(f"[bold green]✅ Role '{role}' applied for this session only[/bold green]")
|
76
|
+
elif config_type in ["local", "global"]:
|
77
|
+
# Set role in the specified configuration
|
78
|
+
if config_type == "local":
|
79
|
+
config.role = role, "local"
|
80
|
+
else:
|
81
|
+
config.role = role, "global"
|
82
|
+
console.print(f"[bold green]✅ Role '{role}' set in {config_type} configuration[/bold green]")
|
83
|
+
else:
|
84
|
+
console.print(f"[bold red]Error:[/bold red] Invalid config_type: {config_type}")
|
85
|
+
return ctx.invoked_subcommand is None and not query
|
86
|
+
|
87
|
+
# Exit after applying role if no other operation is requested
|
88
|
+
return ctx.invoked_subcommand is None and not query
|
89
|
+
except Exception as e:
|
90
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
91
|
+
sys.exit(1)
|
92
|
+
|
93
|
+
return False
|
@@ -0,0 +1,24 @@
|
|
1
|
+
"""
|
2
|
+
Parameter validation functions for Janito CLI.
|
3
|
+
"""
|
4
|
+
import sys
|
5
|
+
from rich.console import Console
|
6
|
+
|
7
|
+
console = Console()
|
8
|
+
|
9
|
+
def validate_parameters(temperature: float) -> None:
|
10
|
+
"""
|
11
|
+
Validate temperature parameter.
|
12
|
+
|
13
|
+
Args:
|
14
|
+
temperature: Temperature value for model generation
|
15
|
+
"""
|
16
|
+
try:
|
17
|
+
if temperature < 0.0 or temperature > 1.0:
|
18
|
+
raise ValueError("Temperature must be between 0.0 and 1.0")
|
19
|
+
|
20
|
+
# We'll use this value directly in the agent initialization but we don't save it to config
|
21
|
+
# Temperature display is hidden
|
22
|
+
except ValueError as e:
|
23
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
24
|
+
sys.exit(1)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
"""
|
2
|
+
Workspace management functions for Janito CLI.
|
3
|
+
"""
|
4
|
+
import sys
|
5
|
+
from typing import Optional
|
6
|
+
from rich.console import Console
|
7
|
+
|
8
|
+
from janito.config import Config
|
9
|
+
|
10
|
+
console = Console()
|
11
|
+
|
12
|
+
def handle_workspace(workspace: Optional[str]) -> bool:
|
13
|
+
"""
|
14
|
+
Handle the --workspace parameter.
|
15
|
+
|
16
|
+
Args:
|
17
|
+
workspace: Workspace directory path
|
18
|
+
|
19
|
+
Returns:
|
20
|
+
bool: True if the program should exit after this operation
|
21
|
+
"""
|
22
|
+
if workspace:
|
23
|
+
try:
|
24
|
+
console.print(f"[bold]📂 Setting workspace directory to: {workspace}[/bold]")
|
25
|
+
Config().workspace_dir = workspace
|
26
|
+
console.print(f"[bold green]✅ Workspace directory set to: {Config().workspace_dir}[/bold green]")
|
27
|
+
except ValueError as e:
|
28
|
+
console.print(f"[bold red]Error:[/bold red] {str(e)}")
|
29
|
+
sys.exit(1)
|
30
|
+
|
31
|
+
return False
|
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
|
-
|
5
|
-
import
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
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
|
+
]
|