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/rich_utils.py
CHANGED
@@ -1,30 +1,43 @@
|
|
1
1
|
"""
|
2
2
|
Utilities for working with the Rich library.
|
3
3
|
"""
|
4
|
+
|
4
5
|
from rich.markdown import Markdown
|
5
6
|
from rich.text import Text
|
6
7
|
from rich.console import Console
|
7
8
|
|
9
|
+
|
8
10
|
def print_markdown(console: Console, message: str):
|
9
11
|
console.print(Markdown(message))
|
10
12
|
|
13
|
+
|
11
14
|
def print_info(console: Console, message: str):
|
12
15
|
console.print(message, style="cyan", end="")
|
13
16
|
|
17
|
+
|
14
18
|
def print_success(console: Console, message: str):
|
15
19
|
console.print(message, style="bold green", end="\n")
|
16
20
|
|
21
|
+
|
17
22
|
def print_error(console: Console, message: str):
|
18
23
|
console.print(message, style="bold red", end="\n")
|
19
24
|
|
25
|
+
|
20
26
|
def print_warning(console: Console, message: str):
|
21
27
|
console.print(message, style="bold yellow", end="\n")
|
22
28
|
|
29
|
+
|
23
30
|
def print_magenta(console: Console, message: str):
|
24
31
|
console.print(message, style="magenta", end="\n")
|
25
32
|
|
33
|
+
|
26
34
|
def print_stdout(console: Console, message: str):
|
27
|
-
console.print(
|
35
|
+
console.print(
|
36
|
+
Text(message, style="on #003300", no_wrap=True, overflow=None), end=""
|
37
|
+
)
|
38
|
+
|
28
39
|
|
29
40
|
def print_stderr(console: Console, message: str):
|
30
|
-
console.print(
|
41
|
+
console.print(
|
42
|
+
Text(message, style="on #330000", no_wrap=True, overflow=None), end=""
|
43
|
+
)
|
janito/web/__main__.py
CHANGED
@@ -3,6 +3,14 @@ from . import app
|
|
3
3
|
|
4
4
|
|
5
5
|
def main():
|
6
|
+
import os
|
7
|
+
|
8
|
+
# Ensure PYTHONUTF8 is set for consistent UTF-8 behavior
|
9
|
+
if os.environ.get("PYTHONUTF8") != "1":
|
10
|
+
os.environ["PYTHONUTF8"] = "1"
|
11
|
+
if os.name == "nt" and sys.argv[0]:
|
12
|
+
print("[info] Restarting web server with PYTHONUTF8=1 for UTF-8 support...")
|
13
|
+
os.execvpe(sys.executable, [sys.executable] + sys.argv, os.environ)
|
6
14
|
port = 8000
|
7
15
|
if len(sys.argv) > 1:
|
8
16
|
try:
|
@@ -10,8 +18,8 @@ def main():
|
|
10
18
|
except ValueError:
|
11
19
|
print(f"Invalid port number: {sys.argv[1]}")
|
12
20
|
sys.exit(1)
|
13
|
-
app.app.run(host=
|
21
|
+
app.app.run(host="0.0.0.0", port=port, debug=True)
|
14
22
|
|
15
23
|
|
16
|
-
if __name__ ==
|
24
|
+
if __name__ == "__main__":
|
17
25
|
main()
|
janito/web/app.py
CHANGED
@@ -1,9 +1,16 @@
|
|
1
|
-
from flask import
|
1
|
+
from flask import (
|
2
|
+
Flask,
|
3
|
+
request,
|
4
|
+
Response,
|
5
|
+
send_from_directory,
|
6
|
+
jsonify,
|
7
|
+
render_template,
|
8
|
+
)
|
2
9
|
from queue import Queue
|
3
10
|
import json
|
4
11
|
from janito.agent.queued_message_handler import QueuedMessageHandler
|
5
|
-
from janito.agent.
|
6
|
-
from janito.
|
12
|
+
from janito.agent.openai_client import Agent
|
13
|
+
from janito.agent.profile_manager import AgentProfileManager
|
7
14
|
import os
|
8
15
|
import threading
|
9
16
|
import traceback
|
@@ -13,23 +20,34 @@ from janito.agent.runtime_config import unified_config
|
|
13
20
|
|
14
21
|
# Render system prompt from config
|
15
22
|
role = unified_config.get("role", "software engineer")
|
16
|
-
|
17
|
-
if
|
18
|
-
|
23
|
+
system_prompt_template_override = unified_config.get("system_prompt_template")
|
24
|
+
if system_prompt_template_override:
|
25
|
+
system_prompt_template = system_prompt_template_override
|
19
26
|
else:
|
20
|
-
|
27
|
+
profile_manager = AgentProfileManager(
|
28
|
+
api_key=unified_config.get("api_key"),
|
29
|
+
model=unified_config.get("model"),
|
30
|
+
role=role,
|
31
|
+
interaction_style=unified_config.get("interaction_style", "default"),
|
32
|
+
interaction_mode=unified_config.get("interaction_mode", "prompt"),
|
33
|
+
verbose_tools=unified_config.get("verbose_tools", False),
|
34
|
+
base_url=unified_config.get("base_url", None),
|
35
|
+
azure_openai_api_version=unified_config.get("azure_openai_api_version", None),
|
36
|
+
use_azure_openai=unified_config.get("use_azure_openai", False),
|
37
|
+
)
|
38
|
+
system_prompt_template = profile_manager.render_prompt()
|
21
39
|
|
22
40
|
app = Flask(
|
23
41
|
__name__,
|
24
|
-
static_url_path=
|
25
|
-
static_folder=os.path.join(os.path.dirname(__file__),
|
42
|
+
static_url_path="/static",
|
43
|
+
static_folder=os.path.join(os.path.dirname(__file__), "static"),
|
26
44
|
)
|
27
45
|
|
28
46
|
# Secret key for session management
|
29
|
-
app.secret_key =
|
47
|
+
app.secret_key = "replace_with_a_secure_random_secret_key"
|
30
48
|
|
31
49
|
# Path for persistent conversation storage
|
32
|
-
conversation_file = os.path.expanduser(
|
50
|
+
conversation_file = os.path.expanduser("~/.janito/last_conversation_web.json")
|
33
51
|
|
34
52
|
# Initially no conversation loaded
|
35
53
|
conversation = None
|
@@ -45,14 +63,18 @@ message_handler = QueuedMessageHandler(stream_queue)
|
|
45
63
|
agent = Agent(
|
46
64
|
api_key=unified_config.get("api_key"),
|
47
65
|
model=unified_config.get("model"),
|
48
|
-
base_url=unified_config.get("base_url")
|
66
|
+
base_url=unified_config.get("base_url"),
|
49
67
|
)
|
50
68
|
|
51
|
-
|
69
|
+
|
70
|
+
@app.route("/get_config")
|
52
71
|
def get_config():
|
53
72
|
# Expose full config for the web app: defaults, effective, runtime (mask api_key)
|
54
|
-
from janito.agent.runtime_config import
|
73
|
+
from janito.agent.runtime_config import (
|
74
|
+
unified_config,
|
75
|
+
) # Kept here: avoids circular import at module level
|
55
76
|
from janito.agent.config_defaults import CONFIG_DEFAULTS
|
77
|
+
|
56
78
|
# Start with defaults
|
57
79
|
config = dict(CONFIG_DEFAULTS)
|
58
80
|
# Overlay effective config
|
@@ -61,19 +83,26 @@ def get_config():
|
|
61
83
|
config.update(unified_config.runtime_cfg.all())
|
62
84
|
api_key = config.get("api_key")
|
63
85
|
if api_key:
|
64
|
-
config["api_key"] =
|
86
|
+
config["api_key"] = (
|
87
|
+
api_key[:4] + "..." + api_key[-4:] if len(api_key) > 8 else "***"
|
88
|
+
)
|
65
89
|
return jsonify(config)
|
66
90
|
|
67
|
-
|
91
|
+
|
92
|
+
@app.route("/set_config", methods=["POST"])
|
68
93
|
def set_config():
|
69
94
|
from janito.agent.runtime_config import runtime_config
|
70
95
|
from janito.agent.config import CONFIG_OPTIONS
|
71
96
|
from janito.agent.config_defaults import CONFIG_DEFAULTS
|
97
|
+
|
72
98
|
data = request.get_json()
|
73
|
-
key = data.get(
|
74
|
-
value = data.get(
|
99
|
+
key = data.get("key")
|
100
|
+
value = data.get("value")
|
75
101
|
if key not in CONFIG_OPTIONS:
|
76
|
-
return
|
102
|
+
return (
|
103
|
+
jsonify({"status": "error", "message": f"Invalid config key: {key}"}),
|
104
|
+
400,
|
105
|
+
)
|
77
106
|
# Type coercion based on defaults
|
78
107
|
default = CONFIG_DEFAULTS.get(key)
|
79
108
|
if default is not None and value is not None:
|
@@ -86,48 +115,56 @@ def set_config():
|
|
86
115
|
value = float(value)
|
87
116
|
# else: leave as string or None
|
88
117
|
except Exception as e:
|
89
|
-
return
|
118
|
+
return (
|
119
|
+
jsonify(
|
120
|
+
{"status": "error", "message": f"Invalid value type for {key}: {e}"}
|
121
|
+
),
|
122
|
+
400,
|
123
|
+
)
|
90
124
|
runtime_config.set(key, value)
|
91
125
|
# Mask api_key in response
|
92
126
|
resp_value = value
|
93
|
-
if key ==
|
94
|
-
resp_value = value[:4] +
|
95
|
-
return jsonify({
|
127
|
+
if key == "api_key" and value:
|
128
|
+
resp_value = value[:4] + "..." + value[-4:] if len(value) > 8 else "***"
|
129
|
+
return jsonify({"status": "ok", "key": key, "value": resp_value})
|
96
130
|
|
97
131
|
|
98
|
-
@app.route(
|
132
|
+
@app.route("/favicon.ico")
|
99
133
|
def favicon():
|
100
134
|
return send_from_directory(
|
101
|
-
os.path.join(app.root_path,
|
102
|
-
|
103
|
-
mimetype=
|
135
|
+
os.path.join(app.root_path, "static"),
|
136
|
+
"favicon.ico",
|
137
|
+
mimetype="image/vnd.microsoft.icon",
|
104
138
|
)
|
105
139
|
|
106
140
|
|
107
|
-
@app.route(
|
141
|
+
@app.route("/")
|
108
142
|
def index():
|
109
|
-
return render_template(
|
143
|
+
return render_template("index.html")
|
144
|
+
|
110
145
|
|
111
|
-
@app.route(
|
146
|
+
@app.route("/load_conversation")
|
112
147
|
def load_conversation():
|
113
148
|
global conversation
|
114
149
|
try:
|
115
|
-
with open(conversation_file,
|
150
|
+
with open(conversation_file, "r") as f:
|
116
151
|
conversation = json.load(f)
|
117
152
|
except (FileNotFoundError, json.JSONDecodeError):
|
118
153
|
conversation = []
|
119
|
-
return jsonify({
|
154
|
+
return jsonify({"status": "ok", "conversation": conversation})
|
155
|
+
|
120
156
|
|
121
|
-
@app.route(
|
157
|
+
@app.route("/new_conversation", methods=["POST"])
|
122
158
|
def new_conversation():
|
123
159
|
global conversation
|
124
160
|
conversation = []
|
125
|
-
return jsonify({
|
161
|
+
return jsonify({"status": "ok"})
|
126
162
|
|
127
|
-
|
163
|
+
|
164
|
+
@app.route("/execute_stream", methods=["POST"])
|
128
165
|
def execute_stream():
|
129
166
|
data = request.get_json()
|
130
|
-
user_input = data.get(
|
167
|
+
user_input = data.get("input", "")
|
131
168
|
|
132
169
|
global conversation
|
133
170
|
if conversation is None:
|
@@ -135,23 +172,22 @@ def execute_stream():
|
|
135
172
|
conversation = []
|
136
173
|
|
137
174
|
# Always start with the system prompt as the first message
|
138
|
-
if not conversation or conversation[0][
|
139
|
-
conversation.insert(0, {"role": "system", "content":
|
175
|
+
if not conversation or conversation[0]["role"] != "system":
|
176
|
+
conversation.insert(0, {"role": "system", "content": system_prompt_template})
|
140
177
|
|
141
178
|
# Append the new user message
|
142
179
|
conversation.append({"role": "user", "content": user_input})
|
143
180
|
|
144
181
|
def run_agent():
|
145
182
|
try:
|
146
|
-
response = agent.chat(
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
conversation.append({"role": "assistant", "content": response['content']})
|
183
|
+
response = agent.chat(conversation, message_handler=message_handler)
|
184
|
+
if response and "content" in response:
|
185
|
+
conversation.append(
|
186
|
+
{"role": "assistant", "content": response["content"]}
|
187
|
+
)
|
152
188
|
try:
|
153
189
|
os.makedirs(os.path.dirname(conversation_file), exist_ok=True)
|
154
|
-
with open(conversation_file,
|
190
|
+
with open(conversation_file, "w") as f:
|
155
191
|
json.dump(conversation, f, indent=2)
|
156
192
|
except Exception as e:
|
157
193
|
print(f"Error saving conversation: {e}")
|
@@ -168,7 +204,7 @@ def execute_stream():
|
|
168
204
|
content = stream_queue.get()
|
169
205
|
if content is None:
|
170
206
|
break
|
171
|
-
if isinstance(content, tuple) and content[0] ==
|
207
|
+
if isinstance(content, tuple) and content[0] == "tool_progress":
|
172
208
|
message = json.dumps({"type": "tool_progress", "data": content[1]})
|
173
209
|
else:
|
174
210
|
message = json.dumps(content)
|
@@ -177,11 +213,11 @@ def execute_stream():
|
|
177
213
|
|
178
214
|
return Response(
|
179
215
|
generate(),
|
180
|
-
mimetype=
|
216
|
+
mimetype="text/event-stream",
|
181
217
|
headers={
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
}
|
218
|
+
"Cache-Control": "no-cache",
|
219
|
+
"X-Accel-Buffering": "no",
|
220
|
+
"Connection": "keep-alive",
|
221
|
+
"Transfer-Encoding": "chunked",
|
222
|
+
},
|
187
223
|
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: janito
|
3
|
-
Version: 1.
|
4
|
-
Summary: A Natural Programming
|
3
|
+
Version: 1.6.0
|
4
|
+
Summary: A Natural Language Programming Agent,
|
5
5
|
Author-email: João Pinto <joao.pinto@gmail.com>
|
6
6
|
License: MIT
|
7
7
|
Project-URL: homepage, https://github.com/joaompinto/janito
|
@@ -23,12 +23,12 @@ Requires-Dist: requests
|
|
23
23
|
Requires-Dist: rich
|
24
24
|
Dynamic: license-file
|
25
25
|
|
26
|
-
# 🚀 Janito: Natural Programming
|
26
|
+
# 🚀 Janito: Natural Language Programming Agent
|
27
27
|
|
28
|
-
**Current Version: 1.
|
29
|
-
See [
|
28
|
+
**Current Version: 1.6.0**
|
29
|
+
See [CHANGELOG.md](./CHANGELOG.md) and [RELEASE_NOTES_1.6.md](./RELEASE_NOTES_1.6.md) for details on the latest release.
|
30
30
|
|
31
|
-
Janito is an AI-powered assistant for the command line and web that interprets natural language
|
31
|
+
Janito is an AI-powered assistant for the command line and web that interprets natural language system_prompt_template to edit code, manage files, and analyze projects using patterns and tools designed by experienced software engineers. It prioritizes transparency, interactive clarification, and precise, reviewable changes.
|
32
32
|
|
33
33
|
For a technical overview, see the [Architecture Guide](docs/ARCHITECTURE.md).
|
34
34
|
|
@@ -51,6 +51,7 @@ You can alter Janito's behavior in any interface using these flags:
|
|
51
51
|
|
52
52
|
- `--system` / `--system-file`: Override or customize the system prompt for the session.
|
53
53
|
- `--no-tools`: Disable all tool usage (Janito will only use the language model, no file/code/shell actions).
|
54
|
+
- `--trust-tools`/`-T`: Trusted tools mode (suppresses all tool output, only shows output file locations).
|
54
55
|
- `--vanilla`: Disables tools, system prompt, and temperature settings for a pure LLM chat experience.
|
55
56
|
|
56
57
|
These modifiers can be combined with any interface mode for tailored workflows.
|
@@ -92,11 +93,11 @@ janito --web
|
|
92
93
|
|
93
94
|
### Contributing & Developer Guide
|
94
95
|
|
95
|
-
If you want to extend Janito or add new tools, see the [Developer Guide](docs/README_DEV.md) for
|
96
|
+
If you want to extend Janito or add new tools, see the [Developer Guide](docs/README_DEV.md) for system_prompt_template, tool registration requirements, and code style guidelines. For the full list of built-in tools and their usage, see the [Tools Reference](janito/agent/tools/README.md).
|
96
97
|
|
97
98
|
|
98
99
|
|
99
|
-
For the full changelog, see [
|
100
|
+
For the full changelog, see [CHANGELOG.md](./CHANGELOG.md).
|
100
101
|
|
101
102
|
...
|
102
103
|
|
@@ -134,16 +135,16 @@ For details on using models hosted on Azure OpenAI, see [docs/AZURE_OPENAI.md](d
|
|
134
135
|
Janito operates using a system prompt template that defines its behavior, communication style, and capabilities. By default, Janito assumes the role of a "software engineer"—this means its responses and actions are tailored to the expectations and best practices of professional software engineering.
|
135
136
|
|
136
137
|
- **Role:** You can customize the agent's role (e.g., "data scientist", "DevOps engineer") using the `--role` flag or config. The default is `software engineer`.
|
137
|
-
- **System Prompt Template:** The system prompt is rendered from a Jinja2 template (see `janito/agent/templates/
|
138
|
+
- **System Prompt Template:** The system prompt is rendered from a Jinja2 template (see `janito/agent/templates/system_prompt_template.j2`). This template governs how the agent interprets system_prompt_template, interacts with files, and communicates with users.
|
138
139
|
- **Customization & Precedence:** Advanced users can override the system prompt with the `--system` flag (raw string), or point to a custom file using `--system-file`. The precedence is: `--system-file` > `--system`/config > default template.
|
139
140
|
|
140
141
|
The default template ensures the agent:
|
141
142
|
- Prioritizes safe, reviewable, and minimal changes
|
142
|
-
- Asks for clarification when
|
143
|
+
- Asks for clarification when system_prompt_template are ambiguous
|
143
144
|
- Provides concise plans before taking action
|
144
145
|
- Documents any changes made
|
145
146
|
|
146
|
-
For more details or to customize the prompt, see the template file at `janito/agent/templates/
|
147
|
+
For more details or to customize the prompt, see the template file at `janito/agent/templates/system_prompt_template.j2` and the architecture overview in [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md).
|
147
148
|
|
148
149
|
---
|
149
150
|
|
@@ -174,3 +175,67 @@ Vanilla mode is ideal for:
|
|
174
175
|
- Ensuring no agent-side intervention or context is added
|
175
176
|
|
176
177
|
> Note: Vanilla mode is a runtime switch and does not change the Agent API or class signatures. It is controlled via CLI/config only.
|
178
|
+
|
179
|
+
## 🧑💻 AgentProfileManager: Profile, Role, and Prompt Management
|
180
|
+
|
181
|
+
Janito now uses a dedicated `AgentProfileManager` class to manage user profiles, roles, interaction styles, and system prompt selection. This manager:
|
182
|
+
- Stores the current role (e.g., "software engineer") and interaction style (e.g., "default", "technical").
|
183
|
+
- Renders the system prompt from the appropriate template based on interaction style.
|
184
|
+
- Instantiates and manages the low-level LLM Agent, passing the correct prompt.
|
185
|
+
- Provides methods to update the role, interaction style, and refresh the prompt at runtime.
|
186
|
+
|
187
|
+
### Multiple System Prompt Templates
|
188
|
+
- The system prompt template is now selected based on the interaction style (e.g., `default` or `technical`).
|
189
|
+
- Templates are located in `janito/agent/templates/` (see `system_prompt_template.j2` and `system_prompt_template_technical.j2`).
|
190
|
+
- You can switch interaction styles at runtime using the profile manager, enabling different agent behaviors for different user needs.
|
191
|
+
|
192
|
+
This separation ensures that the LLM Agent remains focused on language model interaction and tool execution, while all profile, role, and prompt logic is managed at a higher level.
|
193
|
+
|
194
|
+
See `janito/agent/profile_manager.py` for implementation details.
|
195
|
+
|
196
|
+
### Agent Interaction Style
|
197
|
+
|
198
|
+
You can control the agent's behavior and prompt style globally or per-project using the `interaction_style` config key. Supported values:
|
199
|
+
- `default`: Concise, general-purpose agent (default)
|
200
|
+
- `technical`: Strict, workflow-oriented for technical/developer use
|
201
|
+
|
202
|
+
Set globally:
|
203
|
+
```bash
|
204
|
+
janito --set-global-config interaction_style=technical
|
205
|
+
```
|
206
|
+
Or per-project (in your project root):
|
207
|
+
```bash
|
208
|
+
janito --set-local-config interaction_style=technical
|
209
|
+
```
|
210
|
+
|
211
|
+
You can also override for a session with the CLI flag:
|
212
|
+
```bash
|
213
|
+
janito --style technical
|
214
|
+
```
|
215
|
+
|
216
|
+
See [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for full details.
|
217
|
+
|
218
|
+
## 🧩 Combinatorial Style System
|
219
|
+
|
220
|
+
Janito now supports combinatorial styles for system prompts, allowing you to combine a main style (such as `default` or `technical`) with one or more feature extensions (such as `commit_all`).
|
221
|
+
|
222
|
+
- **Main style:** The base agent behavior and workflow (e.g., `default`, `technical`).
|
223
|
+
- **Feature extensions:** Optional features that override or extend the main style (e.g., `commit_all`).
|
224
|
+
- **Syntax:** Use a hyphen to combine, e.g., `technical-commit_all`.
|
225
|
+
|
226
|
+
**How it works:**
|
227
|
+
- The main style template is loaded first.
|
228
|
+
- Each feature extension template is layered on top, overriding or extending specific blocks in the main template.
|
229
|
+
- Feature templates must use `{% extends parent_template %}` for dynamic inheritance.
|
230
|
+
|
231
|
+
**Example usage:**
|
232
|
+
```bash
|
233
|
+
janito --style technical-commit_all
|
234
|
+
```
|
235
|
+
|
236
|
+
This will apply the `technical` style with the `commit_all` feature enabled in the agent's system prompt.
|
237
|
+
|
238
|
+
See `janito/render_prompt.py` and `janito/agent/templates/` for implementation details and to create your own feature extensions.
|
239
|
+
|
240
|
+
---
|
241
|
+
_generated by janito.dev_
|
@@ -0,0 +1,81 @@
|
|
1
|
+
janito/__init__.py,sha256=PTA-UJ0gOgRLnjvcmghK_Up95KKEx6TmFCJ8J8l7GRI,23
|
2
|
+
janito/__main__.py,sha256=KKIoPBE9xPcb54PRYO2UOt0ti04iAwLeJlg8YY36vew,76
|
3
|
+
janito/rich_utils.py,sha256=gZ4uAYyAeSk_H1uCGYhYkFoel5Z1SDmNhp241pnniqg,1085
|
4
|
+
janito/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
janito/agent/config.py,sha256=gD2puBUjKbb8bv_KbGUBP7OeeW0JqEEvYQXmIjv0avE,4617
|
6
|
+
janito/agent/config_defaults.py,sha256=dL3_8mRzEd7c_CF6GQe_-LAN3vWZpOFpm2cgaitpkYo,482
|
7
|
+
janito/agent/config_utils.py,sha256=UmvR236wDrMc-aTy9LxVbop6YeoJaaPb1d2DBMlkSRg,254
|
8
|
+
janito/agent/content_handler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
|
+
janito/agent/conversation.py,sha256=fFdWmyxUBbqm3LWL1INVd1MKAQS7EbTPuGRBBAjWom8,4956
|
10
|
+
janito/agent/conversation_api.py,sha256=v85_BwcyNceeYZorDKnjpgpDUY5sfvTwQMoVjXxAdmE,3441
|
11
|
+
janito/agent/conversation_exceptions.py,sha256=F36wOPRx0yFaiQUuVqxktkRdNlnXVOUovAEdB40poNM,260
|
12
|
+
janito/agent/conversation_tool_calls.py,sha256=7RWy_TVxXZY8Cmafy2XtSF1sCLf9O3NIC7dw1PtVYqk,874
|
13
|
+
janito/agent/conversation_ui.py,sha256=y4f0IoJQoWGrFMB3yi7uIwXokuTjhFtJGK_R7zcTv3w,397
|
14
|
+
janito/agent/message_handler.py,sha256=Za4xUflbRvamlJP_4_YEStOiXuCYYjI1uQkHabTaUtA,754
|
15
|
+
janito/agent/openai_client.py,sha256=LM-94jjmARIuuASMCZeJ6N8_seobaQ_lbkeksTLZl24,4624
|
16
|
+
janito/agent/openai_schema_generator.py,sha256=hqe7VVIf5mPcnSn38_MOlI9HJtTayN-aAXJz9iwxp4s,4821
|
17
|
+
janito/agent/profile_manager.py,sha256=WSd8ZaOCF5MN4EvSIysl-w3TuTaExi8247BASoyta2E,6364
|
18
|
+
janito/agent/queued_message_handler.py,sha256=sWyadc4h1xkFn_kgO0Hp5lgzj_8J23i-tV31M1lNtV0,1422
|
19
|
+
janito/agent/rich_live.py,sha256=NKWU89hRakiJ-0N6FPg40bYREOxQizqicbDv9eUfsKs,927
|
20
|
+
janito/agent/rich_message_handler.py,sha256=JjoGLJThYd-nO5qLB2FsAyaHoTOS4lTEPP-N91nZPeA,2301
|
21
|
+
janito/agent/runtime_config.py,sha256=xSx0-RD-WVA9niSCEmEn2ZPLFbQfRhPwwGIa8tid_v8,901
|
22
|
+
janito/agent/tool_base.py,sha256=b7WJkoCUObFK-WjUXfUm874UmKujYQFAyC7FVkxDOMo,1901
|
23
|
+
janito/agent/tool_registry.py,sha256=Wa1mNzTBKsxQyFCc2hQgDDRrb-m6TI_XbBGebCzr-6U,4037
|
24
|
+
janito/agent/tool_registry_core.py,sha256=bF7rRn3ZMpU7JXBFhYQPg2XxczhN572Xc5pbdLBPkvE,148
|
25
|
+
janito/agent/tools/__init__.py,sha256=68YCMWtkepgjOBkptPNmQpv7Tgb5_58uOWxAMR8fjII,979
|
26
|
+
janito/agent/tools/ask_user.py,sha256=ZQGKI-cjK8CG6O3elEf5v6c5iybVzgfNiZienK6I2oQ,2912
|
27
|
+
janito/agent/tools/create_directory.py,sha256=vIKP0kYnU3Ypik9e_iNwuwU7rkb5sdUtHMj2q8NA37A,1303
|
28
|
+
janito/agent/tools/create_file.py,sha256=wkPpo42KS3958Jialjyt8_Lv0CXIRgOmUI5EJ7wNw3o,2230
|
29
|
+
janito/agent/tools/fetch_url.py,sha256=xsNdxfyDBj6nLYBsMiQoBr685-TUxRx3s3893F7E2ek,2027
|
30
|
+
janito/agent/tools/find_files.py,sha256=CMUAAC-3skw2OKbu_wN6SFBeiVx-xWgVrA5_u4a6sLc,2604
|
31
|
+
janito/agent/tools/get_file_outline.py,sha256=e9RNijfE5koaSB0mJe-L3j-fjG4I1YgTJeToDMTTFuY,5348
|
32
|
+
janito/agent/tools/get_lines.py,sha256=pCV9ut6-GTRj5rBCp8hijTAwh37D8hPXScOjuy1HWUQ,3926
|
33
|
+
janito/agent/tools/gitignore_utils.py,sha256=fDLyRZmCu6Hqhp1BEN8hs7oG0FtA-1SM9TGDz4g0lbw,1470
|
34
|
+
janito/agent/tools/move_file.py,sha256=6-90TNlL9JnhWMFCtoy59TRZq2xk6VrP8Mv-EpPDP80,2568
|
35
|
+
janito/agent/tools/py_compile_file.py,sha256=pfHDXVa75WhO5Io_rXF0DnIB8y2BypoAsS4wNCVANeE,1601
|
36
|
+
janito/agent/tools/remove_directory.py,sha256=oMme-7e6hZG5Z0Wxu6SpdWjop_yMMZlrBtwkoqfn2NY,2192
|
37
|
+
janito/agent/tools/remove_file.py,sha256=dq17r-vd61LGS6RLic77BlD6ZzuAjWBBUGtUsX5PCTk,1731
|
38
|
+
janito/agent/tools/replace_file.py,sha256=oex5dncfny0Lv9om3LVs1u77IOemKZ7Cjh4IRIz_paM,2381
|
39
|
+
janito/agent/tools/replace_text_in_file.py,sha256=DNafuM6CFTKVEimP6jb9IHglG3BGCezQDLRbqSJ6TfI,5288
|
40
|
+
janito/agent/tools/rich_live.py,sha256=KpAN-dF0h9LZnYvSK-UKR_sbDnnDw0jUxY3cj_EW_wQ,1215
|
41
|
+
janito/agent/tools/run_bash_command.py,sha256=yDyVVQspaV_bNqOoAyplwczOpwu62MhNMHsQGkV37s8,6878
|
42
|
+
janito/agent/tools/run_python_command.py,sha256=_NdpRMNeHIf4h0ARaYUyO7ncHEbLXICFk8uJVdwpCPU,6099
|
43
|
+
janito/agent/tools/search_files.py,sha256=iyED-9QW1zGEJWIlqHPTQYanMDZA8vK4qIQ03eO4ZkU,3240
|
44
|
+
janito/agent/tools/tools_utils.py,sha256=ud0S8uVe1I3hKQBdQMf_RcYEDt7baTGBGeDd5IU23-o,358
|
45
|
+
janito/agent/tools/utils.py,sha256=zsW-ROZJYYFeDAhwN0YHMAqsnjfBXPdvJJVAa_TmQ1g,1136
|
46
|
+
janito/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
|
+
janito/cli/_print_config.py,sha256=VRv_KSVaeMmqmF5cHQC0YfRqem3LgcsXoWRn6fyNJfQ,3566
|
48
|
+
janito/cli/_utils.py,sha256=tRAUMDWKczd81ZvKYkwpsHWSeLzQoVlOoQ-lOw9Iujw,291
|
49
|
+
janito/cli/arg_parser.py,sha256=AXzq6TIRjD7EBWb176CCszMz7LWuCtMu4c0a03XRQk8,5897
|
50
|
+
janito/cli/config_commands.py,sha256=CHIeqxs6rwAfvfaq_hZYrSdWtG0oQjsZBfMo95RUfLk,8531
|
51
|
+
janito/cli/logging_setup.py,sha256=u2FxjJo-klLsY6aHxBuDymDYnuw9bc--1aqqsVeW9jc,1213
|
52
|
+
janito/cli/main.py,sha256=2_fy_wPu7wAL-pxvdC65wxu6Wz4sFTTP5N6SLShT5Ak,1289
|
53
|
+
janito/cli/runner/__init__.py,sha256=LBu8S8JS73biePK_WwSIlRBwM1c5DX5DGklN7acIyO0,70
|
54
|
+
janito/cli/runner/cli_main.py,sha256=hKbvMmWZHm01z9qSUYTJ8bUUkE1o3YC55S7PYGN4Eqk,5446
|
55
|
+
janito/cli/runner/config.py,sha256=7uqzw7vIA_SCCJFACjE_pHtPb9l9IXsaZW-ra_0AdQ0,1705
|
56
|
+
janito/cli/runner/formatting.py,sha256=k0mtHoglqR8fKcebSK81iWTT_EL-gDl7eNfjlFZRY6g,287
|
57
|
+
janito/cli/runner/scan.py,sha256=QTA67URhdJtIE8jw7aA2NA0cal1d64G7v36NCH0E0w4,1760
|
58
|
+
janito/cli_chat_shell/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
59
|
+
janito/cli_chat_shell/chat_loop.py,sha256=DD71TzcJublz3I3zRiylw6EPD2SuGNah2P81FZQmYVo,4450
|
60
|
+
janito/cli_chat_shell/chat_state.py,sha256=5wLSjZV0y5fHyU-Lkl4J4-G2GRY0n7gfcAof3515_Bo,1162
|
61
|
+
janito/cli_chat_shell/chat_ui.py,sha256=IbP2OVGkLycgcUBvdgbKyIUbCnMduhvoSMYYKlpWULc,1344
|
62
|
+
janito/cli_chat_shell/config_shell.py,sha256=sG04S_z27wI7nXKMaVDcwDpBCuo6Cvd4uhutUQesJKo,3807
|
63
|
+
janito/cli_chat_shell/load_prompt.py,sha256=8AyHaADBk5_berjt10fISG3Z9Bu5RnVUs2BzNEYOPIQ,633
|
64
|
+
janito/cli_chat_shell/session_manager.py,sha256=qzCDpAAXx_YZRVF4GwWPwbkxROwj_14jF52QjkjDGP4,2136
|
65
|
+
janito/cli_chat_shell/ui.py,sha256=5a5lwlEQs211R6Pr_WYt9HuMoQMjTkbamyoHZC5lsaI,6616
|
66
|
+
janito/cli_chat_shell/commands/__init__.py,sha256=D06FCOmKCFf02Li63KlkAtW753z5fSGJ_AylMJGvk9A,1378
|
67
|
+
janito/cli_chat_shell/commands/config.py,sha256=JTQwIuSBunxDwvGsU_Cu78GkQNYCtDFTPZ7HOxNOZCY,945
|
68
|
+
janito/cli_chat_shell/commands/history_reset.py,sha256=GBY8Cpcm2yE1C3DhiWWQwS7WFYPxoJ3LPmD0hCx8ut8,1017
|
69
|
+
janito/cli_chat_shell/commands/session.py,sha256=64H9UYB-LRSWzMar_C7iNM06MqrKmpRm_Dk9XXIMCiM,1739
|
70
|
+
janito/cli_chat_shell/commands/session_control.py,sha256=7G4XYfI22fHguJgIbIrbcQ_fIbcrvd1gBBXRuYUqtBU,333
|
71
|
+
janito/cli_chat_shell/commands/system.py,sha256=ixKp6JLagcs6zsXsmTvzSNY4TUFIVzRxhiZfLvI-OJU,2717
|
72
|
+
janito/cli_chat_shell/commands/utility.py,sha256=QUa35hppatRLY24DuXiEIn7gCIcNz4w4qbkRC157QOU,936
|
73
|
+
janito/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
74
|
+
janito/web/__main__.py,sha256=5Ck6okOZmxKYkQ-ir4mxXDH7XWMNR-9szgsm0UyQLE0,734
|
75
|
+
janito/web/app.py,sha256=O4rQSSqRG-N2tk3ho0CTMeybbrCd8pESFqpmiGASHVk,7453
|
76
|
+
janito-1.6.0.dist-info/licenses/LICENSE,sha256=sHBqv0bvtrb29H7WRR-Z603YHm9pLtJIo3nHU_9cmgE,1091
|
77
|
+
janito-1.6.0.dist-info/METADATA,sha256=JyLiizuc2poewVQtV2F2-H4rdut0FK7u5QvyaNiUhMU,10729
|
78
|
+
janito-1.6.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
79
|
+
janito-1.6.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
|
80
|
+
janito-1.6.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
|
81
|
+
janito-1.6.0.dist-info/RECORD,,
|
@@ -1,43 +0,0 @@
|
|
1
|
-
from rich.console import Console
|
2
|
-
console = Console()
|
3
|
-
|
4
|
-
class MessageHandler:
|
5
|
-
"""
|
6
|
-
Unified message handler for all output (tool, agent, system) using Rich for styled output.
|
7
|
-
"""
|
8
|
-
def __init__(self):
|
9
|
-
self.console = console
|
10
|
-
|
11
|
-
def handle_message(self, msg, msg_type=None):
|
12
|
-
"""
|
13
|
-
Handles either a dict (with 'type' and 'message') or a plain string.
|
14
|
-
If dict: uses type/message. If str: uses msg_type or defaults to 'info'.
|
15
|
-
"""
|
16
|
-
from rich.markdown import Markdown
|
17
|
-
if isinstance(msg, dict):
|
18
|
-
msg_type = msg.get("type", "info")
|
19
|
-
message = msg.get("message", "")
|
20
|
-
if msg_type == "content":
|
21
|
-
self.console.print(Markdown(message))
|
22
|
-
elif msg_type == "info":
|
23
|
-
self.console.print(message, style="cyan", end="")
|
24
|
-
elif msg_type == "success":
|
25
|
-
self.console.print(message, style="bold green", end="\n")
|
26
|
-
elif msg_type == "error":
|
27
|
-
self.console.print(message, style="bold red", end="\n")
|
28
|
-
elif msg_type == "progress":
|
29
|
-
self._handle_progress(message)
|
30
|
-
elif msg_type == "warning":
|
31
|
-
self.console.print(message, style="bold yellow", end="\n")
|
32
|
-
elif msg_type == "stdout":
|
33
|
-
from rich.text import Text
|
34
|
-
self.console.print(Text(message, style="on #003300", no_wrap=True, overflow=None), end="")
|
35
|
-
elif msg_type == "stderr":
|
36
|
-
from rich.text import Text
|
37
|
-
self.console.print(Text(message, style="on #330000", no_wrap=True, overflow=None), end="")
|
38
|
-
else:
|
39
|
-
# Ignore unsupported message types silently
|
40
|
-
return
|
41
|
-
else:
|
42
|
-
# Print plain strings as markdown/markup
|
43
|
-
self.console.print(Markdown(str(msg)))
|
@@ -1,38 +0,0 @@
|
|
1
|
-
Your Agent Profile:
|
2
|
-
- Role: {{ role }}
|
3
|
-
|
4
|
-
You are an Agent for an analysis and development tool that operates on files and directories using text-based operations.
|
5
|
-
|
6
|
-
<agent_profile>
|
7
|
-
This Agent operates according to its Agent Profile, which includes system settings, role, and tools.
|
8
|
-
</agent_profile>
|
9
|
-
|
10
|
-
Provide a concise plan before calling any tool.
|
11
|
-
Plan changes only after gathering all the necessary information.
|
12
|
-
Always execute the plan immediately after presenting it, unless the user requests otherwise.
|
13
|
-
|
14
|
-
<context>
|
15
|
-
Always review `README_structure.txt` before conducting file-specific searches.
|
16
|
-
Unless specified otherwise, look for the files that match the questions context.
|
17
|
-
Explore files that might be relevant to the current task.
|
18
|
-
</context>
|
19
|
-
|
20
|
-
<analysis>
|
21
|
-
In case of missing code or functions, look into the .bak files and check git diff/history for recent changes.
|
22
|
-
</analysis>
|
23
|
-
|
24
|
-
<editing>
|
25
|
-
If in doubt during editing, use the `ask_user` function to get additional information; otherwise, proceed and inform the user of the decision made.
|
26
|
-
|
27
|
-
When you need to make changes to a file, consider the following:
|
28
|
-
- It is preferred to replace exact text occurrences over file overwriting.
|
29
|
-
- When replacing files, review their current content before requesting the update.
|
30
|
-
- When reorganizing, moving files, or functions, search for references in other files that might need to be updated accordingly.
|
31
|
-
- After making changes to files, use available tools (such as syntax checkers, linters, or test runners) to validate the files and ensure correctness before proceeding.
|
32
|
-
</editing>
|
33
|
-
|
34
|
-
<finishing>
|
35
|
-
- When asked to commit, check the git diff and summarize the changes in the commit message.
|
36
|
-
- Review the README content if there are user-exposed or public API changes.
|
37
|
-
- Update `README_structure.txt` considering discovered, created, or modified files.
|
38
|
-
</finishing>
|
@@ -1,5 +0,0 @@
|
|
1
|
-
# janito/agent/tool_auto_imports.py
|
2
|
-
# This module imports all tool modules to ensure they are registered via their decorators.
|
3
|
-
# It should be imported only where tool auto-registration is needed, to avoid circular import issues.
|
4
|
-
|
5
|
-
from janito.agent.tools import search_files, run_bash_command, replace_text_in_file, remove_file, remove_directory, py_compile, python_exec, move_file, get_lines, get_file_outline, find_files, fetch_url, create_file, create_directory, ask_user, append_text_to_file
|