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.
Files changed (150) hide show
  1. janito/__init__.py +6 -6
  2. janito/_version.py +57 -0
  3. janito/agent/setup_agent.py +92 -18
  4. janito/agent/templates/profiles/system_prompt_template_developer.txt.j2 +44 -0
  5. janito/cli/chat_mode/bindings.py +21 -2
  6. janito/cli/chat_mode/chat_entry.py +2 -3
  7. janito/cli/chat_mode/prompt_style.py +5 -0
  8. janito/cli/chat_mode/session.py +80 -94
  9. janito/cli/chat_mode/session_profile_select.py +80 -0
  10. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  11. janito/cli/chat_mode/shell/commands/__init__.py +13 -7
  12. janito/cli/chat_mode/shell/commands/_priv_check.py +5 -0
  13. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  14. janito/cli/chat_mode/shell/commands/conversation_restart.py +30 -0
  15. janito/cli/chat_mode/shell/commands/execute.py +42 -0
  16. janito/cli/chat_mode/shell/commands/help.py +6 -3
  17. janito/cli/chat_mode/shell/commands/model.py +28 -0
  18. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  19. janito/cli/chat_mode/shell/commands/read.py +37 -0
  20. janito/cli/chat_mode/shell/commands/tools.py +45 -18
  21. janito/cli/chat_mode/shell/commands/write.py +37 -0
  22. janito/cli/chat_mode/shell/commands.bak.zip +0 -0
  23. janito/cli/chat_mode/shell/input_history.py +62 -62
  24. janito/cli/chat_mode/shell/session.bak.zip +0 -0
  25. janito/cli/chat_mode/toolbar.py +44 -27
  26. janito/cli/cli_commands/list_models.py +35 -35
  27. janito/cli/cli_commands/list_providers.py +9 -9
  28. janito/cli/cli_commands/list_tools.py +86 -53
  29. janito/cli/cli_commands/model_selection.py +50 -50
  30. janito/cli/cli_commands/set_api_key.py +19 -19
  31. janito/cli/cli_commands/show_config.py +51 -51
  32. janito/cli/cli_commands/show_system_prompt.py +105 -62
  33. janito/cli/config.py +5 -6
  34. janito/cli/core/__init__.py +4 -4
  35. janito/cli/core/event_logger.py +59 -59
  36. janito/cli/core/runner.py +25 -18
  37. janito/cli/core/setters.py +10 -1
  38. janito/cli/core/unsetters.py +54 -54
  39. janito/cli/main_cli.py +28 -5
  40. janito/cli/prompt_core.py +18 -2
  41. janito/cli/prompt_setup.py +56 -0
  42. janito/cli/single_shot_mode/__init__.py +6 -6
  43. janito/cli/single_shot_mode/handler.py +14 -73
  44. janito/cli/verbose_output.py +1 -1
  45. janito/config.py +5 -5
  46. janito/config_manager.py +13 -0
  47. janito/drivers/anthropic/driver.py +113 -113
  48. janito/drivers/dashscope.bak.zip +0 -0
  49. janito/drivers/openai/README.md +20 -0
  50. janito/drivers/openai_responses.bak.zip +0 -0
  51. janito/event_bus/event.py +2 -2
  52. janito/formatting_token.py +54 -54
  53. janito/i18n/__init__.py +35 -35
  54. janito/i18n/messages.py +23 -23
  55. janito/i18n/pt.py +46 -47
  56. janito/llm/README.md +23 -0
  57. janito/llm/__init__.py +5 -5
  58. janito/llm/agent.py +507 -443
  59. janito/llm/driver.py +8 -0
  60. janito/llm/driver_config_builder.py +34 -34
  61. janito/llm/driver_input.py +12 -12
  62. janito/llm/message_parts.py +60 -60
  63. janito/llm/model.py +38 -38
  64. janito/llm/provider.py +196 -196
  65. janito/provider_registry.py +8 -6
  66. janito/providers/anthropic/model_info.py +22 -22
  67. janito/providers/anthropic/provider.py +2 -0
  68. janito/providers/azure_openai/provider.py +3 -0
  69. janito/providers/dashscope.bak.zip +0 -0
  70. janito/providers/deepseek/__init__.py +1 -1
  71. janito/providers/deepseek/model_info.py +16 -16
  72. janito/providers/deepseek/provider.py +94 -91
  73. janito/providers/google/provider.py +3 -0
  74. janito/providers/mistralai/provider.py +3 -0
  75. janito/providers/openai/provider.py +4 -0
  76. janito/providers/registry.py +26 -26
  77. janito/shell.bak.zip +0 -0
  78. janito/tools/DOCSTRING_STANDARD.txt +33 -0
  79. janito/tools/README.md +3 -0
  80. janito/tools/__init__.py +20 -6
  81. janito/tools/adapters/__init__.py +1 -1
  82. janito/tools/adapters/local/__init__.py +65 -62
  83. janito/tools/adapters/local/adapter.py +18 -35
  84. janito/tools/adapters/local/ask_user.py +101 -102
  85. janito/tools/adapters/local/copy_file.py +84 -84
  86. janito/tools/adapters/local/create_directory.py +69 -69
  87. janito/tools/adapters/local/create_file.py +82 -82
  88. janito/tools/adapters/local/delete_text_in_file.py +2 -2
  89. janito/tools/adapters/local/fetch_url.py +97 -97
  90. janito/tools/adapters/local/find_files.py +139 -138
  91. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  92. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  93. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  94. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  95. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  96. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  97. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  98. janito/tools/adapters/local/move_file.py +2 -2
  99. janito/tools/adapters/local/open_html_in_browser.py +2 -1
  100. janito/tools/adapters/local/open_url.py +2 -2
  101. janito/tools/adapters/local/python_code_run.py +166 -166
  102. janito/tools/adapters/local/python_command_run.py +164 -164
  103. janito/tools/adapters/local/python_file_run.py +163 -163
  104. janito/tools/adapters/local/remove_directory.py +2 -2
  105. janito/tools/adapters/local/remove_file.py +2 -2
  106. janito/tools/adapters/local/replace_text_in_file.py +2 -2
  107. janito/tools/adapters/local/run_bash_command.py +176 -176
  108. janito/tools/adapters/local/run_powershell_command.py +219 -219
  109. janito/tools/adapters/local/search_text/__init__.py +1 -1
  110. janito/tools/adapters/local/search_text/core.py +201 -201
  111. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  112. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  113. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  114. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  115. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  116. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  117. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  118. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  119. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  120. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  121. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  122. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  123. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  124. janito/tools/adapters/local/view_file.py +168 -167
  125. janito/tools/inspect_registry.py +17 -17
  126. janito/tools/outline_file.bak.zip +0 -0
  127. janito/tools/permissions.py +45 -0
  128. janito/tools/permissions_parse.py +12 -0
  129. janito/tools/tool_base.py +118 -105
  130. janito/tools/tool_events.py +58 -58
  131. janito/tools/tool_run_exception.py +12 -12
  132. janito/tools/tool_use_tracker.py +81 -81
  133. janito/tools/tool_utils.py +43 -45
  134. janito/tools/tools_adapter.py +25 -20
  135. janito/tools/tools_schema.py +104 -104
  136. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/METADATA +425 -388
  137. janito-2.4.0.dist-info/RECORD +195 -0
  138. janito/agent/templates/profiles/system_prompt_template_base_pt.txt.j2 +0 -13
  139. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +0 -37
  140. janito/cli/chat_mode/shell/commands/edit.py +0 -25
  141. janito/cli/chat_mode/shell/commands/exec.py +0 -27
  142. janito/cli/chat_mode/shell/commands/termweb_log.py +0 -92
  143. janito/cli/termweb_starter.py +0 -122
  144. janito/termweb/app.py +0 -95
  145. janito/version.py +0 -4
  146. janito-2.3.0.dist-info/RECORD +0 -181
  147. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/WHEEL +0 -0
  148. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/entry_points.txt +0 -0
  149. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/licenses/LICENSE +0 -0
  150. {janito-2.3.0.dist-info → janito-2.4.0.dist-info}/top_level.txt +0 -0
