janito 2.3.0__py3-none-any.whl → 2.4.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 +6 -6
- janito/_version.py +57 -0
- janito/agent/setup_agent.py +92 -18
- janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
- janito/cli/chat_mode/bindings.py +21 -2
- janito/cli/chat_mode/chat_entry.py +2 -3
- janito/cli/chat_mode/prompt_style.py +5 -0
- janito/cli/chat_mode/session.py +80 -94
- janito/cli/chat_mode/session_profile_select.py +80 -0
- janito/cli/chat_mode/shell/autocomplete.py +21 -21
- janito/cli/chat_mode/shell/commands/__init__.py +13 -7
- janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
- janito/cli/chat_mode/shell/commands/clear.py +12 -12
- janito/cli/chat_mode/shell/commands/conversation_restart.py +30 -0
- janito/cli/chat_mode/shell/commands/execute.py +42 -0
- janito/cli/chat_mode/shell/commands/help.py +6 -3
- janito/cli/chat_mode/shell/commands/model.py +28 -0
- janito/cli/chat_mode/shell/commands/multi.py +51 -51
- janito/cli/chat_mode/shell/commands/read.py +37 -0
- janito/cli/chat_mode/shell/commands/tools.py +45 -18
- janito/cli/chat_mode/shell/commands/write.py +37 -0
- janito/cli/chat_mode/shell/commands.bak.zip +0 -0
- janito/cli/chat_mode/shell/input_history.py +62 -62
- janito/cli/chat_mode/shell/session.bak.zip +0 -0
- janito/cli/chat_mode/toolbar.py +44 -27
- janito/cli/cli_commands/list_models.py +35 -35
- janito/cli/cli_commands/list_providers.py +9 -9
- janito/cli/cli_commands/list_tools.py +86 -53
- janito/cli/cli_commands/model_selection.py +50 -50
- janito/cli/cli_commands/set_api_key.py +19 -19
- janito/cli/cli_commands/show_config.py +51 -51
- janito/cli/cli_commands/show_system_prompt.py +105 -62
- janito/cli/config.py +5 -6
- janito/cli/core/__init__.py +4 -4
- janito/cli/core/event_logger.py +59 -59
- janito/cli/core/runner.py +25 -18
- janito/cli/core/setters.py +10 -1
- janito/cli/core/unsetters.py +54 -54
- janito/cli/main_cli.py +28 -5
- janito/cli/prompt_core.py +18 -2
- janito/cli/prompt_setup.py +56 -0
- janito/cli/single_shot_mode/__init__.py +6 -6
- janito/cli/single_shot_mode/handler.py +14 -73
- janito/cli/verbose_output.py +1 -1
- janito/config.py +5 -5
- janito/config_manager.py +13 -0
- janito/drivers/anthropic/driver.py +113 -113
- janito/drivers/dashscope.bak.zip +0 -0
- janito/drivers/openai/README.md +20 -0
- janito/drivers/openai_responses.bak.zip +0 -0
- janito/event_bus/event.py +2 -2
- janito/formatting_token.py +54 -54
- janito/i18n/__init__.py +35 -35
- janito/i18n/messages.py +23 -23
- janito/i18n/pt.py +46 -47
- janito/llm/README.md +23 -0
- janito/llm/__init__.py +5 -5
- janito/llm/agent.py +507 -443
- janito/llm/driver.py +8 -0
- janito/llm/driver_config_builder.py +34 -34
- janito/llm/driver_input.py +12 -12
- janito/llm/message_parts.py +60 -60
- janito/llm/model.py +38 -38
- janito/llm/provider.py +196 -196
- janito/provider_registry.py +8 -6
- janito/providers/anthropic/model_info.py +22 -22
- janito/providers/anthropic/provider.py +2 -0
- janito/providers/azure_openai/provider.py +3 -0
- janito/providers/dashscope.bak.zip +0 -0
- janito/providers/deepseek/__init__.py +1 -1
- janito/providers/deepseek/model_info.py +16 -16
- janito/providers/deepseek/provider.py +94 -91
- janito/providers/google/provider.py +3 -0
- janito/providers/mistralai/provider.py +3 -0
- janito/providers/openai/provider.py +4 -0
- janito/providers/registry.py +26 -26
- janito/shell.bak.zip +0 -0
- janito/tools/DOCSTRING_STANDARD.txt +33 -0
- janito/tools/README.md +3 -0
- janito/tools/__init__.py +20 -6
- janito/tools/adapters/__init__.py +1 -1
- janito/tools/adapters/local/__init__.py +65 -62
- janito/tools/adapters/local/adapter.py +18 -35
- janito/tools/adapters/local/ask_user.py +101 -102
- janito/tools/adapters/local/copy_file.py +84 -84
- janito/tools/adapters/local/create_directory.py +69 -69
- janito/tools/adapters/local/create_file.py +82 -82
- janito/tools/adapters/local/delete_text_in_file.py +2 -2
- janito/tools/adapters/local/fetch_url.py +97 -97
- janito/tools/adapters/local/find_files.py +139 -138
- janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
- janito/tools/adapters/local/get_file_outline/core.py +117 -117
- janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
- janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
- janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
- janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
- janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
- janito/tools/adapters/local/move_file.py +2 -2
- janito/tools/adapters/local/open_html_in_browser.py +2 -1
- janito/tools/adapters/local/open_url.py +2 -2
- janito/tools/adapters/local/python_code_run.py +166 -166
- janito/tools/adapters/local/python_command_run.py +164 -164
- janito/tools/adapters/local/python_file_run.py +163 -163
- janito/tools/adapters/local/remove_directory.py +2 -2
- janito/tools/adapters/local/remove_file.py +2 -2
- janito/tools/adapters/local/replace_text_in_file.py +2 -2
- janito/tools/adapters/local/run_bash_command.py +176 -176
- janito/tools/adapters/local/run_powershell_command.py +219 -219
- janito/tools/adapters/local/search_text/__init__.py +1 -1
- janito/tools/adapters/local/search_text/core.py +201 -201
- janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
- janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
- janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
- janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
- janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
- janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
- janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
- janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
- janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
- janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
- janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
- janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
- janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
- janito/tools/adapters/local/view_file.py +168 -167
- janito/tools/inspect_registry.py +17 -17
- janito/tools/outline_file.bak.zip +0 -0
- janito/tools/permissions.py +45 -0
- janito/tools/permissions_parse.py +12 -0
- janito/tools/tool_base.py +118 -105
- janito/tools/tool_events.py +58 -58
- janito/tools/tool_run_exception.py +12 -12
- janito/tools/tool_use_tracker.py +81 -81
- janito/tools/tool_utils.py +43 -45
- janito/tools/tools_adapter.py +25 -20
- janito/tools/tools_schema.py +104 -104
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/METADATA +425 -388
- janito-2.4.0.dist-info/RECORD +195 -0
- janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
- janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
- janito/cli/chat_mode/shell/commands/edit.py +0 -25
- janito/cli/chat_mode/shell/commands/exec.py +0 -27
- janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
- janito/cli/termweb_starter.py +0 -122
- janito/termweb/app.py +0 -95
- janito/version.py +0 -4
- janito-2.3.0.dist-info/RECORD +0 -181
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/WHEEL +0 -0
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
- {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/top_level.txt +0 -0
janito/cli/main_cli.py
CHANGED
@@ -14,6 +14,14 @@ from janito.cli.core.event_logger import (
|
|
14
14
|
)
|
15
15
|
|
16
16
|
definition = [
|
17
|
+
(
|
18
|
+
["--profile"],
|
19
|
+
{
|
20
|
+
"metavar": "PROFILE",
|
21
|
+
"help": "Select the profile name for the system prompt (e.g. 'developer').",
|
22
|
+
"default": None,
|
23
|
+
},
|
24
|
+
),
|
17
25
|
(
|
18
26
|
["-W", "--workdir"],
|
19
27
|
{
|
@@ -57,6 +65,20 @@ definition = [
|
|
57
65
|
"help": "Enable execution/run tools (allows running code or shell tools from the CLI)",
|
58
66
|
},
|
59
67
|
),
|
68
|
+
(
|
69
|
+
["-r", "--read"],
|
70
|
+
{
|
71
|
+
"action": "store_true",
|
72
|
+
"help": "Enable tools that require read permissions",
|
73
|
+
},
|
74
|
+
),
|
75
|
+
(
|
76
|
+
["-w", "--write"],
|
77
|
+
{
|
78
|
+
"action": "store_true",
|
79
|
+
"help": "Enable tools that require write permissions",
|
80
|
+
},
|
81
|
+
),
|
60
82
|
(["--unset"], {"metavar": "KEY", "help": "Unset (remove) a config key"}),
|
61
83
|
(["--version"], {"action": "version", "version": None}),
|
62
84
|
(["--list-tools"], {"action": "store_true", "help": "List all registered tools"}),
|
@@ -85,7 +107,6 @@ definition = [
|
|
85
107
|
"help": "Show the resolved system prompt for the main agent",
|
86
108
|
},
|
87
109
|
),
|
88
|
-
(["-r", "--role"], {"metavar": "ROLE", "help": "Set the role for the agent"}),
|
89
110
|
(["-p", "--provider"], {"metavar": "PROVIDER", "help": "Select the provider"}),
|
90
111
|
(["-m", "--model"], {"metavar": "MODEL", "help": "Select the model"}),
|
91
112
|
(
|
@@ -104,7 +125,7 @@ definition = [
|
|
104
125
|
},
|
105
126
|
),
|
106
127
|
(
|
107
|
-
["
|
128
|
+
["--web"],
|
108
129
|
{
|
109
130
|
"action": "store_true",
|
110
131
|
"default": False,
|
@@ -112,11 +133,11 @@ definition = [
|
|
112
133
|
},
|
113
134
|
),
|
114
135
|
(
|
115
|
-
["
|
136
|
+
["---port"],
|
116
137
|
{
|
117
138
|
"type": int,
|
118
139
|
"default": 8088,
|
119
|
-
"help": "Port for the
|
140
|
+
"help": "Port for the server (default: 8088)",
|
120
141
|
},
|
121
142
|
),
|
122
143
|
(["--effort"],
|
@@ -150,10 +171,12 @@ MODIFIER_KEYS = [
|
|
150
171
|
"verbose",
|
151
172
|
"raw",
|
152
173
|
"web",
|
153
|
-
"
|
174
|
+
"_port",
|
154
175
|
"verbose_api",
|
155
176
|
"verbose_tools",
|
156
177
|
"exec",
|
178
|
+
"read",
|
179
|
+
"write",
|
157
180
|
]
|
158
181
|
SETTER_KEYS = ["set", "set_provider", "set_api_key", "unset"]
|
159
182
|
GETTER_KEYS = ["show_config", "list_providers", "list_models", "list_tools"]
|
janito/cli/prompt_core.py
CHANGED
@@ -3,7 +3,7 @@ Core PromptHandler: Handles prompt submission and response formatting for janito
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import time
|
6
|
-
from janito
|
6
|
+
from janito import __version__ as VERSION
|
7
7
|
from janito.performance_collector import PerformanceCollector
|
8
8
|
from rich.status import Status
|
9
9
|
from rich.console import Console
|
@@ -210,7 +210,23 @@ class PromptHandler:
|
|
210
210
|
on_event(final_event)
|
211
211
|
global_event_bus.publish(final_event)
|
212
212
|
except KeyboardInterrupt:
|
213
|
-
|
213
|
+
# Capture user interrupt / cancellation
|
214
|
+
self.console.print("[red]Interrupted by the user.[/red]")
|
215
|
+
try:
|
216
|
+
from janito.driver_events import RequestFinished, RequestStatus
|
217
|
+
# Record a synthetic "cancelled" final event so that downstream
|
218
|
+
# handlers (e.g. single_shot_mode.handler._post_prompt_actions)
|
219
|
+
# can reliably detect that the prompt was interrupted by the
|
220
|
+
# user and avoid showing misleading messages such as
|
221
|
+
# "No output produced by the model.".
|
222
|
+
if hasattr(self, "agent") and self.agent is not None:
|
223
|
+
self.agent.last_event = RequestFinished(
|
224
|
+
status=RequestStatus.CANCELLED,
|
225
|
+
reason="Interrupted by the user",
|
226
|
+
)
|
227
|
+
except Exception:
|
228
|
+
# Do not fail on cleanup – this hook is best-effort only.
|
229
|
+
pass
|
214
230
|
|
215
231
|
def _print_verbose_debug(self, message):
|
216
232
|
if hasattr(self.args, "verbose_agent") and self.args.verbose_agent:
|
@@ -0,0 +1,56 @@
|
|
1
|
+
"""
|
2
|
+
Shared utilities to set up an agent together with a GenericPromptHandler that
|
3
|
+
both single–shot and chat modes can reuse. Having one central place avoids the
|
4
|
+
code duplication that previously existed in `chat_mode.session.ChatSession` and
|
5
|
+
`single_shot_mode.handler.PromptHandler`.
|
6
|
+
"""
|
7
|
+
from __future__ import annotations
|
8
|
+
|
9
|
+
from janito.agent.setup_agent import create_configured_agent
|
10
|
+
from janito.cli.prompt_core import (
|
11
|
+
PromptHandler as GenericPromptHandler,
|
12
|
+
)
|
13
|
+
from typing import Any, Optional
|
14
|
+
|
15
|
+
|
16
|
+
def setup_agent_and_prompt_handler(
|
17
|
+
*,
|
18
|
+
args: Any,
|
19
|
+
provider_instance: Any,
|
20
|
+
llm_driver_config: Any,
|
21
|
+
role: Optional[str] = None,
|
22
|
+
verbose_tools: bool = False,
|
23
|
+
verbose_agent: bool = False,
|
24
|
+
exec_enabled: bool = False,
|
25
|
+
allowed_permissions: Optional[list[str]] = None,
|
26
|
+
profile: Optional[str] = None,
|
27
|
+
profile_system_prompt: Optional[str] = None,
|
28
|
+
conversation_history: Any = None,
|
29
|
+
):
|
30
|
+
"""Create a configured *agent* as well as a *GenericPromptHandler* bound to
|
31
|
+
that agent and return them as a tuple.
|
32
|
+
|
33
|
+
This helper consolidates the repetitive boiler-plate that was scattered
|
34
|
+
across *single-shot* and *chat* modes – both of which need an agent plus a
|
35
|
+
prompt handler that points to that agent.
|
36
|
+
"""
|
37
|
+
agent = create_configured_agent(
|
38
|
+
provider_instance=provider_instance,
|
39
|
+
llm_driver_config=llm_driver_config,
|
40
|
+
role=role,
|
41
|
+
verbose_tools=verbose_tools,
|
42
|
+
verbose_agent=verbose_agent,
|
43
|
+
exec_enabled=exec_enabled,
|
44
|
+
allowed_permissions=allowed_permissions,
|
45
|
+
profile=profile,
|
46
|
+
profile_system_prompt=profile_system_prompt,
|
47
|
+
)
|
48
|
+
|
49
|
+
prompt_handler = GenericPromptHandler(
|
50
|
+
args=args,
|
51
|
+
conversation_history=conversation_history,
|
52
|
+
provider_instance=provider_instance,
|
53
|
+
)
|
54
|
+
prompt_handler.agent = agent
|
55
|
+
|
56
|
+
return agent, prompt_handler
|
@@ -1,6 +1,6 @@
|
|
1
|
-
# janito.cli.single_shot_mode package
|
2
|
-
from .handler import PromptHandler
|
3
|
-
|
4
|
-
__all__ = [
|
5
|
-
"PromptHandler",
|
6
|
-
]
|
1
|
+
# janito.cli.single_shot_mode package
|
2
|
+
from .handler import PromptHandler
|
3
|
+
|
4
|
+
__all__ = [
|
5
|
+
"PromptHandler",
|
6
|
+
]
|
@@ -2,48 +2,32 @@
|
|
2
2
|
PromptHandler: Handles prompt submission and response formatting for janito CLI (one-shot prompt execution).
|
3
3
|
"""
|
4
4
|
|
5
|
-
import
|
6
|
-
|
7
|
-
from janito.cli.
|
8
|
-
from janito.cli.verbose_output import (
|
9
|
-
print_verbose_header,
|
10
|
-
print_performance,
|
11
|
-
handle_exception,
|
12
|
-
)
|
5
|
+
from __future__ import annotations
|
6
|
+
|
7
|
+
from janito.cli.prompt_setup import setup_agent_and_prompt_handler
|
13
8
|
import janito.tools # Ensure all tools are registered
|
14
9
|
from janito.cli.console import shared_console
|
15
10
|
|
16
11
|
|
17
12
|
class PromptHandler:
|
18
|
-
def __init__(self, args, provider_instance, llm_driver_config, role=None, exec_enabled=False):
|
13
|
+
def __init__(self, args, provider_instance, llm_driver_config, role=None, exec_enabled=False, allowed_permissions=None):
|
19
14
|
self.args = args
|
20
15
|
self.provider_instance = provider_instance
|
21
16
|
self.llm_driver_config = llm_driver_config
|
22
17
|
self.role = role
|
23
18
|
self.exec_enabled = exec_enabled
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
self.agent = create_configured_agent(
|
19
|
+
# Instantiate agent together with prompt handler using the shared helper
|
20
|
+
self.agent, self.generic_handler = setup_agent_and_prompt_handler(
|
21
|
+
args=args,
|
28
22
|
provider_instance=provider_instance,
|
29
23
|
llm_driver_config=llm_driver_config,
|
30
24
|
role=role,
|
31
25
|
verbose_tools=getattr(args, "verbose_tools", False),
|
32
26
|
verbose_agent=getattr(args, "verbose_agent", False),
|
33
27
|
exec_enabled=exec_enabled,
|
28
|
+
allowed_permissions=allowed_permissions,
|
29
|
+
profile=getattr(args, "profile", None),
|
34
30
|
)
|
35
|
-
# Setup conversation/history if needed
|
36
|
-
# Dynamically enable/disable execution tools in the registry
|
37
|
-
try:
|
38
|
-
registry = __import__('janito.tools', fromlist=['get_local_tools_adapter']).get_local_tools_adapter()
|
39
|
-
if hasattr(registry, 'set_execution_tools_enabled'):
|
40
|
-
registry.set_execution_tools_enabled(exec_enabled)
|
41
|
-
except Exception as e:
|
42
|
-
shared_console.print(f"[yellow]Warning: Could not update execution tools dynamically in single-shot mode: {e}[/yellow]")
|
43
|
-
self.generic_handler = GenericPromptHandler(
|
44
|
-
args, [], provider_instance=provider_instance
|
45
|
-
)
|
46
|
-
self.generic_handler.agent = self.agent
|
47
31
|
|
48
32
|
def handle(self) -> None:
|
49
33
|
import traceback
|
@@ -75,56 +59,13 @@ class PromptHandler:
|
|
75
59
|
self._post_prompt_actions()
|
76
60
|
|
77
61
|
def _post_prompt_actions(self):
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
from janito.perf_singleton import performance_collector
|
84
|
-
|
85
|
-
token_info = performance_collector.get_last_request_usage()
|
86
|
-
from rich.rule import Rule
|
87
|
-
from rich import print as rich_print
|
88
|
-
from janito.cli.utils import format_tokens
|
89
|
-
|
90
|
-
if token_info:
|
91
|
-
if isinstance(token_info, dict):
|
92
|
-
token_str = " | ".join(
|
93
|
-
f"{k}: {format_tokens(v) if isinstance(v, int) else v}"
|
94
|
-
for k, v in token_info.items()
|
95
|
-
)
|
96
|
-
else:
|
97
|
-
token_str = str(token_info)
|
98
|
-
rich_print(Rule(f"[bold cyan]Token Usage[/bold cyan] {token_str}"))
|
99
|
-
else:
|
100
|
-
rich_print(Rule("[cyan]No token usage info available.[/cyan]"))
|
101
|
-
else:
|
102
|
-
shared_console.print("[yellow]No output produced by the model.[/yellow]")
|
62
|
+
# Align with chat mode: only print token usage summary
|
63
|
+
from janito.formatting_token import print_token_message_summary
|
64
|
+
from janito.perf_singleton import performance_collector
|
65
|
+
usage = performance_collector.get_last_request_usage()
|
66
|
+
print_token_message_summary(shared_console, msg_count=1, usage=usage)
|
103
67
|
self._cleanup_driver_and_console()
|
104
68
|
|
105
|
-
def _print_exit_reason_and_parts(self, final_event):
|
106
|
-
exit_reason = (
|
107
|
-
getattr(final_event, "metadata", {}).get("exit_reason")
|
108
|
-
if hasattr(final_event, "metadata")
|
109
|
-
else None
|
110
|
-
)
|
111
|
-
if exit_reason:
|
112
|
-
print(f"[bold yellow]Exit reason: {exit_reason}[/bold yellow]")
|
113
|
-
parts = getattr(final_event, "parts", None)
|
114
|
-
if not exit_reason:
|
115
|
-
if parts is None or len(parts) == 0:
|
116
|
-
shared_console.print(
|
117
|
-
"[yellow]No output produced by the model.[/yellow]"
|
118
|
-
)
|
119
|
-
else:
|
120
|
-
if hasattr(self.args, "verbose_agent") and self.args.verbose_agent:
|
121
|
-
print(
|
122
|
-
"[yellow]No user-visible output. Model returned the following parts:"
|
123
|
-
)
|
124
|
-
for idx, part in enumerate(parts):
|
125
|
-
print(
|
126
|
-
f" [part {idx}] type: {type(part).__name__} | content: {getattr(part, 'content', repr(part))}"
|
127
|
-
)
|
128
69
|
|
129
70
|
def _cleanup_driver_and_console(self):
|
130
71
|
if hasattr(self.agent, "join_driver"):
|
janito/cli/verbose_output.py
CHANGED
@@ -6,7 +6,7 @@ from rich import print as rich_print
|
|
6
6
|
from rich.align import Align
|
7
7
|
from rich.panel import Panel
|
8
8
|
from rich.text import Text
|
9
|
-
from janito
|
9
|
+
from janito import __version__ as VERSION
|
10
10
|
from janito.cli.utils import format_tokens
|
11
11
|
|
12
12
|
|
janito/config.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
# Shared Janito ConfigManager singleton
|
2
|
-
from janito.config_manager import ConfigManager
|
3
|
-
|
4
|
-
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
-
config = ConfigManager(config_path=None)
|
1
|
+
# Shared Janito ConfigManager singleton
|
2
|
+
from janito.config_manager import ConfigManager
|
3
|
+
|
4
|
+
# Only one global instance! Used by CLI, provider_config, others:
|
5
|
+
config = ConfigManager(config_path=None)
|
janito/config_manager.py
CHANGED
@@ -31,6 +31,19 @@ class ConfigManager:
|
|
31
31
|
self.file_config = {}
|
32
32
|
self.runtime_overrides = dict(runtime_overrides) if runtime_overrides else {}
|
33
33
|
self._load_file_config()
|
34
|
+
self._apply_tool_permissions_on_startup()
|
35
|
+
|
36
|
+
def _apply_tool_permissions_on_startup(self):
|
37
|
+
# On startup, read tool_permissions from config and set global permissions
|
38
|
+
perm_str = self.file_config.get("tool_permissions")
|
39
|
+
if perm_str:
|
40
|
+
try:
|
41
|
+
from janito.tools.permissions_parse import parse_permissions_string
|
42
|
+
from janito.tools.permissions import set_global_allowed_permissions
|
43
|
+
perms = parse_permissions_string(perm_str)
|
44
|
+
set_global_allowed_permissions(perms)
|
45
|
+
except Exception as e:
|
46
|
+
print(f"Warning: Failed to apply tool_permissions from config: {e}")
|
34
47
|
|
35
48
|
def _load_file_config(self):
|
36
49
|
if self.config_path.exists():
|
@@ -1,113 +1,113 @@
|
|
1
|
-
from janito.llm.driver import LLMDriver
|
2
|
-
from janito.llm.driver_config import LLMDriverConfig
|
3
|
-
from janito.driver_events import (
|
4
|
-
GenerationStarted,
|
5
|
-
GenerationFinished,
|
6
|
-
RequestStarted,
|
7
|
-
RequestFinished,
|
8
|
-
ResponseReceived,
|
9
|
-
)
|
10
|
-
from janito.llm.message_parts import TextMessagePart
|
11
|
-
import uuid
|
12
|
-
import traceback
|
13
|
-
import time
|
14
|
-
|
15
|
-
# Safe import of anthropic SDK
|
16
|
-
try:
|
17
|
-
import anthropic
|
18
|
-
|
19
|
-
DRIVER_AVAILABLE = True
|
20
|
-
DRIVER_UNAVAILABLE_REASON = None
|
21
|
-
except ImportError:
|
22
|
-
DRIVER_AVAILABLE = False
|
23
|
-
DRIVER_UNAVAILABLE_REASON = "Missing dependency: anthropic (pip install anthropic)"
|
24
|
-
|
25
|
-
|
26
|
-
class AnthropicModelDriver(LLMDriver):
|
27
|
-
available = False
|
28
|
-
unavailable_reason = "AnthropicModelDriver is not implemented yet."
|
29
|
-
|
30
|
-
@classmethod
|
31
|
-
def is_available(cls):
|
32
|
-
return cls.available
|
33
|
-
|
34
|
-
"""
|
35
|
-
LLMDriver for Anthropic's Claude API (v3), using the anthropic SDK.
|
36
|
-
"""
|
37
|
-
required_config = ["api_key", "model"]
|
38
|
-
|
39
|
-
def __init__(self, tools_adapter=None):
|
40
|
-
raise ImportError(self.unavailable_reason)
|
41
|
-
|
42
|
-
def _create_client(self):
|
43
|
-
try:
|
44
|
-
import anthropic
|
45
|
-
except ImportError:
|
46
|
-
raise Exception(
|
47
|
-
"The 'anthropic' Python SDK is required. Please install via `pip install anthropic`."
|
48
|
-
)
|
49
|
-
return anthropic.Anthropic(api_key=self.api_key)
|
50
|
-
|
51
|
-
def _run_generation(
|
52
|
-
self, messages_or_prompt, system_prompt=None, tools=None, **kwargs
|
53
|
-
):
|
54
|
-
request_id = str(uuid.uuid4())
|
55
|
-
client = self._create_client()
|
56
|
-
try:
|
57
|
-
prompt = ""
|
58
|
-
if isinstance(messages_or_prompt, str):
|
59
|
-
prompt = messages_or_prompt
|
60
|
-
elif isinstance(messages_or_prompt, list):
|
61
|
-
chat = []
|
62
|
-
for msg in messages_or_prompt:
|
63
|
-
if msg.get("role") == "user":
|
64
|
-
chat.append("Human: " + msg.get("content", ""))
|
65
|
-
elif msg.get("role") == "assistant":
|
66
|
-
chat.append("Assistant: " + msg.get("content", ""))
|
67
|
-
prompt = "\n".join(chat)
|
68
|
-
if system_prompt:
|
69
|
-
prompt = f"System: {system_prompt}\n{prompt}"
|
70
|
-
|
71
|
-
self.publish(
|
72
|
-
GenerationStarted,
|
73
|
-
request_id,
|
74
|
-
conversation_history=list(getattr(self, "_history", [])),
|
75
|
-
)
|
76
|
-
self.publish(RequestStarted, request_id, payload={})
|
77
|
-
start_time = time.time()
|
78
|
-
response = client.completions.create(
|
79
|
-
model=self.model_name,
|
80
|
-
max_tokens_to_sample=int(getattr(self.config, "max_response", 1024)),
|
81
|
-
prompt=prompt,
|
82
|
-
temperature=float(getattr(self.config, "default_temp", 0.7)),
|
83
|
-
)
|
84
|
-
duration = time.time() - start_time
|
85
|
-
content = response.completion if hasattr(response, "completion") else None
|
86
|
-
self.publish(
|
87
|
-
RequestFinished,
|
88
|
-
request_id,
|
89
|
-
response=content,
|
90
|
-
status=RequestStatus.SUCCESS,
|
91
|
-
usage={},
|
92
|
-
)
|
93
|
-
parts = []
|
94
|
-
if content:
|
95
|
-
parts.append(TextMessagePart(content=content))
|
96
|
-
self.publish(
|
97
|
-
ResponseReceived,
|
98
|
-
request_id=request_id,
|
99
|
-
parts=parts,
|
100
|
-
tool_results=[],
|
101
|
-
timestamp=time.time(),
|
102
|
-
metadata={"raw_response": response},
|
103
|
-
)
|
104
|
-
self.publish(GenerationFinished, request_id, total_turns=1)
|
105
|
-
except Exception as e:
|
106
|
-
self.publish(
|
107
|
-
RequestFinished,
|
108
|
-
request_id,
|
109
|
-
status=RequestStatus.ERROR,
|
110
|
-
error=str(e),
|
111
|
-
exception=e,
|
112
|
-
traceback=traceback.format_exc(),
|
113
|
-
)
|
1
|
+
from janito.llm.driver import LLMDriver
|
2
|
+
from janito.llm.driver_config import LLMDriverConfig
|
3
|
+
from janito.driver_events import (
|
4
|
+
GenerationStarted,
|
5
|
+
GenerationFinished,
|
6
|
+
RequestStarted,
|
7
|
+
RequestFinished,
|
8
|
+
ResponseReceived,
|
9
|
+
)
|
10
|
+
from janito.llm.message_parts import TextMessagePart
|
11
|
+
import uuid
|
12
|
+
import traceback
|
13
|
+
import time
|
14
|
+
|
15
|
+
# Safe import of anthropic SDK
|
16
|
+
try:
|
17
|
+
import anthropic
|
18
|
+
|
19
|
+
DRIVER_AVAILABLE = True
|
20
|
+
DRIVER_UNAVAILABLE_REASON = None
|
21
|
+
except ImportError:
|
22
|
+
DRIVER_AVAILABLE = False
|
23
|
+
DRIVER_UNAVAILABLE_REASON = "Missing dependency: anthropic (pip install anthropic)"
|
24
|
+
|
25
|
+
|
26
|
+
class AnthropicModelDriver(LLMDriver):
|
27
|
+
available = False
|
28
|
+
unavailable_reason = "AnthropicModelDriver is not implemented yet."
|
29
|
+
|
30
|
+
@classmethod
|
31
|
+
def is_available(cls):
|
32
|
+
return cls.available
|
33
|
+
|
34
|
+
"""
|
35
|
+
LLMDriver for Anthropic's Claude API (v3), using the anthropic SDK.
|
36
|
+
"""
|
37
|
+
required_config = ["api_key", "model"]
|
38
|
+
|
39
|
+
def __init__(self, tools_adapter=None):
|
40
|
+
raise ImportError(self.unavailable_reason)
|
41
|
+
|
42
|
+
def _create_client(self):
|
43
|
+
try:
|
44
|
+
import anthropic
|
45
|
+
except ImportError:
|
46
|
+
raise Exception(
|
47
|
+
"The 'anthropic' Python SDK is required. Please install via `pip install anthropic`."
|
48
|
+
)
|
49
|
+
return anthropic.Anthropic(api_key=self.api_key)
|
50
|
+
|
51
|
+
def _run_generation(
|
52
|
+
self, messages_or_prompt, system_prompt=None, tools=None, **kwargs
|
53
|
+
):
|
54
|
+
request_id = str(uuid.uuid4())
|
55
|
+
client = self._create_client()
|
56
|
+
try:
|
57
|
+
prompt = ""
|
58
|
+
if isinstance(messages_or_prompt, str):
|
59
|
+
prompt = messages_or_prompt
|
60
|
+
elif isinstance(messages_or_prompt, list):
|
61
|
+
chat = []
|
62
|
+
for msg in messages_or_prompt:
|
63
|
+
if msg.get("role") == "user":
|
64
|
+
chat.append("Human: " + msg.get("content", ""))
|
65
|
+
elif msg.get("role") == "assistant":
|
66
|
+
chat.append("Assistant: " + msg.get("content", ""))
|
67
|
+
prompt = "\n".join(chat)
|
68
|
+
if system_prompt:
|
69
|
+
prompt = f"System: {system_prompt}\n{prompt}"
|
70
|
+
|
71
|
+
self.publish(
|
72
|
+
GenerationStarted,
|
73
|
+
request_id,
|
74
|
+
conversation_history=list(getattr(self, "_history", [])),
|
75
|
+
)
|
76
|
+
self.publish(RequestStarted, request_id, payload={})
|
77
|
+
start_time = time.time()
|
78
|
+
response = client.completions.create(
|
79
|
+
model=self.model_name,
|
80
|
+
max_tokens_to_sample=int(getattr(self.config, "max_response", 1024)),
|
81
|
+
prompt=prompt,
|
82
|
+
temperature=float(getattr(self.config, "default_temp", 0.7)),
|
83
|
+
)
|
84
|
+
duration = time.time() - start_time
|
85
|
+
content = response.completion if hasattr(response, "completion") else None
|
86
|
+
self.publish(
|
87
|
+
RequestFinished,
|
88
|
+
request_id,
|
89
|
+
response=content,
|
90
|
+
status=RequestStatus.SUCCESS,
|
91
|
+
usage={},
|
92
|
+
)
|
93
|
+
parts = []
|
94
|
+
if content:
|
95
|
+
parts.append(TextMessagePart(content=content))
|
96
|
+
self.publish(
|
97
|
+
ResponseReceived,
|
98
|
+
request_id=request_id,
|
99
|
+
parts=parts,
|
100
|
+
tool_results=[],
|
101
|
+
timestamp=time.time(),
|
102
|
+
metadata={"raw_response": response},
|
103
|
+
)
|
104
|
+
self.publish(GenerationFinished, request_id, total_turns=1)
|
105
|
+
except Exception as e:
|
106
|
+
self.publish(
|
107
|
+
RequestFinished,
|
108
|
+
request_id,
|
109
|
+
status=RequestStatus.ERROR,
|
110
|
+
error=str(e),
|
111
|
+
exception=e,
|
112
|
+
traceback=traceback.format_exc(),
|
113
|
+
)
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# OpenAI Driver Debugging
|
2
|
+
|
3
|
+
## HTTP Debugging via Environment Variable
|
4
|
+
|
5
|
+
To debug HTTP requests and responses for the OpenAI driver, set the environment variable `OPENAI_DEBUG_HTTP=1` before running your application. This will print the full HTTP request and response bodies to the console for troubleshooting purposes.
|
6
|
+
|
7
|
+
**Example (PowerShell):**
|
8
|
+
|
9
|
+
```
|
10
|
+
$env:OPENAI_DEBUG_HTTP=1
|
11
|
+
python your_app.py
|
12
|
+
```
|
13
|
+
|
14
|
+
**Example (bash):**
|
15
|
+
|
16
|
+
```
|
17
|
+
OPENAI_DEBUG_HTTP=1 python your_app.py
|
18
|
+
```
|
19
|
+
|
20
|
+
This feature is implemented in `janito/drivers/openai/driver.py` and works by wrapping the OpenAI client HTTP transport with a debug logger when the environment variable is set.
|
Binary file
|
janito/event_bus/event.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import attr
|
2
2
|
from typing import ClassVar
|
3
|
-
from datetime import datetime
|
3
|
+
from datetime import datetime, timezone
|
4
4
|
|
5
5
|
|
6
6
|
@attr.s(auto_attribs=True, kw_only=True)
|
@@ -12,4 +12,4 @@ class Event:
|
|
12
12
|
"""
|
13
13
|
|
14
14
|
category: ClassVar[str] = "generic"
|
15
|
-
timestamp: datetime = attr.ib(factory=datetime.
|
15
|
+
timestamp: datetime = attr.ib(factory=lambda: datetime.now(timezone.utc))
|