janito 2.1.0__py3-none-any.whl → 2.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- janito/__init__.py +1 -1
- janito/cli/chat_mode/shell/commands/__init__.py +0 -2
- janito/cli/chat_mode/shell/input_history.py +2 -2
- janito/cli/chat_mode/toolbar.py +2 -1
- janito/cli/config.py +1 -2
- janito/cli/core/runner.py +148 -141
- janito/cli/main_cli.py +8 -0
- janito/drivers/azure_openai/driver.py +21 -2
- janito/llm/provider.py +9 -0
- janito/provider_registry.py +158 -152
- janito/providers/azure_openai/provider.py +20 -0
- janito/providers/deepseek/model_info.py +2 -2
- janito/providers/deepseek/provider.py +1 -1
- janito/providers/openai/model_info.py +0 -11
- janito/providers/openai/provider.py +1 -1
- janito/providers/registry.py +26 -26
- janito/tools/__init__.py +6 -2
- janito/tools/adapters/local/__init__.py +62 -57
- janito/tools/adapters/local/adapter.py +5 -1
- janito/tools/adapters/local/ask_user.py +2 -15
- janito/tools/adapters/local/find_files.py +0 -2
- janito/tools/adapters/local/get_file_outline/core.py +68 -102
- janito/tools/adapters/local/get_file_outline/java_outline.py +40 -0
- janito/tools/adapters/local/open_html_in_browser.py +24 -29
- janito/tools/adapters/local/open_url.py +3 -2
- janito/tools/adapters/local/python_code_run.py +1 -0
- janito/tools/adapters/local/python_command_run.py +1 -0
- janito/tools/adapters/local/python_file_run.py +1 -0
- janito/tools/adapters/local/remove_file.py +5 -5
- janito/version.py +1 -1
- {janito-2.1.0.dist-info → janito-2.2.0.dist-info}/METADATA +21 -2
- {janito-2.1.0.dist-info → janito-2.2.0.dist-info}/RECORD +36 -35
- janito-2.2.0.dist-info/licenses/LICENSE +21 -0
- janito/cli/chat_mode/shell/commands/last.py +0 -137
- {janito-2.1.0.dist-info → janito-2.2.0.dist-info}/WHEEL +0 -0
- {janito-2.1.0.dist-info → janito-2.2.0.dist-info}/entry_points.txt +0 -0
- {janito-2.1.0.dist-info → janito-2.2.0.dist-info}/top_level.txt +0 -0
janito/__init__.py
CHANGED
@@ -3,7 +3,6 @@ from .edit import EditShellHandler
|
|
3
3
|
from .history_view import ViewShellHandler
|
4
4
|
from .lang import LangShellHandler
|
5
5
|
from .livelogs import LivelogsShellHandler
|
6
|
-
from .last import LastShellHandler
|
7
6
|
from .prompt import PromptShellHandler, RoleShellHandler, ProfileShellHandler
|
8
7
|
from .multi import MultiShellHandler
|
9
8
|
from .role import RoleCommandShellHandler
|
@@ -25,7 +24,6 @@ COMMAND_HANDLERS = {
|
|
25
24
|
"/view": ViewShellHandler,
|
26
25
|
"/lang": LangShellHandler,
|
27
26
|
"/livelogs": LivelogsShellHandler,
|
28
|
-
"/last": LastShellHandler,
|
29
27
|
"/prompt": PromptShellHandler,
|
30
28
|
"/role": RoleShellHandler,
|
31
29
|
"/profile": ProfileShellHandler,
|
@@ -7,7 +7,7 @@ from typing import List, Any, Dict
|
|
7
7
|
class UserInputHistory:
|
8
8
|
"""
|
9
9
|
Handles loading, saving, and appending of user input history for the shell.
|
10
|
-
Each day's history is stored in a line-delimited
|
10
|
+
Each day's history is stored in a line-delimited JSONL file (.jsonl) under .janito/input_history/.
|
11
11
|
Each line is a JSON dict, e.g., {"input": ..., "ts": ...}
|
12
12
|
"""
|
13
13
|
|
@@ -17,7 +17,7 @@ class UserInputHistory:
|
|
17
17
|
|
18
18
|
def _get_today_file(self):
|
19
19
|
today_str = datetime.now().strftime("%y%m%d")
|
20
|
-
return os.path.join(self.history_dir, f"{today_str}.
|
20
|
+
return os.path.join(self.history_dir, f"{today_str}.jsonl")
|
21
21
|
|
22
22
|
def load(self) -> List[Dict[str, Any]]:
|
23
23
|
"""Load today's input history as a list of dicts."""
|
janito/cli/chat_mode/toolbar.py
CHANGED
@@ -22,7 +22,8 @@ def assemble_first_line(provider_name, model_name, role, agent=None):
|
|
22
22
|
|
23
23
|
def assemble_bindings_line(width):
|
24
24
|
return (
|
25
|
-
f" <key-label>
|
25
|
+
f" <key-label>CTRL-C</key-label>: Interrupt Request/Exit Shell | "
|
26
|
+
f"<key-label>F1</key-label>: Restart conversation | "
|
26
27
|
f"<b>/help</b>: Help | "
|
27
28
|
f"<key-label>F12</key-label>: Do It "
|
28
29
|
)
|
janito/cli/config.py
CHANGED
@@ -3,12 +3,11 @@ from janito.config import config
|
|
3
3
|
CONFIG_OPTIONS = {
|
4
4
|
"api_key": "API key for OpenAI-compatible service (required)", # pragma: allowlist secret
|
5
5
|
"trust": "Trust mode: suppress all console output (bool, default: False)",
|
6
|
-
"model": "Model name to use (e.g., 'gpt-4.1', 'gpt-4o', 'gpt-4-turbo', 'o3-mini', 'o4-mini'
|
6
|
+
"model": "Model name to use (e.g., 'gpt-4.1', 'gpt-4o', 'gpt-4-turbo', 'o3-mini', 'o4-mini')",
|
7
7
|
"base_url": "API base URL (OpenAI-compatible endpoint)",
|
8
8
|
"role": "Role description for the Agent Profile (e.g., 'software engineer')",
|
9
9
|
"temperature": "Sampling temperature (float, e.g., 0.0 - 2.0)",
|
10
10
|
"max_tokens": "Maximum tokens for model response (int)",
|
11
|
-
"use_azure_openai": "Whether to use Azure OpenAI client (default: False)",
|
12
11
|
"template": "Template context dictionary for Agent Profile prompt rendering (nested)",
|
13
12
|
"profile": "Agent Profile name (only 'base' is supported)",
|
14
13
|
}
|
janito/cli/core/runner.py
CHANGED
@@ -1,141 +1,148 @@
|
|
1
|
-
"""Handles LLM driver config preparation and execution modes."""
|
2
|
-
|
3
|
-
from janito.llm.driver_config import LLMDriverConfig
|
4
|
-
from janito.provider_config import get_config_provider
|
5
|
-
from janito.cli.verbose_output import print_verbose_info
|
6
|
-
|
7
|
-
|
8
|
-
def _choose_provider(args):
|
9
|
-
provider = getattr(args, "provider", None)
|
10
|
-
if provider is None:
|
11
|
-
provider = get_config_provider()
|
12
|
-
if provider and getattr(args, "verbose", False):
|
13
|
-
print_verbose_info(
|
14
|
-
"Default provider", provider, style="magenta", align_content=True
|
15
|
-
)
|
16
|
-
elif provider is None:
|
17
|
-
print(
|
18
|
-
"Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
19
|
-
)
|
20
|
-
return None
|
21
|
-
return provider
|
22
|
-
|
23
|
-
|
24
|
-
def _populate_driver_config_data(args, modifiers, provider, model):
|
25
|
-
from janito.provider_config import get_effective_setting
|
26
|
-
|
27
|
-
CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
|
28
|
-
driver_config_data = {"model": model}
|
29
|
-
if getattr(args, "verbose_api", None) is not None:
|
30
|
-
driver_config_data["verbose_api"] = args.verbose_api
|
31
|
-
for field in LLMDriverConfig.__dataclass_fields__:
|
32
|
-
if field in CONFIG_LOOKUP_KEYS:
|
33
|
-
if field in modifiers and modifiers[field] is not None:
|
34
|
-
driver_config_data[field] = modifiers[field]
|
35
|
-
else:
|
36
|
-
value = get_effective_setting(provider, model, field)
|
37
|
-
if value is not None:
|
38
|
-
driver_config_data[field] = value
|
39
|
-
elif field in modifiers and field != "model":
|
40
|
-
driver_config_data[field] = modifiers[field]
|
41
|
-
return driver_config_data
|
42
|
-
|
43
|
-
|
44
|
-
def prepare_llm_driver_config(args, modifiers):
|
45
|
-
"""Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
|
46
|
-
|
47
|
-
This helper additionally validates that the chosen ``--model`` (or the
|
48
|
-
resolved model coming from config precedence) is actually available for the
|
49
|
-
selected provider. If the combination is invalid an error is printed and
|
50
|
-
``None`` is returned for the config so that the caller can abort execution
|
51
|
-
gracefully.
|
52
|
-
"""
|
53
|
-
provider = _choose_provider(args)
|
54
|
-
if provider is None:
|
55
|
-
return None, None, None
|
56
|
-
from janito.provider_config import get_effective_model
|
57
|
-
|
58
|
-
model = getattr(args, "model", None)
|
59
|
-
if not model:
|
60
|
-
model = get_effective_model(provider)
|
61
|
-
|
62
|
-
# Validate that the chosen model is supported by the selected provider
|
63
|
-
if model:
|
64
|
-
from janito.provider_registry import ProviderRegistry
|
65
|
-
|
66
|
-
provider_instance = None
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
print
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
handler
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
1
|
+
"""Handles LLM driver config preparation and execution modes."""
|
2
|
+
|
3
|
+
from janito.llm.driver_config import LLMDriverConfig
|
4
|
+
from janito.provider_config import get_config_provider
|
5
|
+
from janito.cli.verbose_output import print_verbose_info
|
6
|
+
|
7
|
+
|
8
|
+
def _choose_provider(args):
|
9
|
+
provider = getattr(args, "provider", None)
|
10
|
+
if provider is None:
|
11
|
+
provider = get_config_provider()
|
12
|
+
if provider and getattr(args, "verbose", False):
|
13
|
+
print_verbose_info(
|
14
|
+
"Default provider", provider, style="magenta", align_content=True
|
15
|
+
)
|
16
|
+
elif provider is None:
|
17
|
+
print(
|
18
|
+
"Error: No provider selected and no provider found in config. Please set a provider using '-p PROVIDER', '--set provider=name', or configure a provider."
|
19
|
+
)
|
20
|
+
return None
|
21
|
+
return provider
|
22
|
+
|
23
|
+
|
24
|
+
def _populate_driver_config_data(args, modifiers, provider, model):
|
25
|
+
from janito.provider_config import get_effective_setting
|
26
|
+
|
27
|
+
CONFIG_LOOKUP_KEYS = ("max_tokens", "base_url")
|
28
|
+
driver_config_data = {"model": model}
|
29
|
+
if getattr(args, "verbose_api", None) is not None:
|
30
|
+
driver_config_data["verbose_api"] = args.verbose_api
|
31
|
+
for field in LLMDriverConfig.__dataclass_fields__:
|
32
|
+
if field in CONFIG_LOOKUP_KEYS:
|
33
|
+
if field in modifiers and modifiers[field] is not None:
|
34
|
+
driver_config_data[field] = modifiers[field]
|
35
|
+
else:
|
36
|
+
value = get_effective_setting(provider, model, field)
|
37
|
+
if value is not None:
|
38
|
+
driver_config_data[field] = value
|
39
|
+
elif field in modifiers and field != "model":
|
40
|
+
driver_config_data[field] = modifiers[field]
|
41
|
+
return driver_config_data
|
42
|
+
|
43
|
+
|
44
|
+
def prepare_llm_driver_config(args, modifiers):
|
45
|
+
"""Prepare the LLMDriverConfig instance based on CLI *args* and *modifiers*.
|
46
|
+
|
47
|
+
This helper additionally validates that the chosen ``--model`` (or the
|
48
|
+
resolved model coming from config precedence) is actually available for the
|
49
|
+
selected provider. If the combination is invalid an error is printed and
|
50
|
+
``None`` is returned for the config so that the caller can abort execution
|
51
|
+
gracefully.
|
52
|
+
"""
|
53
|
+
provider = _choose_provider(args)
|
54
|
+
if provider is None:
|
55
|
+
return None, None, None
|
56
|
+
from janito.provider_config import get_effective_model
|
57
|
+
|
58
|
+
model = getattr(args, "model", None)
|
59
|
+
if not model:
|
60
|
+
model = get_effective_model(provider)
|
61
|
+
|
62
|
+
# Validate that the chosen model is supported by the selected provider
|
63
|
+
if model:
|
64
|
+
from janito.provider_registry import ProviderRegistry
|
65
|
+
|
66
|
+
provider_instance = None
|
67
|
+
provider_instance = ProviderRegistry().get_instance(provider)
|
68
|
+
if provider_instance is None:
|
69
|
+
return provider, None, None
|
70
|
+
try:
|
71
|
+
if not provider_instance.is_model_available(model):
|
72
|
+
print(
|
73
|
+
f"Error: Model '{model}' is not available for provider '{provider}'."
|
74
|
+
)
|
75
|
+
# Optionally, print available models if possible
|
76
|
+
if hasattr(provider_instance, 'get_model_info'):
|
77
|
+
available_models = [
|
78
|
+
m["name"]
|
79
|
+
for m in provider_instance.get_model_info().values()
|
80
|
+
if isinstance(m, dict) and "name" in m
|
81
|
+
]
|
82
|
+
print(f"Available models: {', '.join(available_models)}")
|
83
|
+
return provider, None, None
|
84
|
+
except Exception as e:
|
85
|
+
print(f"Error validating model for provider '{provider}': {e}")
|
86
|
+
return provider, None, None
|
87
|
+
driver_config_data = _populate_driver_config_data(args, modifiers, provider, model)
|
88
|
+
llm_driver_config = LLMDriverConfig(**driver_config_data)
|
89
|
+
if getattr(llm_driver_config, "verbose_api", None):
|
90
|
+
pass
|
91
|
+
agent_role = modifiers.get("role", "software developer")
|
92
|
+
return provider, llm_driver_config, agent_role
|
93
|
+
|
94
|
+
|
95
|
+
def handle_runner(args, provider, llm_driver_config, agent_role, verbose_tools=False, exec_enabled=False):
|
96
|
+
"""
|
97
|
+
Main runner for CLI execution. If exec_enabled is False, disables execution/run tools.
|
98
|
+
"""
|
99
|
+
zero_mode = getattr(args, "zero", False)
|
100
|
+
from janito.provider_registry import ProviderRegistry
|
101
|
+
|
102
|
+
# Patch: disable execution/run tools if not enabled
|
103
|
+
if not exec_enabled:
|
104
|
+
import janito.tools
|
105
|
+
adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
|
106
|
+
if hasattr(adapter, "disable_execution_tools"):
|
107
|
+
adapter.disable_execution_tools()
|
108
|
+
else:
|
109
|
+
import janito.tools
|
110
|
+
adapter = janito.tools.get_local_tools_adapter(workdir=getattr(args, "workdir", None))
|
111
|
+
|
112
|
+
provider_instance = ProviderRegistry().get_instance(provider, llm_driver_config)
|
113
|
+
if provider_instance is None:
|
114
|
+
return
|
115
|
+
mode = get_prompt_mode(args)
|
116
|
+
if getattr(args, "verbose", False):
|
117
|
+
print_verbose_info(
|
118
|
+
"Active LLMDriverConfig (after provider)", llm_driver_config, style="green"
|
119
|
+
)
|
120
|
+
print_verbose_info("Agent role", agent_role, style="green")
|
121
|
+
if mode == "single_shot":
|
122
|
+
from janito.cli.single_shot_mode.handler import (
|
123
|
+
PromptHandler as SingleShotPromptHandler,
|
124
|
+
)
|
125
|
+
|
126
|
+
handler = SingleShotPromptHandler(
|
127
|
+
args, provider_instance, llm_driver_config, role=agent_role
|
128
|
+
)
|
129
|
+
handler.handle()
|
130
|
+
else:
|
131
|
+
from janito.cli.chat_mode.session import ChatSession
|
132
|
+
from rich.console import Console
|
133
|
+
|
134
|
+
console = Console()
|
135
|
+
session = ChatSession(
|
136
|
+
console,
|
137
|
+
provider_instance,
|
138
|
+
llm_driver_config,
|
139
|
+
role=agent_role,
|
140
|
+
args=args,
|
141
|
+
verbose_tools=verbose_tools,
|
142
|
+
verbose_agent=getattr(args, "verbose_agent", False),
|
143
|
+
)
|
144
|
+
session.run()
|
145
|
+
|
146
|
+
|
147
|
+
def get_prompt_mode(args):
|
148
|
+
return "single_shot" if getattr(args, "user_prompt", None) else "chat_mode"
|
janito/cli/main_cli.py
CHANGED
@@ -13,6 +13,14 @@ from janito.cli.core.event_logger import (
|
|
13
13
|
)
|
14
14
|
|
15
15
|
definition = [
|
16
|
+
(
|
17
|
+
["-W", "--workdir"],
|
18
|
+
{
|
19
|
+
"metavar": "WORKDIR",
|
20
|
+
"help": "Working directory to chdir to before tool execution",
|
21
|
+
"default": None,
|
22
|
+
},
|
23
|
+
),
|
16
24
|
(
|
17
25
|
["--verbose-api"],
|
18
26
|
{
|
@@ -28,9 +28,28 @@ class AzureOpenAIModelDriver(OpenAIModelDriver):
|
|
28
28
|
raise ImportError(
|
29
29
|
f"AzureOpenAIModelDriver unavailable: {self.unavailable_reason}"
|
30
30
|
)
|
31
|
-
super().__init__
|
31
|
+
# Do NOT call super().__init__ if Azure SDK is not available
|
32
|
+
OpenAIModelDriver.__init__(self, tools_adapter=tools_adapter)
|
32
33
|
self.azure_endpoint = None
|
33
34
|
self.api_version = None
|
34
35
|
self.api_key = None
|
35
36
|
|
36
|
-
|
37
|
+
def _instantiate_openai_client(self, config):
|
38
|
+
try:
|
39
|
+
from openai import AzureOpenAI
|
40
|
+
api_key_display = str(config.api_key)
|
41
|
+
if api_key_display and len(api_key_display) > 8:
|
42
|
+
api_key_display = api_key_display[:4] + "..." + api_key_display[-4:]
|
43
|
+
client_kwargs = {
|
44
|
+
"api_key": config.api_key,
|
45
|
+
"azure_endpoint": getattr(config, "base_url", None),
|
46
|
+
"api_version": config.extra.get("api_version", "2023-05-15"),
|
47
|
+
}
|
48
|
+
client = AzureOpenAI(**client_kwargs)
|
49
|
+
return client
|
50
|
+
except Exception as e:
|
51
|
+
print(f"[ERROR] Exception during AzureOpenAI client instantiation: {e}", flush=True)
|
52
|
+
import traceback
|
53
|
+
print(traceback.format_exc(), flush=True)
|
54
|
+
raise
|
55
|
+
|
janito/llm/provider.py
CHANGED
@@ -93,6 +93,15 @@ class LLMProvider(ABC):
|
|
93
93
|
def driver(self) -> LLMDriver:
|
94
94
|
pass
|
95
95
|
|
96
|
+
def is_model_available(self, model_name):
|
97
|
+
"""
|
98
|
+
Returns True if the given model is available for this provider.
|
99
|
+
Default implementation checks MODEL_SPECS; override for dynamic providers.
|
100
|
+
"""
|
101
|
+
if not hasattr(self, "MODEL_SPECS"):
|
102
|
+
return False
|
103
|
+
return model_name in self.MODEL_SPECS
|
104
|
+
|
96
105
|
def get_model_info(self, model_name=None):
|
97
106
|
"""
|
98
107
|
Return the info dict for a given model (driver, params, etc). If model_name is None, return all model info dicts.
|