@@ -1,91 +1,94 @@
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 DeepseekProvider(LLMProvider):
16
- name = "deepseek"
17
- maintainer = "Needs maintainer"
18
- MODEL_SPECS = MODEL_SPECS
19
- DEFAULT_MODEL = "deepseek-chat" # Options: deepseek-chat, deepseek-reasoner
20
-
21
- def __init__(
22
- self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
23
- ):
24
- if not self.available:
25
- self._driver = None
26
- else:
27
- self.auth_manager = auth_manager or LLMAuthManager()
28
- self._api_key = self.auth_manager.get_credentials(type(self).name)
29
- self._tools_adapter = get_local_tools_adapter()
30
- self._driver_config = config or LLMDriverConfig(model=None)
31
- if not self._driver_config.model:
32
- self._driver_config.model = self.DEFAULT_MODEL
33
- if not self._driver_config.api_key:
34
- self._driver_config.api_key = self._api_key
35
- # Set DeepSeek public endpoint as default base_url if not provided
36
- if not getattr(self._driver_config, "base_url", None):
37
- self._driver_config.base_url = "https://api.deepseek.com/v1"
38
- self.fill_missing_device_info(self._driver_config)
39
- self._driver = None # to be provided by factory/agent
40
-
41
- @property
42
- def driver(self) -> OpenAIModelDriver:
43
- if not self.available:
44
- raise ImportError(f"OpenAIProvider unavailable: {self.unavailable_reason}")
45
- return self._driver
46
-
47
- @property
48
- def available(self):
49
- return available
50
-
51
- @property
52
- def unavailable_reason(self):
53
- return unavailable_reason
54
-
55
- def create_driver(self):
56
- """
57
- Creates and returns a new OpenAIModelDriver instance with input/output queues.
58
- """
59
- driver = OpenAIModelDriver(
60
- tools_adapter=self._tools_adapter, provider_name=self.name
61
- )
62
- driver.config = self._driver_config
63
- # NOTE: The caller is responsible for calling driver.start() if background processing is needed.
64
- return driver
65
-
66
- def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
67
- from janito.llm.agent import LLMAgent
68
-
69
- # Always create a new driver with the passed-in tools_adapter
70
- if tools_adapter is None:
71
- tools_adapter = get_local_tools_adapter()
72
- # Should use new-style driver construction via queues/factory (handled elsewhere)
73
- raise NotImplementedError(
74
- "create_agent must be constructed via new factory using input/output queues and config."
75
- )
76
-
77
- @property
78
- def model_name(self):
79
- return self._driver_config.model
80
-
81
- @property
82
- def driver_config(self):
83
- """Public, read-only access to the provider's LLMDriverConfig object."""
84
- return self._driver_config
85
-
86
- def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
87
- self._tools_adapter.event_bus = event_bus
88
- return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
89
-
90
-
91
- LLMProviderRegistry.register(DeepseekProvider.name, DeepseekProvider)
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 DeepseekProvider(LLMProvider):
16
+ name = "deepseek"
17
+ maintainer = "Needs maintainer"
18
+ MODEL_SPECS = MODEL_SPECS
19
+ DEFAULT_MODEL = "deepseek-chat" # Options: deepseek-chat, deepseek-reasoner
20
+
21
+ def __init__(
22
+ self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
23
+ ):
24
+ # Always set a tools adapter so that even if the driver is unavailable,
25
+ # generic code paths that expect provider.execute_tool() continue to work.
26
+ self._tools_adapter = get_local_tools_adapter()
27
+ if not self.available:
28
+ self._driver = None
29
+ else:
30
+ self.auth_manager = auth_manager or LLMAuthManager()
31
+ self._api_key = self.auth_manager.get_credentials(type(self).name)
32
+ self._tools_adapter = get_local_tools_adapter()
33
+ self._driver_config = config or LLMDriverConfig(model=None)
34
+ if not self._driver_config.model:
35
+ self._driver_config.model = self.DEFAULT_MODEL
36
+ if not self._driver_config.api_key:
37
+ self._driver_config.api_key = self._api_key
38
+ # Set DeepSeek public endpoint as default base_url if not provided
39
+ if not getattr(self._driver_config, "base_url", None):
40
+ self._driver_config.base_url = "https://api.deepseek.com/v1"
41
+ self.fill_missing_device_info(self._driver_config)
42
+ self._driver = None # to be provided by factory/agent
43
+
44
+ @property
45
+ def driver(self) -> OpenAIModelDriver:
46
+ if not self.available:
47
+ raise ImportError(f"OpenAIProvider unavailable: {self.unavailable_reason}")
48
+ return self._driver
49
+
50
+ @property
51
+ def available(self):
52
+ return available
53
+
54
+ @property
55
+ def unavailable_reason(self):
56
+ return unavailable_reason
57
+
58
+ def create_driver(self):
59
+ """
60
+ Creates and returns a new OpenAIModelDriver instance with input/output queues.
61
+ """
62
+ driver = OpenAIModelDriver(
63
+ tools_adapter=self._tools_adapter, provider_name=self.name
64
+ )
65
+ driver.config = self._driver_config
66
+ # NOTE: The caller is responsible for calling driver.start() if background processing is needed.
67
+ return driver
68
+
69
+ def create_agent(self, tools_adapter=None, agent_name: str = None, **kwargs):
70
+ from janito.llm.agent import LLMAgent
71
+
72
+ # Always create a new driver with the passed-in tools_adapter
73
+ if tools_adapter is None:
74
+ tools_adapter = get_local_tools_adapter()
75
+ # Should use new-style driver construction via queues/factory (handled elsewhere)
76
+ raise NotImplementedError(
77
+ "create_agent must be constructed via new factory using input/output queues and config."
78
+ )
79
+
80
+ @property
81
+ def model_name(self):
82
+ return self._driver_config.model
83
+
84
+ @property
85
+ def driver_config(self):
86
+ """Public, read-only access to the provider's LLMDriverConfig object."""
87
+ return self._driver_config
88
+
89
+ def execute_tool(self, tool_name: str, event_bus, *args, **kwargs):
90
+ self._tools_adapter.event_bus = event_bus
91
+ return self._tools_adapter.execute_by_name(tool_name, *args, **kwargs)
92
+
93
+
94
+ LLMProviderRegistry.register(DeepseekProvider.name, DeepseekProvider)
@@ -22,6 +22,9 @@ class GoogleProvider(LLMProvider):
22
22
  def __init__(
23
23
  self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
24
24
  ):
