janito 2.7.0__py3-none-any.whl → 2.9.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.
Files changed (121) hide show
  1. janito/__init__.py +0 -1
  2. janito/__main__.py +0 -1
  3. janito/_version.py +0 -3
  4. janito/agent/setup_agent.py +77 -10
  5. janito/agent/templates/profiles/{system_prompt_template_plain_software_developer.txt.j2 → system_prompt_template_Developer_with_Python_Tools.txt.j2} +5 -1
  6. janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +3 -12
  7. janito/cli/__init__.py +0 -1
  8. janito/cli/chat_mode/bindings.py +1 -1
  9. janito/cli/chat_mode/chat_entry.py +0 -2
  10. janito/cli/chat_mode/prompt_style.py +0 -3
  11. janito/cli/chat_mode/script_runner.py +9 -5
  12. janito/cli/chat_mode/session.py +100 -37
  13. janito/cli/chat_mode/session_profile_select.py +61 -52
  14. janito/cli/chat_mode/shell/commands/__init__.py +1 -5
  15. janito/cli/chat_mode/shell/commands/_priv_check.py +1 -0
  16. janito/cli/chat_mode/shell/commands/_priv_status.py +13 -0
  17. janito/cli/chat_mode/shell/commands/bang.py +10 -3
  18. janito/cli/chat_mode/shell/commands/conversation_restart.py +24 -7
  19. janito/cli/chat_mode/shell/commands/execute.py +22 -7
  20. janito/cli/chat_mode/shell/commands/help.py +4 -1
  21. janito/cli/chat_mode/shell/commands/model.py +13 -5
  22. janito/cli/chat_mode/shell/commands/privileges.py +21 -0
  23. janito/cli/chat_mode/shell/commands/prompt.py +0 -2
  24. janito/cli/chat_mode/shell/commands/read.py +22 -5
  25. janito/cli/chat_mode/shell/commands/tools.py +15 -4
  26. janito/cli/chat_mode/shell/commands/write.py +22 -5
  27. janito/cli/chat_mode/shell/input_history.py +3 -1
  28. janito/cli/chat_mode/shell/session/manager.py +0 -2
  29. janito/cli/chat_mode/toolbar.py +25 -19
  30. janito/cli/cli_commands/list_config.py +31 -0
  31. janito/cli/cli_commands/list_models.py +1 -1
  32. janito/cli/cli_commands/list_profiles.py +79 -0
  33. janito/cli/cli_commands/list_providers.py +1 -0
  34. janito/cli/cli_commands/list_tools.py +35 -7
  35. janito/cli/cli_commands/model_utils.py +5 -3
  36. janito/cli/cli_commands/show_config.py +16 -11
  37. janito/cli/cli_commands/show_system_prompt.py +23 -9
  38. janito/cli/config.py +0 -13
  39. janito/cli/core/getters.py +16 -1
  40. janito/cli/core/runner.py +25 -8
  41. janito/cli/core/setters.py +13 -76
  42. janito/cli/main_cli.py +60 -27
  43. janito/cli/prompt_core.py +19 -18
  44. janito/cli/prompt_setup.py +6 -3
  45. janito/cli/rich_terminal_reporter.py +19 -5
  46. janito/cli/single_shot_mode/handler.py +14 -5
  47. janito/cli/verbose_output.py +5 -1
  48. janito/config.py +1 -0
  49. janito/config_manager.py +15 -2
  50. janito/drivers/azure_openai/driver.py +27 -30
  51. janito/drivers/openai/driver.py +53 -36
  52. janito/formatting_token.py +12 -4
  53. janito/llm/agent.py +15 -6
  54. janito/llm/driver.py +1 -0
  55. janito/llm/provider.py +1 -1
  56. janito/provider_registry.py +31 -70
  57. janito/providers/__init__.py +1 -0
  58. janito/providers/anthropic/model_info.py +0 -1
  59. janito/providers/anthropic/provider.py +9 -14
  60. janito/providers/azure_openai/provider.py +10 -5
  61. janito/providers/deepseek/provider.py +5 -4
  62. janito/providers/google/model_info.py +4 -2
  63. janito/providers/google/provider.py +11 -5
  64. janito/providers/groq/__init__.py +1 -0
  65. janito/providers/groq/model_info.py +45 -0
  66. janito/providers/groq/provider.py +76 -0
  67. janito/providers/moonshotai/provider.py +11 -4
  68. janito/providers/openai/model_info.py +0 -1
  69. janito/providers/openai/provider.py +6 -7
  70. janito/tools/__init__.py +2 -0
  71. janito/tools/adapters/local/__init__.py +2 -1
  72. janito/tools/adapters/local/adapter.py +21 -4
  73. janito/tools/adapters/local/ask_user.py +1 -0
  74. janito/tools/adapters/local/copy_file.py +1 -0
  75. janito/tools/adapters/local/create_directory.py +1 -0
  76. janito/tools/adapters/local/create_file.py +1 -0
  77. janito/tools/adapters/local/delete_text_in_file.py +2 -1
  78. janito/tools/adapters/local/fetch_url.py +1 -0
  79. janito/tools/adapters/local/find_files.py +7 -6
  80. janito/tools/adapters/local/get_file_outline/core.py +1 -0
  81. janito/tools/adapters/local/get_file_outline/java_outline.py +22 -15
  82. janito/tools/adapters/local/get_file_outline/search_outline.py +1 -0
  83. janito/tools/adapters/local/move_file.py +1 -0
  84. janito/tools/adapters/local/open_html_in_browser.py +15 -5
  85. janito/tools/adapters/local/open_url.py +1 -0
  86. janito/tools/adapters/local/python_code_run.py +1 -0
  87. janito/tools/adapters/local/python_command_run.py +1 -0
  88. janito/tools/adapters/local/python_file_run.py +1 -0
  89. janito/tools/adapters/local/read_files.py +19 -4
  90. janito/tools/adapters/local/remove_directory.py +1 -0
  91. janito/tools/adapters/local/remove_file.py +1 -0
  92. janito/tools/adapters/local/replace_text_in_file.py +4 -3
  93. janito/tools/adapters/local/run_bash_command.py +1 -0
  94. janito/tools/adapters/local/run_powershell_command.py +1 -0
  95. janito/tools/adapters/local/search_text/core.py +18 -17
  96. janito/tools/adapters/local/search_text/match_lines.py +5 -5
  97. janito/tools/adapters/local/search_text/pattern_utils.py +1 -1
  98. janito/tools/adapters/local/search_text/traverse_directory.py +7 -7
  99. janito/tools/adapters/local/validate_file_syntax/core.py +1 -1
  100. janito/tools/adapters/local/validate_file_syntax/html_validator.py +8 -1
  101. janito/tools/disabled_tools.py +68 -0
  102. janito/tools/path_security.py +18 -11
  103. janito/tools/permissions.py +6 -0
  104. janito/tools/permissions_parse.py +4 -3
  105. janito/tools/tool_base.py +11 -5
  106. janito/tools/tool_use_tracker.py +1 -4
  107. janito/tools/tool_utils.py +1 -1
  108. janito/tools/tools_adapter.py +57 -25
  109. {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/METADATA +11 -19
  110. janito-2.9.0.dist-info/RECORD +205 -0
  111. janito/cli/chat_mode/shell/commands/livelogs.py +0 -49
  112. janito/drivers/mistralai/driver.py +0 -41
  113. janito/providers/mistralai/model_info.py +0 -37
  114. janito/providers/mistralai/provider.py +0 -72
  115. janito/providers/provider_static_info.py +0 -21
  116. janito-2.7.0.dist-info/RECORD +0 -202
  117. /janito/agent/templates/profiles/{system_prompt_template_assistant.txt.j2 → system_prompt_template_model_conversation_without_tools_or_context.txt.j2} +0 -0
  118. {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/WHEEL +0 -0
  119. {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/entry_points.txt +0 -0
  120. {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/licenses/LICENSE +0 -0
  121. {janito-2.7.0.dist-info → janito-2.9.0.dist-info}/top_level.txt +0 -0
@@ -11,12 +11,13 @@ from janito.drivers.azure_openai.driver import AzureOpenAIModelDriver
11
11
 
12
12
  available = AzureOpenAIModelDriver.available
13
13
  unavailable_reason = AzureOpenAIModelDriver.unavailable_reason
14
- maintainer = "João Pinto <lamego.pinto@gmail.com>"
14
+ maintainer = "João Pinto <janito@ikignosis.org>"
15
15
 
16
16
 
17
17
  class AzureOpenAIProvider(LLMProvider):
18
18
  name = "azure_openai"
19
- maintainer = "João Pinto <lamego.pinto@gmail.com>"
19
+ NAME = "azure_openai"
20
+ MAINTAINER = "João Pinto <janito@ikignosis.org>"
20
21
  MODEL_SPECS = MODEL_SPECS
21
22
  DEFAULT_MODEL = "azure_openai_deployment"
22
23
 
@@ -30,7 +31,7 @@ class AzureOpenAIProvider(LLMProvider):
30
31
  self._driver = None
31
32
  return
32
33
  self._auth_manager = auth_manager or LLMAuthManager()
33
- self._api_key = self._auth_manager.get_credentials(type(self).name)
34
+ self._api_key = self._auth_manager.get_credentials(type(self).NAME)
34
35
  self._tools_adapter = get_local_tools_adapter()
35
36
  self._driver_config = config or LLMDriverConfig(model=None)
36
37
  if not self._driver_config.model:
@@ -41,6 +42,7 @@ class AzureOpenAIProvider(LLMProvider):
41
42
  self._driver_config.extra["api_version"] = "2023-05-15"
42
43
  # Inject azure_deployment_name from config if present
43
44
  from janito.config import config as global_config
45
+
44
46
  deployment_name = global_config.get("azure_deployment_name")
45
47
  if deployment_name:
46
48
  self._driver_config.extra["azure_deployment_name"] = deployment_name
@@ -76,7 +78,10 @@ class AzureOpenAIProvider(LLMProvider):
76
78
  """
77
79
  if model_name is None:
78
80
  # Return all known specs, but note: only static ones are listed
79
- return {name: model_info.to_dict() for name, model_info in self.MODEL_SPECS.items()}
81
+ return {
82
+ name: model_info.to_dict()
83
+ for name, model_info in self.MODEL_SPECS.items()
84
+ }
80
85
  if model_name in self.MODEL_SPECS:
81
86
  return self.MODEL_SPECS[model_name].to_dict()
82
87
  # Accept any deployment name as a valid model
@@ -120,4 +125,4 @@ class AzureOpenAIProvider(LLMProvider):
120
125
  return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
121
126
 
122
127
 
123
- LLMProviderRegistry.register(AzureOpenAIProvider.name, AzureOpenAIProvider)
128
+ LLMProviderRegistry.register(AzureOpenAIProvider.NAME, AzureOpenAIProvider)
@@ -12,9 +12,10 @@ available = OpenAIModelDriver.available
12
12
  unavailable_reason = OpenAIModelDriver.unavailable_reason
13
13
 
14
14
 
15
- class DeepseekProvider(LLMProvider):
15
+ class DeepSeekProvider(LLMProvider):
16
16
  name = "deepseek"
17
- maintainer = "Needs maintainer"
17
+ NAME = "deepseek"
18
+ MAINTAINER = "João Pinto <janito@ikignosis.org>"
18
19
  MODEL_SPECS = MODEL_SPECS
19
20
  DEFAULT_MODEL = "deepseek-chat" # Options: deepseek-chat, deepseek-reasoner
20
21
 
@@ -28,7 +29,7 @@ class DeepseekProvider(LLMProvider):
28
29
  self._driver = None
29
30
  else:
30
31
  self.auth_manager = auth_manager or LLMAuthManager()
31
- self._api_key = self.auth_manager.get_credentials(type(self).name)
32
+ self._api_key = self.auth_manager.get_credentials(type(self).NAME)
32
33
  self._tools_adapter = get_local_tools_adapter()
33
34
  self._driver_config = config or LLMDriverConfig(model=None)
34
35
  if not self._driver_config.model:
@@ -91,4 +92,4 @@ class DeepseekProvider(LLMProvider):
91
92
  return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
92
93
 
93
94
 
94
- LLMProviderRegistry.register(DeepseekProvider.name, DeepseekProvider)
95
+ LLMProviderRegistry.register(DeepSeekProvider.NAME, DeepSeekProvider)
@@ -10,7 +10,7 @@ MODEL_SPECS = {
10
10
  max_cot=24576,
11
11
  thinking_supported=True,
12
12
  ),
13
- "gemini-2.5-pro": LLMModelInfo(
13
+ "gemini-2.5-pro": LLMModelInfo(
14
14
  name="gemini-2.5-pro",
15
15
  other={"description": "Google Gemini 2.5 Pro (OpenAI-compatible endpoint)"},
16
16
  open="google",
@@ -21,7 +21,9 @@ MODEL_SPECS = {
21
21
  ),
22
22
  "gemini-2.5-flash-lite-preview-06-17": LLMModelInfo(
23
23
  name="gemini-2.5-flash-lite-preview-06-17",
24
- other={"description": "Google Gemini 2.5 Flash-Lite Preview (OpenAI-compatible endpoint)"},
24
+ other={
25
+ "description": "Google Gemini 2.5 Flash-Lite Preview (OpenAI-compatible endpoint)"
26
+ },
25
27
  open="google",
26
28
  driver="OpenAIModelDriver",
27
29
  max_response=64000,
@@ -13,9 +13,11 @@ try:
13
13
  except ImportError:
14
14
  MODEL_SPECS = {}
15
15
 
16
+
16
17
  class GoogleProvider(LLMProvider):
17
18
  name = "google"
18
- maintainer = "João Pinto <lamego.pinto@gmail.com>"
19
+ NAME = "google"
20
+ MAINTAINER = "João Pinto <janito@ikignosis.org>"
19
21
  MODEL_SPECS = MODEL_SPECS
20
22
  DEFAULT_MODEL = "gemini-2.5-flash" # Default Gemini model
21
23
 
@@ -33,19 +35,23 @@ class GoogleProvider(LLMProvider):
33
35
  self._tools_adapter = get_local_tools_adapter()
34
36
  self._driver_config = config or LLMDriverConfig(model=None)
35
37
  # Only set default if model is not set by CLI/config
36
- if not getattr(self._driver_config, 'model', None):
38
+ if not getattr(self._driver_config, "model", None):
37
39
  self._driver_config.model = self.DEFAULT_MODEL
38
40
  if not self._driver_config.api_key:
39
41
  self._driver_config.api_key = self._api_key
40
42
  # Set the Gemini API endpoint for OpenAI compatibility
41
- self._driver_config.base_url = "https://generativelanguage.googleapis.com/v1beta/openai/"
43
+ self._driver_config.base_url = (
44
+ "https://generativelanguage.googleapis.com/v1beta/openai/"
45
+ )
42
46
  self.fill_missing_device_info(self._driver_config)
43
47
  self._driver = None # to be provided by factory/agent
44
48
 
45
49
  @property
46
50
  def driver(self) -> OpenAIModelDriver:
47
51
  if not self.available:
48
- raise ImportError(f"GoogleOpenAIProvider unavailable: {self.unavailable_reason}")
52
+ raise ImportError(
53
+ f"GoogleOpenAIProvider unavailable: {self.unavailable_reason}"
54
+ )
49
55
  return self._driver
50
56
 
51
57
  @property
@@ -80,4 +86,4 @@ class GoogleProvider(LLMProvider):
80
86
  return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
81
87
 
82
88
 
83
- LLMProviderRegistry.register(GoogleProvider.name, GoogleProvider)
89
+ LLMProviderRegistry.register(GoogleProvider.NAME, GoogleProvider)
@@ -0,0 +1 @@
1
+ from .provider import GroqProvider
@@ -0,0 +1,45 @@
1
+ # Groq provider model specifications
2
+ from janito.llm.model import LLMModelInfo
3
+
4
+ MODEL_SPECS = {
5
+ "moonshotai/kimi-k2-instruct": LLMModelInfo(
6
+ name="moonshotai/kimi-k2-instruct",
7
+ context=128000,
8
+ max_input=122880,
9
+ max_cot="N/A",
10
+ max_response=4096,
11
+ thinking_supported=False,
12
+ default_temp=0.2,
13
+ open="groq",
14
+ driver="GroqModelDriver",
15
+ other={
16
+ "description": "Kimi K2 Instruct model by Moonshot AI",
17
+ "supports_tools": True,
18
+ "supports_streaming": True,
19
+ "supports_vision": False,
20
+ "supports_system_prompt": True,
21
+ "supports_temperature": True,
22
+ "supports_top_p": True,
23
+ "supports_frequency_penalty": True,
24
+ "supports_presence_penalty": True,
25
+ "supports_stop_sequences": True,
26
+ "supports_max_tokens": True,
27
+ "supports_seed": False,
28
+ "supports_json_mode": True,
29
+ "supports_logprobs": False,
30
+ "supports_top_logprobs": False,
31
+ "supports_response_format": True,
32
+ "supports_n": False,
33
+ "supports_best_of": False,
34
+ "supports_echo": False,
35
+ "supports_logit_bias": False,
36
+ "supports_user": False,
37
+ "supports_assistant": False,
38
+ "supports_system": False,
39
+ "supports_functions": True,
40
+ "supports_tool_calls": True,
41
+ "supports_stream_options": False,
42
+ "supports_include_usage": False,
43
+ },
44
+ )
45
+ }
@@ -0,0 +1,76 @@
1
+ from janito.llm.provider import LLMProvider
2
+ from janito.llm.model import LLMModelInfo
3
+ from janito.llm.auth import LLMAuthManager
4
+ from janito.llm.driver_config import LLMDriverConfig
5
+ from janito.drivers.openai.driver import OpenAIModelDriver
6
+ from janito.tools import get_local_tools_adapter
7
+ from janito.providers.registry import LLMProviderRegistry
8
+ from .model_info import MODEL_SPECS
9
+ from queue import Queue
10
+
11
+ available = OpenAIModelDriver.available
12
+ unavailable_reason = OpenAIModelDriver.unavailable_reason
13
+
14
+
15
+ class GroqProvider(LLMProvider):
16
+ name = "groq"
17
+ NAME = "groq"
18
+ MAINTAINER = "Groq Inc. <support@groq.com>"
19
+ MODEL_SPECS = MODEL_SPECS
20
+ DEFAULT_MODEL = "moonshotai/kimi-k2-instruct"
21
+
22
+ def __init__(
23
+ self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
24
+ ):
25
+ if not self.available:
26
+ self._tools_adapter = get_local_tools_adapter()
27
+ self._driver = None
28
+ else:
29
+ self.auth_manager = auth_manager or LLMAuthManager()
30
+ self._api_key = self.auth_manager.get_credentials(type(self).NAME)
31
+ self._tools_adapter = get_local_tools_adapter()
32
+ self._driver_config = config or LLMDriverConfig(model=self.DEFAULT_MODEL)
33
+ if not self._driver_config.model:
34
+ self._driver_config.model = self.DEFAULT_MODEL
35
+
36
+ if not self._driver_config.api_key:
37
+ self._driver_config.api_key = self._api_key
38
+ self._driver_config.base_url = "https://api.groq.com/openai/v1"
39
+ self.fill_missing_device_info(self._driver_config)
40
+ self._driver = None
41
+
42
+ @property
43
+ def driver(self) -> OpenAIModelDriver:
44
+ if not self.available:
45
+ raise ImportError(f"GroqProvider unavailable: {self.unavailable_reason}")
46
+ return self._driver
47
+
48
+ @property
49
+ def available(self):
50
+ return available
51
+
52
+ @property
53
+ def unavailable_reason(self):
54
+ return unavailable_reason
55
+
56
+ def create_driver(self):
57
+ driver = OpenAIModelDriver(
58
+ tools_adapter=self._tools_adapter, provider_name=self.NAME
59
+ )
60
+ driver.config = self._driver_config
61
+ return driver
62
+
63
+ @property
64
+ def model_name(self):
65
+ return self._driver_config.model
66
+
67
+ @property
68
+ def driver_config(self):
69
+ return self._driver_config
70
+
71
+ def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
72
+ self._tools_adapter.event_bus = event_bus
73
+ return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
74
+
75
+
76
+ LLMProviderRegistry.register(GroqProvider.NAME, GroqProvider)
@@ -6,13 +6,17 @@ from janito.tools import get_local_tools_adapter
6
6
  from janito.providers.registry import LLMProviderRegistry
7
7
  from .model_info import MOONSHOTAI_MODEL_SPECS
8
8
 
9
+
9
10
  class MoonshotAIProvider(LLMProvider):
10
11
  name = "moonshotai"
11
- maintainer = "João Pinto <lamego.pinto@gmail.com>"
12
+ NAME = "moonshotai"
13
+ MAINTAINER = "João Pinto <janito@ikignosis.org>"
12
14
  MODEL_SPECS = MOONSHOTAI_MODEL_SPECS
13
15
  DEFAULT_MODEL = "kimi-k2-0711-preview"
14
16
 
15
- def __init__(self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None):
17
+ def __init__(
18
+ self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
19
+ ):
16
20
  if not self.available:
17
21
  self._tools_adapter = get_local_tools_adapter()
18
22
  self._driver = None
@@ -49,7 +53,9 @@ class MoonshotAIProvider(LLMProvider):
49
53
  @property
50
54
  def driver(self) -> OpenAIModelDriver:
51
55
  if not self.available:
52
- raise ImportError(f"MoonshotAIProvider unavailable: {self.unavailable_reason}")
56
+ raise ImportError(
57
+ f"MoonshotAIProvider unavailable: {self.unavailable_reason}"
58
+ )
53
59
  return self._driver
54
60
 
55
61
  @property
@@ -79,4 +85,5 @@ class MoonshotAIProvider(LLMProvider):
79
85
  self._tools_adapter.event_bus = event_bus
80
86
  return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
81
87
 
82
- LLMProviderRegistry.register(MoonshotAIProvider.name, MoonshotAIProvider)
88
+
89
+ LLMProviderRegistry.register(MoonshotAIProvider.NAME, MoonshotAIProvider)
@@ -123,5 +123,4 @@ MODEL_SPECS = {
123
123
  open="openai",
124
124
  driver="OpenAIModelDriver",
125
125
  ),
126
-
127
126
  }
@@ -14,11 +14,10 @@ unavailable_reason = OpenAIModelDriver.unavailable_reason
14
14
 
15
15
  class OpenAIProvider(LLMProvider):
16
16
  name = "openai"
17
- maintainer = "João Pinto <lamego.pinto@gmail.com>"
17
+ NAME = "openai"
18
+ MAINTAINER = "João Pinto <janito@ikignosis.org>"
18
19
  MODEL_SPECS = MODEL_SPECS
19
- DEFAULT_MODEL = (
20
- "gpt-4.1" # Options: gpt-4.1, gpt-4o, o3-mini, o4-mini,
21
- )
20
+ DEFAULT_MODEL = "gpt-4.1" # Options: gpt-4.1, gpt-4o, o3-mini, o4-mini,
22
21
 
23
22
  def __init__(
24
23
  self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
@@ -31,7 +30,7 @@ class OpenAIProvider(LLMProvider):
31
30
  self._driver = None
32
31
  else:
33
32
  self.auth_manager = auth_manager or LLMAuthManager()
34
- self._api_key = self.auth_manager.get_credentials(type(self).name)
33
+ self._api_key = self.auth_manager.get_credentials(type(self).NAME)
35
34
  self._tools_adapter = get_local_tools_adapter()
36
35
  self._driver_config = config or LLMDriverConfig(model=None)
37
36
  if not self._driver_config.model:
@@ -77,7 +76,7 @@ class OpenAIProvider(LLMProvider):
77
76
  Creates and returns a new OpenAIModelDriver instance with input/output queues.
78
77
  """
79
78
  driver = OpenAIModelDriver(
80
- tools_adapter=self._tools_adapter, provider_name=self.name
79
+ tools_adapter=self._tools_adapter, provider_name=self.NAME
81
80
  )
82
81
  driver.config = self._driver_config
83
82
  # NOTE: The caller is responsible for calling driver.start() if background processing is needed.
@@ -108,4 +107,4 @@ class OpenAIProvider(LLMProvider):
108
107
  return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
109
108
 
110
109
 
111
- LLMProviderRegistry.register(OpenAIProvider.name, OpenAIProvider)
110
+ LLMProviderRegistry.register(OpenAIProvider.NAME, OpenAIProvider)
janito/tools/__init__.py CHANGED
@@ -7,6 +7,7 @@ from janito.tools.adapters.local import (
7
7
  def get_local_tools_adapter(workdir=None, allowed_permissions=None):
8
8
  # Use set_verbose_tools on the returned adapter to set verbosity as needed
9
9
  import os
10
+
10
11
  if workdir is not None and not os.path.exists(workdir):
11
12
  os.makedirs(workdir, exist_ok=True)
12
13
  # Permissions are now managed globally; ignore allowed_permissions argument except for backward compatibility
@@ -16,6 +17,7 @@ def get_local_tools_adapter(workdir=None, allowed_permissions=None):
16
17
  if workdir is not None:
17
18
  try:
18
19
  import os
20
+
19
21
  if not os.path.exists(workdir):
20
22
  os.makedirs(workdir, exist_ok=True)
21
23
  os.chdir(workdir)
@@ -31,9 +31,11 @@ from janito.tools.permissions import get_global_allowed_permissions
31
31
  # Singleton tools adapter with all standard tools registered
32
32
  local_tools_adapter = LocalToolsAdapter(workdir=os.getcwd())
33
33
 
34
+
34
35
  def get_local_tools_adapter(workdir=None):
35
36
  return LocalToolsAdapter(workdir=workdir or os.getcwd())
36
37
 
38
+
37
39
  # Register tools
38
40
  for tool_class in [
39
41
  AskUserTool,
@@ -63,4 +65,3 @@ for tool_class in [
63
65
  local_tools_adapter.register_tool(tool_class)
64
66
 
65
67
  # DEBUG: Print registered tools at startup
66
-
@@ -40,6 +40,7 @@ class LocalToolsAdapter(ToolsAdapter):
40
40
  # to UI components even if the caller did not supply a custom bus.
41
41
  if event_bus is None:
42
42
  from janito.event_bus.bus import event_bus as global_event_bus
43
+
43
44
  event_bus = global_event_bus
44
45
 
45
46
  super().__init__(tools=tools, event_bus=event_bus)
@@ -48,6 +49,7 @@ class LocalToolsAdapter(ToolsAdapter):
48
49
  self._tools: Dict[str, Dict[str, Any]] = {}
49
50
 
50
51
  import os
52
+
51
53
  self.workdir = workdir or os.getcwd()
52
54
  # Ensure *some* workdir is set – fallback to CWD.
53
55
  if not self.workdir:
@@ -93,27 +95,39 @@ class LocalToolsAdapter(ToolsAdapter):
93
95
  # Lookup helpers used by ToolsAdapterBase
94
96
  # ------------------------------------------------------------------
95
97
  def get_tool(self, name: str):
96
- return self._tools[name]["instance"] if name in self._tools else None
98
+ from janito.tools.disabled_tools import is_tool_disabled
99
+
100
+ if name in self._tools and not is_tool_disabled(name):
101
+ return self._tools[name]["instance"]
102
+ return None
97
103
 
98
104
  def list_tools(self):
105
+ from janito.tools.disabled_tools import is_tool_disabled
106
+
99
107
  return [
100
108
  name
101
109
  for name, entry in self._tools.items()
102
- if self.is_tool_allowed(entry["instance"])
110
+ if self.is_tool_allowed(entry["instance"]) and not is_tool_disabled(name)
103
111
  ]
104
112
 
105
113
  def get_tool_classes(self):
114
+ from janito.tools.disabled_tools import is_tool_disabled
115
+
106
116
  return [
107
117
  entry["class"]
108
118
  for entry in self._tools.values()
109
119
  if self.is_tool_allowed(entry["instance"])
120
+ and not is_tool_disabled(entry["instance"].tool_name)
110
121
  ]
111
122
 
112
123
  def get_tools(self):
124
+ from janito.tools.disabled_tools import is_tool_disabled
125
+
113
126
  return [
114
127
  entry["instance"]
115
128
  for entry in self._tools.values()
116
129
  if self.is_tool_allowed(entry["instance"])
130
+ and not is_tool_disabled(entry["instance"].tool_name)
117
131
  ]
118
132
 
119
133
  # ------------------------------------------------------------------
@@ -125,7 +139,9 @@ class LocalToolsAdapter(ToolsAdapter):
125
139
  raise TypeError(f"Tool '{tool}' must implement a callable 'run' method.")
126
140
  tool_name = getattr(tool, "tool_name", None)
127
141
  if not tool_name or not isinstance(tool_name, str):
128
- raise ValueError(f"Tool '{tool}' must provide a 'tool_name' (str) attribute.")
142
+ raise ValueError(
143
+ f"Tool '{tool}' must provide a 'tool_name' (str) attribute."
144
+ )
129
145
  if tool_name in self._tools:
130
146
  raise ValueError(f"Tool '{tool_name}' is already registered.")
131
147
  self._tools[tool_name] = {
@@ -139,6 +155,7 @@ class LocalToolsAdapter(ToolsAdapter):
139
155
  # Decorator helper for quick registration of local tools
140
156
  # -------------------------------------------------------------------------
141
157
 
158
+
142
159
  def register_local_tool(tool=None):
143
160
  """Class decorator that registers the tool on the *singleton* adapter.
144
161
 
@@ -150,7 +167,7 @@ def register_local_tool(tool=None):
150
167
  """
151
168
 
152
169
  def decorator(cls):
153
- # Register the tool on a *fresh* adapter instance to avoid circular
170
+ # Register the tool on a *fresh* adapter instance to avoid circular
154
171
  # import issues during package initialisation. This keeps behaviour
155
172
  # identical to the original implementation while still allowing
156
173
  # immediate use via the singleton in janito.tools.adapters.local.
@@ -27,6 +27,7 @@ class AskUserTool(ToolBase):
27
27
  - "No"
28
28
  - "Some detailed answer..."
29
29
  """
30
+
30
31
  permissions = ToolPermissions(read=True)
31
32
  tool_name = "ask_user"
32
33
 
@@ -21,6 +21,7 @@ class CopyFileTool(ToolBase):
21
21
  Returns:
22
22
  str: Status string for each copy operation.
23
23
  """
24
+
24
25
  permissions = ToolPermissions(read=True, write=True)
25
26
  tool_name = "copy_file"
26
27
 
@@ -18,6 +18,7 @@ class CreateDirectoryTool(ToolBase):
18
18
  - "5c5 Successfully created the directory at ..."
19
19
  - "5d7 Cannot create directory: ..."
20
20
  """
21
+
21
22
  permissions = ToolPermissions(write=True)
22
23
  tool_name = "create_directory"
23
24
 
@@ -25,6 +25,7 @@ class CreateFileTool(ToolBase):
25
25
 
26
26
  Note: Syntax validation is automatically performed after this operation.
27
27
  """
28
+
28
29
  permissions = ToolPermissions(write=True)
29
30
  tool_name = "create_file"
30
31
 
@@ -19,6 +19,7 @@ class DeleteTextInFileTool(ToolBase):
19
19
  Returns:
20
20
  str: Status message indicating the result.
21
21
  """
22
+
22
23
  permissions = ToolPermissions(read=True, write=True)
23
24
  tool_name = "delete_text_in_file"
24
25
 
@@ -62,7 +63,7 @@ class DeleteTextInFileTool(ToolBase):
62
63
  return tr(
63
64
  "Deleted {count} block(s) between markers in {path}. ",
64
65
  count=deleted_blocks,
65
- path=path
66
+ path=path,
66
67
  ) + (f"\n{validation_result}" if validation_result else "")
67
68
  except Exception as e:
68
69
  self.report_error(tr(" ❌ Error: {error}", error=e), ReportAction.REPLACE)
@@ -21,6 +21,7 @@ class FetchUrlTool(ToolBase):
21
21
  - "No lines found for the provided search strings."
22
22
  - "Warning: Empty URL provided. Operation skipped."
23
23
  """
24
+
24
25
  permissions = ToolPermissions(read=True)
25
26
  tool_name = "fetch_url"
26
27
 
@@ -61,7 +61,9 @@ class FindFilesTool(ToolBase):
61
61
  break
62
62
  return dir_output
63
63
 
64
- def _handle_directory_path(self, directory, patterns, max_depth, include_gitignored):
64
+ def _handle_directory_path(
65
+ self, directory, patterns, max_depth, include_gitignored
66
+ ):
65
67
  dir_output = set()
66
68
  for root, dirs, files in walk_dir_with_gitignore(
67
69
  directory,
@@ -73,9 +75,7 @@ class FindFilesTool(ToolBase):
73
75
  dir_output.update(self._match_directories(root, dirs, pat))
74
76
  else:
75
77
  dir_output.update(self._match_files(root, files, pat))
76
- dir_output.update(
77
- self._match_dirs_without_slash(root, dirs, pat)
78
- )
78
+ dir_output.update(self._match_dirs_without_slash(root, dirs, pat))
79
79
  return dir_output
80
80
 
81
81
  def _report_search(self, pattern, disp_path, depth_msg):
@@ -131,9 +131,10 @@ class FindFilesTool(ToolBase):
131
131
  if os.path.isfile(directory):
132
132
  dir_output = self._handle_path(directory, patterns)
133
133
  elif os.path.isdir(directory):
134
- dir_output = self._handle_directory_path(directory, patterns, max_depth, include_gitignored)
134
+ dir_output = self._handle_directory_path(
135
+ directory, patterns, max_depth, include_gitignored
136
+ )
135
137
  self._report_success(len(dir_output))
136
138
  results.extend(self._format_output(directory, dir_output))
137
139
  result = "\n".join(results)
138
140
  return result
139
-
@@ -20,6 +20,7 @@ class GetFileOutlineTool(ToolBase):
20
20
  Args:
21
21
  path (str): Path to the file to outline.
22
22
  """
23
+
23
24
  permissions = ToolPermissions(read=True)
24
25
  tool_name = "get_file_outline"
25
26
 
@@ -1,6 +1,7 @@
1
1
  import re
2
2
  from typing import List, Dict
3
3
 
4
+
4
5
  def parse_java_outline(lines: List[str]) -> List[Dict]:
5
6
  """
6
7
  Parses Java source code lines and extracts classes and methods with their signatures.
@@ -9,19 +10,23 @@ def parse_java_outline(lines: List[str]) -> List[Dict]:
9
10
  outline = []
10
11
  class_pattern = re.compile(r"\bclass\s+(\w+)(\s*<[^>]+>)?")
11
12
  # Match methods with or without visibility modifiers (including package-private)
12
- method_pattern = re.compile(r"^(?:\s*(public|protected|private)\s+)?(?:static\s+)?([\w<>\[\]]+)\s+(\w+)\s*\(([^)]*)\)")
13
+ method_pattern = re.compile(
14
+ r"^(?:\s*(public|protected|private)\s+)?(?:static\s+)?([\w<>\[\]]+)\s+(\w+)\s*\(([^)]*)\)"
15
+ )
13
16
  current_class = None
14
17
  for idx, line in enumerate(lines, 1):
15
18
  class_match = class_pattern.search(line)
16
19
  if class_match:
17
20
  class_name = class_match.group(1)
18
21
  generics = class_match.group(2) or ""
19
- outline.append({
20
- "type": "class",
21
- "name": class_name,
22
- "generics": generics.strip("<>") if generics else None,
23
- "line": idx
24
- })
22
+ outline.append(
23
+ {
24
+ "type": "class",
25
+ "name": class_name,
26
+ "generics": generics.strip("<>") if generics else None,
27
+ "line": idx,
28
+ }
29
+ )
25
30
  current_class = class_name
26
31
  else:
27
32
  method_match = method_pattern.search(line)
@@ -29,12 +34,14 @@ def parse_java_outline(lines: List[str]) -> List[Dict]:
29
34
  return_type = method_match.group(2)
30
35
  method_name = method_match.group(3)
31
36
  params = method_match.group(4)
32
- outline.append({
33
- "type": "method",
34
- "class": current_class,
35
- "name": method_name,
36
- "return_type": return_type,
37
- "parameters": params.strip(),
38
- "line": idx
39
- })
37
+ outline.append(
38
+ {
39
+ "type": "method",
40
+ "class": current_class,
41
+ "name": method_name,
42
+ "return_type": return_type,
43
+ "parameters": params.strip(),
44
+ "line": idx,
45
+ }
46
+ )
40
47
  return outline
@@ -11,6 +11,7 @@ class SearchOutlineTool(ToolBase):
11
11
  Returns:
12
12
  str: Outline search result or status message.
13
13
  """
14
+
14
15
  permissions = ToolPermissions(read=True)
15
16
  tool_name = "search_outline"
16
17
 
@@ -20,6 +20,7 @@ class MoveFileTool(ToolBase):
20
20
  Returns:
21
21
  str: Status message indicating the result.
22
22
  """
23
+
23
24
  permissions = ToolPermissions(read=True, write=True)
24
25
  tool_name = "move_file"
25
26