janito 1.5.2__py3-none-any.whl → 1.6.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 +0 -1
- janito/agent/config.py +11 -10
- janito/agent/config_defaults.py +3 -2
- janito/agent/conversation.py +93 -119
- janito/agent/conversation_api.py +98 -0
- janito/agent/conversation_exceptions.py +12 -0
- janito/agent/conversation_tool_calls.py +22 -0
- janito/agent/conversation_ui.py +17 -0
- janito/agent/message_handler.py +8 -9
- janito/agent/{agent.py → openai_client.py} +48 -16
- janito/agent/openai_schema_generator.py +53 -37
- janito/agent/profile_manager.py +172 -0
- janito/agent/queued_message_handler.py +13 -14
- janito/agent/rich_live.py +32 -0
- janito/agent/rich_message_handler.py +64 -0
- janito/agent/runtime_config.py +6 -1
- janito/agent/{tools/tool_base.py → tool_base.py} +15 -8
- janito/agent/tool_registry.py +118 -132
- janito/agent/tools/__init__.py +41 -2
- janito/agent/tools/ask_user.py +43 -33
- janito/agent/tools/create_directory.py +18 -16
- janito/agent/tools/create_file.py +31 -36
- janito/agent/tools/fetch_url.py +23 -19
- janito/agent/tools/find_files.py +40 -36
- janito/agent/tools/get_file_outline.py +100 -22
- janito/agent/tools/get_lines.py +40 -32
- janito/agent/tools/gitignore_utils.py +9 -6
- janito/agent/tools/move_file.py +22 -13
- janito/agent/tools/py_compile_file.py +40 -0
- janito/agent/tools/remove_directory.py +34 -24
- janito/agent/tools/remove_file.py +22 -20
- janito/agent/tools/replace_file.py +51 -0
- janito/agent/tools/replace_text_in_file.py +69 -42
- janito/agent/tools/rich_live.py +9 -2
- janito/agent/tools/run_bash_command.py +155 -107
- janito/agent/tools/run_python_command.py +139 -0
- janito/agent/tools/search_files.py +51 -34
- janito/agent/tools/tools_utils.py +4 -2
- janito/agent/tools/utils.py +6 -2
- janito/cli/_print_config.py +42 -16
- janito/cli/_utils.py +1 -0
- janito/cli/arg_parser.py +182 -29
- janito/cli/config_commands.py +54 -22
- janito/cli/logging_setup.py +9 -3
- janito/cli/main.py +11 -10
- janito/cli/runner/__init__.py +2 -0
- janito/cli/runner/cli_main.py +148 -0
- janito/cli/runner/config.py +33 -0
- janito/cli/runner/formatting.py +12 -0
- janito/cli/runner/scan.py +44 -0
- janito/cli_chat_shell/__init__.py +0 -1
- janito/cli_chat_shell/chat_loop.py +71 -92
- janito/cli_chat_shell/chat_state.py +38 -0
- janito/cli_chat_shell/chat_ui.py +43 -0
- janito/cli_chat_shell/commands/__init__.py +45 -0
- janito/cli_chat_shell/commands/config.py +22 -0
- janito/cli_chat_shell/commands/history_reset.py +29 -0
- janito/cli_chat_shell/commands/session.py +48 -0
- janito/cli_chat_shell/commands/session_control.py +12 -0
- janito/cli_chat_shell/commands/system.py +73 -0
- janito/cli_chat_shell/commands/utility.py +29 -0
- janito/cli_chat_shell/config_shell.py +39 -10
- janito/cli_chat_shell/load_prompt.py +5 -2
- janito/cli_chat_shell/session_manager.py +24 -27
- janito/cli_chat_shell/ui.py +75 -40
- janito/rich_utils.py +15 -2
- janito/web/__main__.py +10 -2
- janito/web/app.py +88 -52
- {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/METADATA +76 -11
- janito-1.6.0.dist-info/RECORD +81 -0
- {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/WHEEL +1 -1
- janito/agent/rich_tool_handler.py +0 -43
- janito/agent/templates/system_instructions.j2 +0 -38
- janito/agent/tool_auto_imports.py +0 -5
- janito/agent/tools/append_text_to_file.py +0 -41
- janito/agent/tools/py_compile.py +0 -39
- janito/agent/tools/python_exec.py +0 -83
- janito/cli/runner.py +0 -137
- janito/cli_chat_shell/commands.py +0 -204
- janito/render_prompt.py +0 -13
- janito-1.5.2.dist-info/RECORD +0 -66
- {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/entry_points.txt +0 -0
- {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/licenses/LICENSE +0 -0
- {janito-1.5.2.dist-info → janito-1.6.0.dist-info}/top_level.txt +0 -0
janito/cli/logging_setup.py
CHANGED
@@ -7,7 +7,9 @@ def setup_verbose_logging(args):
|
|
7
7
|
httpx_logger = logging.getLogger("httpx")
|
8
8
|
httpx_logger.setLevel(logging.DEBUG)
|
9
9
|
handler = logging.StreamHandler()
|
10
|
-
handler.setFormatter(
|
10
|
+
handler.setFormatter(
|
11
|
+
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
12
|
+
)
|
11
13
|
httpx_logger.addHandler(handler)
|
12
14
|
|
13
15
|
if args.verbose_http_raw:
|
@@ -16,12 +18,16 @@ def setup_verbose_logging(args):
|
|
16
18
|
httpcore_logger = logging.getLogger("httpcore")
|
17
19
|
httpcore_logger.setLevel(logging.DEBUG)
|
18
20
|
handler_core = logging.StreamHandler()
|
19
|
-
handler_core.setFormatter(
|
21
|
+
handler_core.setFormatter(
|
22
|
+
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
23
|
+
)
|
20
24
|
httpcore_logger.addHandler(handler_core)
|
21
25
|
|
22
26
|
# Re-add handler to httpx logger in case
|
23
27
|
httpx_logger = logging.getLogger("httpx")
|
24
28
|
httpx_logger.setLevel(logging.DEBUG)
|
25
29
|
handler = logging.StreamHandler()
|
26
|
-
handler.setFormatter(
|
30
|
+
handler.setFormatter(
|
31
|
+
logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
|
32
|
+
)
|
27
33
|
httpx_logger.addHandler(handler)
|
janito/cli/main.py
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
"""Main CLI entry point for Janito."""
|
2
2
|
|
3
|
-
import janito.agent.tool_auto_imports
|
4
3
|
from janito.cli.arg_parser import create_parser
|
5
4
|
from janito.cli.config_commands import handle_config_commands
|
6
5
|
from janito.cli.logging_setup import setup_verbose_logging
|
7
6
|
from janito.cli.runner import run_cli
|
8
7
|
|
8
|
+
# Ensure all tools are registered at startup
|
9
|
+
import janito.agent.tools # noqa: F401
|
10
|
+
|
9
11
|
|
10
12
|
def main():
|
11
|
-
"""
|
13
|
+
"""Unified entry point for the Janito CLI and web server."""
|
14
|
+
import sys
|
12
15
|
|
13
|
-
Parses command-line arguments, handles config commands, sets up logging,
|
14
|
-
and launches either the CLI chat shell or the web server.
|
15
|
-
"""
|
16
|
-
# Ensure configs are loaded once at CLI startup
|
17
16
|
from janito.agent.config import local_config, global_config
|
17
|
+
|
18
18
|
local_config.load()
|
19
19
|
global_config.load()
|
20
20
|
|
21
21
|
parser = create_parser()
|
22
22
|
args = parser.parse_args()
|
23
23
|
|
24
|
-
from janito.agent.config import CONFIG_OPTIONS
|
24
|
+
from janito.agent.config import CONFIG_OPTIONS
|
25
25
|
from janito.agent.config_defaults import CONFIG_DEFAULTS
|
26
|
-
|
26
|
+
|
27
27
|
if getattr(args, "help_config", False):
|
28
28
|
print("Available configuration options:\n")
|
29
29
|
for key, desc in CONFIG_OPTIONS.items():
|
@@ -33,8 +33,9 @@ def main():
|
|
33
33
|
|
34
34
|
handle_config_commands(args)
|
35
35
|
setup_verbose_logging(args)
|
36
|
-
if getattr(args,
|
36
|
+
if getattr(args, "web", False):
|
37
37
|
import subprocess # Only needed if launching web
|
38
|
-
|
38
|
+
|
39
|
+
subprocess.run([sys.executable, "-m", "janito.web"])
|
39
40
|
else:
|
40
41
|
run_cli(args)
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import sys
|
2
|
+
import os
|
3
|
+
from rich.console import Console
|
4
|
+
from janito.agent.profile_manager import AgentProfileManager
|
5
|
+
from janito.agent.runtime_config import unified_config, runtime_config
|
6
|
+
from janito.agent.config import get_api_key
|
7
|
+
from janito import __version__
|
8
|
+
from .formatting import format_tokens
|
9
|
+
from .scan import scan_project
|
10
|
+
from .config import get_system_prompt_template
|
11
|
+
from janito.agent.conversation_exceptions import (
|
12
|
+
MaxRoundsExceededError,
|
13
|
+
EmptyResponseError,
|
14
|
+
ProviderError,
|
15
|
+
)
|
16
|
+
|
17
|
+
def run_cli(args):
|
18
|
+
if args.version:
|
19
|
+
print(f"janito version {__version__}")
|
20
|
+
sys.exit(0)
|
21
|
+
|
22
|
+
# --scan: auto-detect tech/skills and save to .janito/tech.txt
|
23
|
+
if getattr(args, "scan", False):
|
24
|
+
scan_project()
|
25
|
+
sys.exit(0)
|
26
|
+
|
27
|
+
# Check for .janito/tech.txt and print a tip if missing
|
28
|
+
tech_txt_path = os.path.join(".janito", "tech.txt")
|
29
|
+
if not os.path.exists(tech_txt_path):
|
30
|
+
print("⚠️ No tech.txt found in .janito.")
|
31
|
+
print(
|
32
|
+
"💡 Tip: Run with --scan first to auto-detect project tech/skills and improve results."
|
33
|
+
)
|
34
|
+
|
35
|
+
role = args.role or unified_config.get("role", "software engineer")
|
36
|
+
|
37
|
+
# Ensure runtime_config is updated so chat shell sees the role
|
38
|
+
if args.role:
|
39
|
+
runtime_config.set("role", args.role)
|
40
|
+
|
41
|
+
# Set runtime_config['model'] if --model is provided (highest priority, session only)
|
42
|
+
if getattr(args, "model", None):
|
43
|
+
runtime_config.set("model", args.model)
|
44
|
+
|
45
|
+
# Set runtime_config['max_tools'] if --max-tools is provided
|
46
|
+
if getattr(args, "max_tools", None) is not None:
|
47
|
+
runtime_config.set("max_tools", args.max_tools)
|
48
|
+
|
49
|
+
# Set trust-tools mode if enabled
|
50
|
+
if getattr(args, "trust_tools", False):
|
51
|
+
runtime_config.set("trust_tools", True)
|
52
|
+
|
53
|
+
# Get system prompt template (instructions/config logic)
|
54
|
+
system_prompt_template = get_system_prompt_template(args, role)
|
55
|
+
|
56
|
+
if args.show_system:
|
57
|
+
api_key = get_api_key()
|
58
|
+
model = unified_config.get("model")
|
59
|
+
print("Model:", model)
|
60
|
+
print("Parameters: {}")
|
61
|
+
print(
|
62
|
+
"System Prompt Template:",
|
63
|
+
system_prompt_template or "(default system prompt template not provided)",
|
64
|
+
)
|
65
|
+
sys.exit(0)
|
66
|
+
|
67
|
+
api_key = get_api_key()
|
68
|
+
model = unified_config.get("model")
|
69
|
+
base_url = unified_config.get("base_url", "https://openrouter.ai/api/v1")
|
70
|
+
azure_openai_api_version = unified_config.get(
|
71
|
+
"azure_openai_api_version", "2023-05-15"
|
72
|
+
)
|
73
|
+
# Handle vanilla mode
|
74
|
+
vanilla_mode = getattr(args, "vanilla", False)
|
75
|
+
if vanilla_mode:
|
76
|
+
runtime_config.set("vanilla_mode", True)
|
77
|
+
system_prompt_template = None
|
78
|
+
runtime_config.set("system_prompt_template", None)
|
79
|
+
if args.temperature is None:
|
80
|
+
runtime_config.set("temperature", None)
|
81
|
+
else:
|
82
|
+
runtime_config.set("vanilla_mode", False)
|
83
|
+
|
84
|
+
interaction_style = getattr(args, "style", None) or unified_config.get(
|
85
|
+
"interaction_style", "default"
|
86
|
+
)
|
87
|
+
|
88
|
+
if not getattr(args, "prompt", None):
|
89
|
+
interaction_mode = "chat"
|
90
|
+
else:
|
91
|
+
interaction_mode = "prompt"
|
92
|
+
|
93
|
+
profile_manager = AgentProfileManager(
|
94
|
+
api_key=api_key,
|
95
|
+
model=model,
|
96
|
+
role=role,
|
97
|
+
interaction_style=interaction_style,
|
98
|
+
interaction_mode=interaction_mode,
|
99
|
+
verbose_tools=args.verbose_tools,
|
100
|
+
base_url=base_url,
|
101
|
+
azure_openai_api_version=azure_openai_api_version,
|
102
|
+
use_azure_openai=unified_config.get("use_azure_openai", False),
|
103
|
+
)
|
104
|
+
profile_manager.refresh_prompt()
|
105
|
+
|
106
|
+
if args.max_tokens is not None:
|
107
|
+
runtime_config.set("max_tokens", args.max_tokens)
|
108
|
+
|
109
|
+
if not getattr(args, "prompt", None):
|
110
|
+
from janito.cli_chat_shell.chat_loop import start_chat_shell
|
111
|
+
|
112
|
+
start_chat_shell(
|
113
|
+
profile_manager, continue_session=getattr(args, "continue_session", False)
|
114
|
+
)
|
115
|
+
sys.exit(0)
|
116
|
+
|
117
|
+
prompt = args.prompt
|
118
|
+
console = Console()
|
119
|
+
from janito.agent.rich_message_handler import RichMessageHandler
|
120
|
+
|
121
|
+
message_handler = RichMessageHandler()
|
122
|
+
messages = []
|
123
|
+
if profile_manager.system_prompt_template:
|
124
|
+
messages.append(
|
125
|
+
{"role": "system", "content": profile_manager.system_prompt_template}
|
126
|
+
)
|
127
|
+
messages.append({"role": "user", "content": prompt})
|
128
|
+
try:
|
129
|
+
try:
|
130
|
+
max_rounds = runtime_config.get("max_rounds", 50)
|
131
|
+
profile_manager.agent.handle_conversation(
|
132
|
+
messages,
|
133
|
+
message_handler=message_handler,
|
134
|
+
spinner=True,
|
135
|
+
max_rounds=max_rounds,
|
136
|
+
verbose_response=getattr(args, "verbose_response", False),
|
137
|
+
verbose_events=getattr(args, "verbose_events", False),
|
138
|
+
stream=getattr(args, "stream", False),
|
139
|
+
verbose_stream=getattr(args, "verbose_stream", False),
|
140
|
+
)
|
141
|
+
except MaxRoundsExceededError:
|
142
|
+
console.print("[red]Max conversation rounds exceeded.[/red]")
|
143
|
+
except ProviderError as e:
|
144
|
+
console.print(f"[red]Provider error:[/red] {e}")
|
145
|
+
except EmptyResponseError as e:
|
146
|
+
console.print(f"[red]Error:[/red] {e}")
|
147
|
+
except KeyboardInterrupt:
|
148
|
+
console.print("[yellow]Interrupted by user.[/yellow]")
|
@@ -0,0 +1,33 @@
|
|
1
|
+
import os
|
2
|
+
from janito.agent.profile_manager import AgentProfileManager
|
3
|
+
from janito.agent.runtime_config import unified_config, runtime_config
|
4
|
+
from janito.agent.config import get_api_key
|
5
|
+
|
6
|
+
def get_system_prompt_template(args, role):
|
7
|
+
system_prompt_template = None
|
8
|
+
if getattr(args, "system_prompt_template_file", None):
|
9
|
+
with open(args.system_prompt_template_file, "r", encoding="utf-8") as f:
|
10
|
+
system_prompt_template = f.read()
|
11
|
+
runtime_config.set(
|
12
|
+
"system_prompt_template_file", args.system_prompt_template_file
|
13
|
+
)
|
14
|
+
else:
|
15
|
+
system_prompt_template = getattr(
|
16
|
+
args, "system_prompt_template", None
|
17
|
+
) or unified_config.get("system_prompt_template")
|
18
|
+
if getattr(args, "system_prompt_template", None):
|
19
|
+
runtime_config.set("system_prompt_template", system_prompt_template)
|
20
|
+
if system_prompt_template is None:
|
21
|
+
profile_manager = AgentProfileManager(
|
22
|
+
api_key=get_api_key(),
|
23
|
+
model=unified_config.get("model"),
|
24
|
+
role=role,
|
25
|
+
interaction_style=unified_config.get("interaction_style", "default"),
|
26
|
+
interaction_mode=unified_config.get("interaction_mode", "prompt"),
|
27
|
+
verbose_tools=unified_config.get("verbose_tools", False),
|
28
|
+
base_url=unified_config.get("base_url", None),
|
29
|
+
azure_openai_api_version=unified_config.get("azure_openai_api_version", None),
|
30
|
+
use_azure_openai=unified_config.get("use_azure_openai", False),
|
31
|
+
)
|
32
|
+
system_prompt_template = profile_manager.render_prompt()
|
33
|
+
return system_prompt_template
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import os
|
2
|
+
from janito.agent.openai_client import Agent
|
3
|
+
from janito.agent.runtime_config import unified_config
|
4
|
+
from janito.agent.config import get_api_key
|
5
|
+
|
6
|
+
def scan_project():
|
7
|
+
prompt_path = os.path.abspath(os.path.join(
|
8
|
+
os.path.dirname(__file__),
|
9
|
+
"..", "..", "agent", "templates", "detect_tech_prompt.j2"
|
10
|
+
))
|
11
|
+
with open(prompt_path, "r", encoding="utf-8") as f:
|
12
|
+
detect_prompt = f.read()
|
13
|
+
api_key = get_api_key()
|
14
|
+
model = unified_config.get("model")
|
15
|
+
base_url = unified_config.get("base_url", "https://openrouter.ai/api/v1")
|
16
|
+
azure_openai_api_version = unified_config.get("azure_openai_api_version", "2023-05-15")
|
17
|
+
use_azure_openai = unified_config.get("use_azure_openai", False)
|
18
|
+
agent = Agent(
|
19
|
+
api_key=api_key,
|
20
|
+
model=model,
|
21
|
+
system_prompt_template=detect_prompt,
|
22
|
+
verbose_tools=True,
|
23
|
+
base_url=base_url,
|
24
|
+
azure_openai_api_version=azure_openai_api_version,
|
25
|
+
use_azure_openai=use_azure_openai,
|
26
|
+
)
|
27
|
+
from janito.agent.rich_message_handler import RichMessageHandler
|
28
|
+
message_handler = RichMessageHandler()
|
29
|
+
messages = [{"role": "system", "content": detect_prompt}]
|
30
|
+
print("🔍 Scanning project for relevant tech/skills...")
|
31
|
+
result = agent.chat(
|
32
|
+
messages,
|
33
|
+
message_handler=message_handler,
|
34
|
+
spinner=True,
|
35
|
+
max_rounds=10,
|
36
|
+
verbose_response=False,
|
37
|
+
verbose_events=False,
|
38
|
+
stream=False,
|
39
|
+
)
|
40
|
+
os.makedirs(".janito", exist_ok=True)
|
41
|
+
tech_txt = os.path.join(".janito", "tech.txt")
|
42
|
+
with open(tech_txt, "w", encoding="utf-8") as f:
|
43
|
+
f.write(result["content"].strip() + "\n")
|
44
|
+
print(f"✅ Tech/skills detected and saved to {tech_txt}")
|
@@ -1 +0,0 @@
|
|
1
|
-
from .chat_loop import start_chat_shell
|
@@ -1,93 +1,47 @@
|
|
1
|
-
from janito.agent.
|
2
|
-
from
|
3
|
-
from .
|
4
|
-
from .ui import print_welcome, get_toolbar_func, get_prompt_session
|
5
|
-
from janito import __version__
|
1
|
+
from janito.agent.rich_message_handler import RichMessageHandler
|
2
|
+
from .chat_state import load_chat_state, save_chat_state
|
3
|
+
from .chat_ui import setup_prompt_session, print_welcome_message
|
6
4
|
from .commands import handle_command
|
7
|
-
from janito.agent.
|
8
|
-
from janito.agent.runtime_config import runtime_config
|
9
|
-
from janito.agent.conversation import EmptyResponseError, ProviderError
|
5
|
+
from janito.agent.conversation_exceptions import EmptyResponseError, ProviderError
|
10
6
|
|
11
7
|
|
12
|
-
def start_chat_shell(
|
13
|
-
|
8
|
+
def start_chat_shell(profile_manager, continue_session=False, max_rounds=50):
|
9
|
+
agent = profile_manager.agent
|
10
|
+
message_handler = RichMessageHandler()
|
14
11
|
console = message_handler.console
|
15
12
|
|
16
|
-
# Load
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# Initialize chat state variables
|
23
|
-
messages = []
|
24
|
-
last_usage_info = None
|
25
|
-
last_elapsed = None
|
26
|
-
|
27
|
-
state = {
|
28
|
-
'messages': messages,
|
29
|
-
'mem_history': mem_history,
|
30
|
-
'history_list': history_list,
|
31
|
-
'last_usage_info': last_usage_info,
|
32
|
-
'last_elapsed': last_elapsed,
|
33
|
-
}
|
34
|
-
|
35
|
-
# Restore conversation if requested
|
36
|
-
if continue_session:
|
37
|
-
msgs, prompts, usage = load_last_conversation()
|
38
|
-
messages = msgs
|
39
|
-
last_usage_info = usage
|
40
|
-
mem_history = InMemoryHistory()
|
41
|
-
for item in prompts:
|
42
|
-
mem_history.append_string(item)
|
43
|
-
# update state dict with restored data
|
44
|
-
|
45
|
-
state['messages'] = messages
|
46
|
-
state['last_usage_info'] = last_usage_info
|
47
|
-
state['mem_history'] = mem_history
|
48
|
-
message_handler.handle_message({'type': 'success', 'message': 'Restored last saved conversation.'})
|
13
|
+
# Load state
|
14
|
+
state = load_chat_state(continue_session)
|
15
|
+
messages = state["messages"]
|
16
|
+
mem_history = state["mem_history"]
|
17
|
+
last_usage_info = state["last_usage_info"]
|
18
|
+
last_elapsed = state["last_elapsed"]
|
49
19
|
|
50
20
|
# Add system prompt if needed
|
51
|
-
if
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
# Toolbar references
|
57
|
-
def get_messages():
|
58
|
-
return messages
|
59
|
-
|
60
|
-
def get_usage():
|
61
|
-
return last_usage_info
|
62
|
-
|
63
|
-
def get_elapsed():
|
64
|
-
return last_elapsed
|
21
|
+
if profile_manager.system_prompt_template and not any(
|
22
|
+
m.get("role") == "system" for m in messages
|
23
|
+
):
|
24
|
+
messages.insert(0, {"role": "system", "content": agent.system_prompt_template})
|
65
25
|
|
66
|
-
|
67
|
-
model_name = getattr(agent, 'model', None)
|
26
|
+
print_welcome_message(console, continued=continue_session)
|
68
27
|
|
69
|
-
session =
|
70
|
-
|
71
|
-
get_messages, get_usage, get_elapsed, model_name=model_name,
|
72
|
-
role_ref=lambda: ("*using custom system prompt*" if (runtime_config.get('system_prompt') or runtime_config.get('system_prompt_file')) else (runtime_config.get('role') or effective_config.get('role')))
|
73
|
-
),
|
74
|
-
mem_history
|
28
|
+
session = setup_prompt_session(
|
29
|
+
messages, last_usage_info, last_elapsed, mem_history, profile_manager, agent
|
75
30
|
)
|
76
31
|
|
77
|
-
|
78
|
-
# Main chat loop
|
79
32
|
while True:
|
80
|
-
# max_rounds is now available for use in the chat loop
|
81
|
-
|
82
33
|
try:
|
83
|
-
if state.get(
|
84
|
-
console.print(
|
85
|
-
user_input = session.prompt(
|
34
|
+
if state.get("paste_mode"):
|
35
|
+
console.print("")
|
36
|
+
user_input = session.prompt("Multiline> ", multiline=True)
|
86
37
|
was_paste_mode = True
|
87
|
-
state[
|
38
|
+
state["paste_mode"] = False
|
88
39
|
else:
|
89
40
|
from prompt_toolkit.formatted_text import HTML
|
90
|
-
|
41
|
+
|
42
|
+
user_input = session.prompt(
|
43
|
+
HTML("<prompt>💬 </prompt>"), multiline=False
|
44
|
+
)
|
91
45
|
was_paste_mode = False
|
92
46
|
except EOFError:
|
93
47
|
console.print("\n[bold red]Exiting...[/bold red]")
|
@@ -95,19 +49,39 @@ def start_chat_shell(agent, continue_session=False, max_rounds=50):
|
|
95
49
|
except KeyboardInterrupt:
|
96
50
|
console.print() # Move to next line
|
97
51
|
try:
|
98
|
-
confirm =
|
52
|
+
confirm = (
|
53
|
+
session.prompt(
|
54
|
+
HTML("<prompt>Do you really want to exit? (y/n): </prompt>")
|
55
|
+
)
|
56
|
+
.strip()
|
57
|
+
.lower()
|
58
|
+
)
|
99
59
|
except KeyboardInterrupt:
|
100
|
-
message_handler.handle_message(
|
60
|
+
message_handler.handle_message(
|
61
|
+
{"type": "error", "message": "Exiting..."}
|
62
|
+
)
|
101
63
|
break
|
102
|
-
if confirm ==
|
103
|
-
message_handler.handle_message(
|
64
|
+
if confirm == "y":
|
65
|
+
message_handler.handle_message(
|
66
|
+
{"type": "error", "message": "Exiting..."}
|
67
|
+
)
|
104
68
|
break
|
105
69
|
else:
|
106
70
|
continue
|
107
71
|
|
108
|
-
|
109
|
-
|
110
|
-
|
72
|
+
cmd_input = user_input.strip().lower()
|
73
|
+
if not was_paste_mode and (cmd_input.startswith("/") or cmd_input == "exit"):
|
74
|
+
# Treat both '/exit' and 'exit' as commands
|
75
|
+
result = handle_command(
|
76
|
+
user_input.strip(),
|
77
|
+
console,
|
78
|
+
profile_manager=profile_manager,
|
79
|
+
agent=agent,
|
80
|
+
messages=messages,
|
81
|
+
mem_history=mem_history,
|
82
|
+
state=state,
|
83
|
+
)
|
84
|
+
if result == "exit":
|
111
85
|
break
|
112
86
|
continue
|
113
87
|
|
@@ -117,29 +91,34 @@ def start_chat_shell(agent, continue_session=False, max_rounds=50):
|
|
117
91
|
mem_history.append_string(user_input)
|
118
92
|
messages.append({"role": "user", "content": user_input})
|
119
93
|
|
120
|
-
start_time = None
|
121
94
|
import time
|
122
|
-
start_time = time.time()
|
123
95
|
|
96
|
+
start_time = time.time()
|
124
97
|
|
125
98
|
try:
|
126
|
-
response = agent.
|
99
|
+
response = profile_manager.agent.handle_conversation(
|
100
|
+
messages,
|
101
|
+
max_rounds=max_rounds,
|
102
|
+
message_handler=message_handler,
|
103
|
+
spinner=True,
|
104
|
+
)
|
127
105
|
except KeyboardInterrupt:
|
128
|
-
message_handler.handle_message(
|
106
|
+
message_handler.handle_message(
|
107
|
+
{"type": "info", "message": "Request interrupted. Returning to prompt."}
|
108
|
+
)
|
129
109
|
continue
|
130
110
|
except ProviderError as e:
|
131
|
-
message_handler.handle_message(
|
111
|
+
message_handler.handle_message(
|
112
|
+
{"type": "error", "message": f"Provider error: {e}"}
|
113
|
+
)
|
132
114
|
continue
|
133
115
|
except EmptyResponseError as e:
|
134
|
-
message_handler.handle_message({
|
116
|
+
message_handler.handle_message({"type": "error", "message": f"Error: {e}"})
|
135
117
|
continue
|
136
118
|
last_elapsed = time.time() - start_time
|
137
119
|
|
138
|
-
usage = response.get(
|
120
|
+
usage = response.get("usage")
|
139
121
|
last_usage_info = usage
|
140
122
|
|
141
123
|
# Save conversation and input history
|
142
|
-
|
143
|
-
prompts = [h for h in mem_history.get_strings()]
|
144
|
-
save_conversation(messages, prompts, last_usage_info)
|
145
|
-
save_input_history(prompts)
|
124
|
+
save_chat_state(messages, mem_history, last_usage_info)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from .session_manager import (
|
2
|
+
load_last_conversation,
|
3
|
+
load_input_history,
|
4
|
+
save_conversation,
|
5
|
+
save_input_history,
|
6
|
+
)
|
7
|
+
from prompt_toolkit.history import InMemoryHistory
|
8
|
+
|
9
|
+
|
10
|
+
def load_chat_state(continue_session: bool):
|
11
|
+
messages = []
|
12
|
+
last_usage_info = None
|
13
|
+
last_elapsed = None
|
14
|
+
history_list = load_input_history()
|
15
|
+
mem_history = InMemoryHistory()
|
16
|
+
for item in history_list:
|
17
|
+
mem_history.append_string(item)
|
18
|
+
if continue_session:
|
19
|
+
msgs, prompts, usage = load_last_conversation()
|
20
|
+
messages = msgs
|
21
|
+
last_usage_info = usage
|
22
|
+
mem_history = InMemoryHistory()
|
23
|
+
for item in prompts:
|
24
|
+
mem_history.append_string(item)
|
25
|
+
state = {
|
26
|
+
"messages": messages,
|
27
|
+
"mem_history": mem_history,
|
28
|
+
"history_list": history_list,
|
29
|
+
"last_usage_info": last_usage_info,
|
30
|
+
"last_elapsed": last_elapsed,
|
31
|
+
}
|
32
|
+
return state
|
33
|
+
|
34
|
+
|
35
|
+
def save_chat_state(messages, mem_history, last_usage_info):
|
36
|
+
prompts = [h for h in mem_history.get_strings()]
|
37
|
+
save_conversation(messages, prompts, last_usage_info)
|
38
|
+
save_input_history(prompts)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
from .ui import print_welcome, get_toolbar_func, get_prompt_session
|
2
|
+
from janito import __version__
|
3
|
+
from janito.agent.config import effective_config
|
4
|
+
from janito.agent.runtime_config import runtime_config
|
5
|
+
|
6
|
+
|
7
|
+
def setup_prompt_session(
|
8
|
+
messages, last_usage_info, last_elapsed, mem_history, profile_manager, agent
|
9
|
+
):
|
10
|
+
model_name = getattr(agent, "model", None)
|
11
|
+
|
12
|
+
def get_messages():
|
13
|
+
return messages
|
14
|
+
|
15
|
+
def get_usage():
|
16
|
+
return last_usage_info
|
17
|
+
|
18
|
+
def get_elapsed():
|
19
|
+
return last_elapsed
|
20
|
+
|
21
|
+
session = get_prompt_session(
|
22
|
+
get_toolbar_func(
|
23
|
+
get_messages,
|
24
|
+
get_usage,
|
25
|
+
get_elapsed,
|
26
|
+
model_name=model_name,
|
27
|
+
role_ref=lambda: (
|
28
|
+
"*using custom system prompt*"
|
29
|
+
if (
|
30
|
+
runtime_config.get("system_prompt_template")
|
31
|
+
or runtime_config.get("system_prompt_template_file")
|
32
|
+
)
|
33
|
+
else (runtime_config.get("role") or effective_config.get("role"))
|
34
|
+
),
|
35
|
+
style_ref=lambda: getattr(profile_manager, "interaction_style", "default"),
|
36
|
+
),
|
37
|
+
mem_history,
|
38
|
+
)
|
39
|
+
return session
|
40
|
+
|
41
|
+
|
42
|
+
def print_welcome_message(console, continued):
|
43
|
+
print_welcome(console, version=__version__, continued=continued)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
from .session import handle_continue, handle_history
|
2
|
+
from .system import handle_system, handle_role, handle_style
|
3
|
+
from .session_control import handle_exit, handle_restart
|
4
|
+
from .utility import handle_help, handle_clear, handle_multi
|
5
|
+
from .config import handle_reload
|
6
|
+
from .history_reset import handle_reset
|
7
|
+
from ..config_shell import handle_config_shell
|
8
|
+
from janito.agent.runtime_config import runtime_config
|
9
|
+
|
10
|
+
COMMAND_HANDLERS = {
|
11
|
+
"/history": handle_history,
|
12
|
+
"/continue": handle_continue,
|
13
|
+
"/exit": handle_exit,
|
14
|
+
"exit": handle_exit,
|
15
|
+
"/restart": handle_restart,
|
16
|
+
"/help": handle_help,
|
17
|
+
"/multi": handle_multi,
|
18
|
+
"/system": handle_system,
|
19
|
+
}
|
20
|
+
|
21
|
+
if not runtime_config.get("vanilla_mode", False):
|
22
|
+
COMMAND_HANDLERS["/role"] = handle_role
|
23
|
+
|
24
|
+
COMMAND_HANDLERS.update(
|
25
|
+
{
|
26
|
+
"/clear": handle_clear,
|
27
|
+
"/reset": handle_reset,
|
28
|
+
"/config": handle_config_shell,
|
29
|
+
"/reload": handle_reload,
|
30
|
+
"/style": handle_style,
|
31
|
+
}
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
def handle_command(command, console, **kwargs):
|
36
|
+
parts = command.strip().split()
|
37
|
+
cmd = parts[0]
|
38
|
+
args = parts[1:]
|
39
|
+
handler = COMMAND_HANDLERS.get(cmd)
|
40
|
+
if handler:
|
41
|
+
return handler(console, *args, **kwargs)
|
42
|
+
console.print(
|
43
|
+
f"[bold red]Invalid command: {cmd}. Type /help for a list of commands.[/bold red]"
|
44
|
+
)
|
45
|
+
return None
|