25
+ # Always have a tools adapter available to avoid AttributeError downstream when
26
+ # the driver is missing but other logic still relies on tools execution.
27
+ self._tools_adapter = get_local_tools_adapter()
25
28
  if not self.available:
26
29
  self._driver = None
27
30
  else:
@@ -24,6 +24,9 @@ class MistralAIProvider(LLMProvider):
24
24
  def __init__(
25
25
  self, config: LLMDriverConfig = None, auth_manager: LLMAuthManager = None
26
26
  ):
27
+ # Always instantiate a tools adapter so that provider.execute_tool() remains functional
28
+ # even when the driver cannot be constructed due to missing dependencies.
29
+ self._tools_adapter = get_local_tools_adapter()
27
30
  if not self.available:
28
31
  self._driver = None
29
32
  return
@@ -24,6 +24,10 @@ class OpenAIProvider(LLMProvider):
24
24
  self, auth_manager: LLMAuthManager = None, config: LLMDriverConfig = None
25
25
  ):
26
26
  if not self.available:
27
+ # Even when the OpenAI driver is unavailable we still need a tools adapter
28
+ # so that any generic logic that expects `execute_tool()` to work does not
29
+ # crash with an AttributeError when it tries to access `self._tools_adapter`.
30
+ self._tools_adapter = get_local_tools_adapter()
27
31
  self._driver = None
28
32
  else:
29
33
  self.auth_manager = auth_manager or LLMAuthManager()
@@ -1,26 +1,26 @@
1
- from typing import Type, Dict
2
- from janito.llm.provider import LLMProvider
3
-
4
-
5
- class LLMProviderRegistry:
6
- """
7
- Registry for LLM provider classes.
8
- """
9
-
10
- _providers: Dict[str, Type[LLMProvider]] = {}
11
-
12
- @classmethod
13
- def register(cls, name: str, provider_cls: Type[LLMProvider]):
14
- if name in cls._providers:
15
- raise ValueError(f"Provider '{name}' is already registered.")
16
- cls._providers[name] = provider_cls
17
-
18
- @classmethod
19
- def get(cls, name: str) -> Type[LLMProvider]:
20
- if name not in cls._providers:
21
- return None
22
- return cls._providers[name]
23
-
24
- @classmethod
25
- def list_providers(cls):
26
- return list(cls._providers.keys())
1
+ from typing import Type, Dict
2
+ from janito.llm.provider import LLMProvider
3
+
4
+
5
+ class LLMProviderRegistry:
6
+ """
7
+ Registry for LLM provider classes.
8
+ """
9
+
10
+ _providers: Dict[str, Type[LLMProvider]] = {}
11
+
12
+ @classmethod
13
+ def register(cls, name: str, provider_cls: Type[LLMProvider]):
14
+ if name in cls._providers:
15
+ raise ValueError(f"Provider '{name}' is already registered.")
16
+ cls._providers[name] = provider_cls
17
+
18
+ @classmethod
19
+ def get(cls, name: str) -> Type[LLMProvider]:
20
+ if name not in cls._providers:
21
+ return None
22
+ return cls._providers[name]
23
+
24
+ @classmethod
25
+ def list_providers(cls):
26
+ return list(cls._providers.keys())
janito/shell.bak.zip ADDED
Binary file
@@ -0,0 +1,33 @@
1
+ # Docstring Format Standard for Tools
2
+
3
+ All tool classes must use the following docstring style for schema compatibility and consistency:
4
+
5
+ - Use a single docstring in the tool class describing Args and Returns for all parameters of the `call` method.
6
+ - Args: List each parameter as `name (type): description` (type hints required for clarity).
7
+ - No blank lines between Args entries.
8
+ - Returns: Single line description, followed by examples if needed (no list markers).
9
+ - Keep formatting simple and consistent for schema compatibility.
10
+
11
+ Example:
12
+
13
+ class FindFilesTool(ToolBase):
14
+ """
15
+ Find files in one or more directories matching a pattern.
16
+
17
+ Args:
18
+ directories (list[str]): List of directories to search in.
19
+ pattern (str): File pattern to match. Uses Unix shell-style wildcards (fnmatch), e.g. '*.py', 'data_??.csv', '[a-z]*.txt'.
20
+
21
+ max_results (int, optional): Maximum number of results to return. Defaults to 100.
22
+ Returns:
23
+ str: Newline-separated list of matching file paths. Example:
24
+ "/path/to/file1.py\n/path/to/file2.py"
25
+ "Warning: Empty file pattern provided. Operation skipped."
26
+ """
27
+
28
+ # Tool Class Docstring Requirement
29
+
30
+ - All parameter documentation for OpenAI function tools must be in the class docstring, not the `call` method docstring.
31
+ - The class docstring is prepended to the tool's description in the OpenAI schema and is user-facing.
32
+ - Write class docstrings as concise, clear summaries of the tool's purpose and behavior, including parameter and return descriptions as shown above.
33
+ - Avoid implementation details; focus on what the tool does for the user.
janito/tools/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Tools Reference
2
+
3
+ This documentation has moved to [docs/TOOLS_REFERENCE.md](../../../docs/TOOLS_REFERENCE.md).
janito/tools/__init__.py CHANGED
@@ -4,17 +4,31 @@ from janito.tools.adapters.local import (
4
4
  )
5
5
 
6
6
 
7
- def get_local_tools_adapter(workdir=None):
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
+ import os
10
+ if workdir is not None and not os.path.exists(workdir):
11
+ os.makedirs(workdir, exist_ok=True)
12
+ # Permissions are now managed globally; ignore allowed_permissions argument except for backward compatibility
13
+ # Reuse the singleton adapter defined in janito.tools.adapters.local to maintain tool registrations
14
+ registry = _internal_local_tools_adapter
15
+ # Change workdir if requested
9
16
  if workdir is not None:
10
- import os
11
- if not os.path.exists(workdir):
12
- os.makedirs(workdir, exist_ok=True)
13
- return LocalToolsAdapter(workdir=workdir)
14
- return _internal_local_tools_adapter
17
+ try:
18
+ import os
19
+ if not os.path.exists(workdir):
20
+ os.makedirs(workdir, exist_ok=True)
21
+ os.chdir(workdir)
22
+ registry.workdir = workdir
23
+ except Exception:
24
+ pass
25
+ return registry
15
26
 
16
27
 
28
+ local_tools_adapter = _internal_local_tools_adapter
29
+
17
30
  __all__ = [
18
31
  "LocalToolsAdapter",
19
32
  "get_local_tools_adapter",
33
+ "local_tools_adapter",
20
34
  ]
@@ -1 +1 @@
1
- # Tools providers package: for plug-and-play tool collections, integrations, and adapters.
1
+ # Tools providers package: for plug-and-play tool collections, integrations, and adapters.
@@ -1,62 +1,65 @@
1
- from .adapter import LocalToolsAdapter
2
-
3
- from .ask_user import AskUserTool
4
- from .copy_file import CopyFileTool
5
- from .create_directory import CreateDirectoryTool
6
- from .create_file import CreateFileTool
7
- from .fetch_url import FetchUrlTool
8
- from .find_files import FindFilesTool
9
- from .view_file import ViewFileTool
10
- from .move_file import MoveFileTool
11
- from .open_url import OpenUrlTool
12
- from .open_html_in_browser import OpenHtmlInBrowserTool
13
- from .python_code_run import PythonCodeRunTool
14
- from .python_command_run import PythonCommandRunTool
15
- from .python_file_run import PythonFileRunTool
16
- from .remove_directory import RemoveDirectoryTool
17
- from .remove_file import RemoveFileTool
18
- from .replace_text_in_file import ReplaceTextInFileTool
19
- from .run_bash_command import RunBashCommandTool
20
- from .run_powershell_command import RunPowershellCommandTool
21
- from .get_file_outline.core import GetFileOutlineTool
22
- from .get_file_outline.search_outline import SearchOutlineTool
23
- from .search_text.core import SearchTextTool
24
- from .validate_file_syntax.core import ValidateFileSyntaxTool
25
-
26
- # Singleton tools adapter with all standard tools registered
27
- import os
28
- local_tools_adapter = LocalToolsAdapter(workdir=os.getcwd())
29
-
30
- def get_local_tools_adapter(workdir=None):
31
- import os
32
- return LocalToolsAdapter(workdir=workdir or os.getcwd())
33
-
34
- # Register tools
35
- for tool_class in [
36
- AskUserTool,
37
- CopyFileTool,
38
- CreateDirectoryTool,
39
- CreateFileTool,
40
- FetchUrlTool,
41
- FindFilesTool,
42
- ViewFileTool,
43
- MoveFileTool,
44
- OpenUrlTool,
45
- OpenHtmlInBrowserTool,
46
- PythonCodeRunTool,
47
- PythonCommandRunTool,
48
- PythonFileRunTool,
49
- RemoveDirectoryTool,
50
- RemoveFileTool,
51
- ReplaceTextInFileTool,
52
- RunBashCommandTool,
53
- RunPowershellCommandTool,
54
- GetFileOutlineTool,
55
- SearchOutlineTool,
56
- SearchTextTool,
57
- ValidateFileSyntaxTool,
58
- ]:
59
- local_tools_adapter.register_tool(tool_class)
60
-
61
- # DEBUG: Print registered tools at startup
62
-
1
+ from .adapter import LocalToolsAdapter
2
+
3
+ from .ask_user import AskUserTool
4
+ from .copy_file import CopyFileTool
5
+ from .create_directory import CreateDirectoryTool
6
+ from .create_file import CreateFileTool
7
+ from .fetch_url import FetchUrlTool
8
+ from .find_files import FindFilesTool
9
+ from .view_file import ViewFileTool
10
+ from .move_file import MoveFileTool
11
+ from .open_url import OpenUrlTool
12
+ from .open_html_in_browser import OpenHtmlInBrowserTool
13
+ from .python_code_run import PythonCodeRunTool
14
+ from .python_command_run import PythonCommandRunTool
15
+ from .python_file_run import PythonFileRunTool
16
+ from .remove_directory import RemoveDirectoryTool
17
+ from .remove_file import RemoveFileTool
18
+ from .replace_text_in_file import ReplaceTextInFileTool
19
+ from .run_bash_command import RunBashCommandTool
20
+ from .run_powershell_command import RunPowershellCommandTool
21
+ from .get_file_outline.core import GetFileOutlineTool
22
+ from .get_file_outline.search_outline import SearchOutlineTool
23
+ from .search_text.core import SearchTextTool
24
+ from .validate_file_syntax.core import ValidateFileSyntaxTool
25
+
26
+ # Singleton tools adapter with all standard tools registered
27
+ from janito.tools.tool_base import ToolPermissions
28
+ import os
29
+ local_tools_adapter = LocalToolsAdapter(workdir=os.getcwd())
30
+
31
+ from janito.tools.permissions import get_global_allowed_permissions
32
+
33
+ def get_local_tools_adapter(workdir=None):
34
+ import os
35
+ return LocalToolsAdapter(workdir=workdir or os.getcwd())
36
+
37
+ # Register tools
38
+ for tool_class in [
39
+ AskUserTool,
40
+ CopyFileTool,
41
+ CreateDirectoryTool,
42
+ CreateFileTool,
43
+ FetchUrlTool,
44
+ FindFilesTool,
45
+ ViewFileTool,
46
+ MoveFileTool,
47
+ OpenUrlTool,
48
+ OpenHtmlInBrowserTool,
49
+ PythonCodeRunTool,
50
+ PythonCommandRunTool,
51
+ PythonFileRunTool,
52
+ RemoveDirectoryTool,
53
+ RemoveFileTool,
54
+ ReplaceTextInFileTool,
55
+ RunBashCommandTool,
56
+ RunPowershellCommandTool,
57
+ GetFileOutlineTool,
58
+ SearchOutlineTool,
59
+ SearchTextTool,
60
+ ValidateFileSyntaxTool,
61
+ ]:
62
+ local_tools_adapter.register_tool(tool_class)
63
+
64
+ # DEBUG: Print registered tools at startup
65
+
@@ -3,35 +3,22 @@ from janito.tools.tools_adapter import ToolsAdapterBase as ToolsAdapter
3
3
 
4
4
 
5
5
  class LocalToolsAdapter(ToolsAdapter):
6
- def set_execution_tools_enabled(self, enabled: bool):
7
- """
8
- Dynamically include or exclude execution tools from the enabled_tools set.
9
- If enabled_tools is None, all tools are enabled (default). If set, restricts enabled tools.
10
- """
11
- all_tool_names = set(self._tools.keys())
12
- exec_tool_names = {
13
- name for name, entry in self._tools.items()
14
- if getattr(entry["instance"], "provides_execution", False)
15
- }
16
- if self._enabled_tools is None:
17
- # If not restricted, create a new enabled-tools set excluding execution tools if disabling
18
- if enabled:
19
- self._enabled_tools = None # all tools enabled
20
- else:
21
- self._enabled_tools = all_tool_names - exec_tool_names
22
- else:
23
- if enabled:
24
- self._enabled_tools |= exec_tool_names
25
- else:
26
- self._enabled_tools -= exec_tool_names
6
+ """Local, in-process implementation of :class:`ToolsAdapterBase`.
27
7
 
28
- """
29
- Adapter for local, statically registered tools in the agent/tools system.
30
- Handles registration, lookup, enabling/disabling, listing, and now, tool execution (merged from executor).
8
+ This adapter keeps an **in-memory registry** of tool classes and manages
9
+ permission filtering (read/write/execute) as required by the janito CLI.
10
+
11
+ The legacy ``set_execution_tools_enabled()`` helper has been removed – use
12
+ ``janito.tools.permissions.set_global_allowed_permissions`` or
13
+ :py:meth:`LocalToolsAdapter.set_allowed_permissions` to adjust the
14
+ permission mask at runtime.
15
+
16
+ Apart from registration/lookup helpers the class derives all execution
17
+ logic from :class:`janito.tools.tools_adapter.ToolsAdapterBase`.
31
18
  """
32
19
 
33
- def __init__(self, tools=None, event_bus=None, enabled_tools=None, workdir=None):
34
- super().__init__(tools=tools, event_bus=event_bus, enabled_tools=enabled_tools)
20
+ def __init__(self, tools=None, event_bus=None, workdir=None):
21
+ super().__init__(tools=tools, event_bus=event_bus)
35
22
  self._tools: Dict[str, Dict[str, Any]] = {}
36
23
  self.workdir = workdir
37
24
  if self.workdir:
@@ -71,19 +58,13 @@ class LocalToolsAdapter(ToolsAdapter):
71
58
  return self._tools[name]["instance"] if name in self._tools else None
72
59
 
73
60
  def list_tools(self):
74
- if self._enabled_tools is None:
75
- return list(self._tools.keys())
76
- return [name for name in self._tools.keys() if name in self._enabled_tools]
61
+ return [name for name, entry in self._tools.items() if self.is_tool_allowed(entry["instance"])]
77
62
 
78
63
  def get_tool_classes(self):
79
- if self._enabled_tools is None:
80
- return [entry["class"] for entry in self._tools.values()]
81
- return [entry["class"] for name, entry in self._tools.items() if name in self._enabled_tools]
64
+ return [entry["class"] for entry in self._tools.values() if self.is_tool_allowed(entry["instance"])]
82
65
 
83
66
  def get_tools(self):
84
- if self._enabled_tools is None:
85
- return [entry["instance"] for entry in self._tools.values()]
86
- return [entry["instance"] for name, entry in self._tools.items() if name in self._enabled_tools]
67
+ return [entry["instance"] for entry in self._tools.values() if self.is_tool_allowed(entry["instance"])]
87
68
 
88
69
 
89
70
  def add_tool(self, tool):
@@ -109,6 +90,8 @@ class LocalToolsAdapter(ToolsAdapter):
109
90
 
110
91
  def register_local_tool(tool=None):
111
92
  def decorator(cls):
93
+ from janito.tools.tool_base import ToolPermissions
94
+ from janito.tools.permissions import get_global_allowed_permissions
112
95
  LocalToolsAdapter().register_tool(cls)
113
96
  return cls
114
97