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,82 +1,82 @@
1
- import os
2
- from janito.tools.adapters.local.adapter import register_local_tool
3
-
4
- from janito.tools.tool_utils import display_path
5
- from janito.tools.tool_base import ToolBase
6
- from janito.report_events import ReportAction
7
- from janito.i18n import tr
8
-
9
-
10
- from janito.tools.adapters.local.validate_file_syntax.core import validate_file_syntax
11
-
12
-
13
- @register_local_tool
14
- class CreateFileTool(ToolBase):
15
- """
16
- Create a new file with the given content.
17
-
18
- Args:
19
- file_path (str): Path to the file to create.
20
- content (str): Content to write to the file.
21
- overwrite (bool, optional): Overwrite existing file if True. Default: False. Recommended only after reading the file to be overwritten.
22
- Returns:
23
- str: Status message indicating the result. Example:
24
- - "✅ Successfully created the file at ..."
25
-
26
- Note: Syntax validation is automatically performed after this operation.
27
- """
28
-
29
- tool_name = "create_file"
30
-
31
- def run(self, file_path: str, content: str, overwrite: bool = False) -> str:
32
- expanded_file_path = file_path # Using file_path as is
33
- disp_path = display_path(expanded_file_path)
34
- file_path = expanded_file_path
35
- if os.path.exists(file_path) and not overwrite:
36
- try:
37
- with open(file_path, "r", encoding="utf-8", errors="replace") as f:
38
- existing_content = f.read()
39
- except Exception as e:
40
- existing_content = f"[Error reading file: {e}]"
41
- return tr(
42
- "❗ Cannot create file: file already exists at '{disp_path}'.\n--- Current file content ---\n{existing_content}",
43
- disp_path=disp_path,
44
- existing_content=existing_content,
45
- )
46
- # Determine if we are overwriting an existing file
47
- is_overwrite = os.path.exists(file_path) and overwrite
48
- if is_overwrite:
49
- # Overwrite branch: log only overwrite warning (no create message)
50
- self.report_action(
51
- tr("⚠️ Overwriting file '{disp_path}'", disp_path=disp_path),
52
- ReportAction.CREATE,
53
- )
54
- dir_name = os.path.dirname(file_path)
55
- if dir_name:
56
- os.makedirs(dir_name, exist_ok=True)
57
- if not is_overwrite:
58
- # Create branch: log file creation message
59
- self.report_action(
60
- tr("📝 Create file '{disp_path}' ...", disp_path=disp_path),
61
- ReportAction.CREATE,
62
- )
63
- with open(file_path, "w", encoding="utf-8", errors="replace") as f:
64
- f.write(content)
65
- new_lines = content.count("\n") + 1 if content else 0
66
- self.report_success(
67
- tr("✅ {new_lines} lines", new_lines=new_lines), ReportAction.CREATE
68
- )
69
- # Perform syntax validation and append result
70
- validation_result = validate_file_syntax(file_path)
71
- if is_overwrite:
72
- # Overwrite branch: return minimal overwrite info to user
73
- return (
74
- tr("✅ {new_lines} lines", new_lines=new_lines)
75
- + f"\n{validation_result}"
76
- )
77
- else:
78
- # Create branch: return detailed create success to user
79
- return (
80
- tr("✅ Created file {new_lines} lines.", new_lines=new_lines)
81
- + f"\n{validation_result}"
82
- )
1
+ import os
2
+ from janito.tools.adapters.local.adapter import register_local_tool
3
+
4
+ from janito.tools.tool_utils import display_path
5
+ from janito.tools.tool_base import ToolBase, ToolPermissions
6
+ from janito.report_events import ReportAction
7
+ from janito.i18n import tr
8
+
9
+
10
+ from janito.tools.adapters.local.validate_file_syntax.core import validate_file_syntax
11
+
12
+
13
+ @register_local_tool
14
+ class CreateFileTool(ToolBase):
15
+ """
16
+ Create a new file with the given content.
17
+
18
+ Args:
19
+ file_path (str): Path to the file to create.
20
+ content (str): Content to write to the file.
21
+ overwrite (bool, optional): Overwrite existing file if True. Default: False. Recommended only after reading the file to be overwritten.
22
+ Returns:
23
+ str: Status message indicating the result. Example:
24
+ - "✅ Successfully created the file at ..."
25
+
26
+ Note: Syntax validation is automatically performed after this operation.
27
+ """
28
+ permissions = ToolPermissions(write=True)
29
+ tool_name = "create_file"
30
+
31
+ def run(self, file_path: str, content: str, overwrite: bool = False) -> str:
32
+ expanded_file_path = file_path # Using file_path as is
33
+ disp_path = display_path(expanded_file_path)
34
+ file_path = expanded_file_path
35
+ if os.path.exists(file_path) and not overwrite:
36
+ try:
37
+ with open(file_path, "r", encoding="utf-8", errors="replace") as f:
38
+ existing_content = f.read()
39
+ except Exception as e:
40
+ existing_content = f"[Error reading file: {e}]"
41
+ return tr(
42
+ "❗ Cannot create file: file already exists at '{disp_path}'.\n--- Current file content ---\n{existing_content}",
43
+ disp_path=disp_path,
44
+ existing_content=existing_content,
45
+ )
46
+ # Determine if we are overwriting an existing file
47
+ is_overwrite = os.path.exists(file_path) and overwrite
48
+ if is_overwrite:
49
+ # Overwrite branch: log only overwrite warning (no create message)
50
+ self.report_action(
51
+ tr("⚠️ Overwriting file '{disp_path}'", disp_path=disp_path),
52
+ ReportAction.CREATE,
53
+ )
54
+ dir_name = os.path.dirname(file_path)
55
+ if dir_name:
56
+ os.makedirs(dir_name, exist_ok=True)
57
+ if not is_overwrite:
58
+ # Create branch: log file creation message
59
+ self.report_action(
60
+ tr("📝 Create file '{disp_path}' ...", disp_path=disp_path),
61
+ ReportAction.CREATE,
62
+ )
63
+ with open(file_path, "w", encoding="utf-8", errors="replace") as f:
64
+ f.write(content)
65
+ new_lines = content.count("\n") + 1 if content else 0
66
+ self.report_success(
67
+ tr("✅ {new_lines} lines", new_lines=new_lines), ReportAction.CREATE
68
+ )
69
+ # Perform syntax validation and append result
70
+ validation_result = validate_file_syntax(file_path)
71
+ if is_overwrite:
72
+ # Overwrite branch: return minimal overwrite info to user
73
+ return (
74
+ tr("✅ {new_lines} lines", new_lines=new_lines)
75
+ + f"\n{validation_result}"
76
+ )
77
+ else:
78
+ # Create branch: return detailed create success to user
79
+ return (
80
+ tr("✅ Created file {new_lines} lines.", new_lines=new_lines)
81
+ + f"\n{validation_result}"
82
+ )
@@ -1,4 +1,4 @@
1
- from janito.tools.tool_base import ToolBase
1
+ from janito.tools.tool_base import ToolBase, ToolPermissions
2
2
  from janito.report_events import ReportAction
3
3
  from janito.tools.adapters.local.adapter import register_local_tool
4
4
  from janito.i18n import tr
@@ -19,7 +19,7 @@ class DeleteTextInFileTool(ToolBase):
19
19
  Returns:
20
20
  str: Status message indicating the result.
21
21
  """
22
-
22
+ permissions = ToolPermissions(read=True, write=True)
23
23
  tool_name = "delete_text_in_file"
24
24
 
25
25
  def run(
@@ -1,97 +1,97 @@
1
- import requests
2
- from bs4 import BeautifulSoup
3
- from janito.tools.adapters.local.adapter import register_local_tool
4
- from janito.tools.tool_base import ToolBase
5
- from janito.report_events import ReportAction
6
- from janito.i18n import tr
7
- from janito.tools.tool_utils import pluralize
8
-
9
-
10
- @register_local_tool
11
- class FetchUrlTool(ToolBase):
12
- """
13
- Fetch the content of a web page and extract its text.
14
-
15
- Args:
16
- url (str): The URL of the web page to fetch.
17
- search_strings (list[str], optional): Strings to search for in the page content.
18
- Returns:
19
- str: Extracted text content from the web page, or a warning message. Example:
20
- - "<main text content...>"
21
- - "No lines found for the provided search strings."
22
- - "Warning: Empty URL provided. Operation skipped."
23
- """
24
-
25
- tool_name = "fetch_url"
26
-
27
- def run(self, url: str, search_strings: list[str] = None) -> str:
28
- if not url.strip():
29
- self.report_warning(tr("ℹ️ Empty URL provided."), ReportAction.READ)
30
- return tr("Warning: Empty URL provided. Operation skipped.")
31
- self.report_action(tr("🌐 Fetch URL '{url}' ...", url=url), ReportAction.READ)
32
- try:
33
- response = requests.get(url, timeout=10)
34
- response.raise_for_status()
35
- except requests.exceptions.HTTPError as http_err:
36
- status_code = http_err.response.status_code if http_err.response else None
37
- if status_code and 400 <= status_code < 500:
38
- self.report_error(
39
- tr(
40
- "❗ HTTP {status_code} error for URL: {url}",
41
- status_code=status_code,
42
- url=url,
43
- ),
44
- ReportAction.READ,
45
- )
46
- return tr(
47
- "Warning: HTTP {status_code} error for URL: {url}",
48
- status_code=status_code,
49
- url=url,
50
- )
51
- else:
52
- self.report_error(
53
- tr(
54
- "❗ HTTP error for URL: {url}: {err}",
55
- url=url,
56
- err=str(http_err),
57
- ),
58
- ReportAction.READ,
59
- )
60
- return tr(
61
- "Warning: HTTP error for URL: {url}: {err}",
62
- url=url,
63
- err=str(http_err),
64
- )
65
- except Exception as err:
66
- self.report_error(
67
- tr("❗ Error fetching URL: {url}: {err}", url=url, err=str(err)),
68
- ReportAction.READ,
69
- )
70
- return tr(
71
- "Warning: Error fetching URL: {url}: {err}", url=url, err=str(err)
72
- )
73
- soup = BeautifulSoup(response.text, "html.parser")
74
- text = soup.get_text(separator="\n")
75
- if search_strings:
76
- filtered = []
77
- for s in search_strings:
78
- idx = text.find(s)
79
- if idx != -1:
80
- start = max(0, idx - 200)
81
- end = min(len(text), idx + len(s) + 200)
82
- snippet = text[start:end]
83
- filtered.append(snippet)
84
- if filtered:
85
- text = "\n...\n".join(filtered)
86
- else:
87
- text = tr("No lines found for the provided search strings.")
88
- num_lines = len(text.splitlines())
89
- self.report_success(
90
- tr(
91
- "✅ {num_lines} {line_word}",
92
- num_lines=num_lines,
93
- line_word=pluralize("line", num_lines),
94
- ),
95
- ReportAction.READ,
96
- )
97
- return text
1
+ import requests
2
+ from bs4 import BeautifulSoup
3
+ from janito.tools.adapters.local.adapter import register_local_tool
4
+ from janito.tools.tool_base import ToolBase, ToolPermissions
5
+ from janito.report_events import ReportAction
6
+ from janito.i18n import tr
7
+ from janito.tools.tool_utils import pluralize
8
+
9
+
10
+ @register_local_tool
11
+ class FetchUrlTool(ToolBase):
12
+ """
13
+ Fetch the content of a web page and extract its text.
14
+
15
+ Args:
16
+ url (str): The URL of the web page to fetch.
17
+ search_strings (list[str], optional): Strings to search for in the page content.
18
+ Returns:
19
+ str: Extracted text content from the web page, or a warning message. Example:
20
+ - "<main text content...>"
21
+ - "No lines found for the provided search strings."
22
+ - "Warning: Empty URL provided. Operation skipped."
23
+ """
24
+ permissions = ToolPermissions(read=True)
25
+ tool_name = "fetch_url"
26
+
27
+ def run(self, url: str, search_strings: list[str] = None) -> str:
28
+ if not url.strip():
29
+ self.report_warning(tr("ℹ️ Empty URL provided."), ReportAction.READ)
30
+ return tr("Warning: Empty URL provided. Operation skipped.")
31
+ self.report_action(tr("🌐 Fetch URL '{url}' ...", url=url), ReportAction.READ)
32
+ try:
33
+ response = requests.get(url, timeout=10)
34
+ response.raise_for_status()
35
+ except requests.exceptions.HTTPError as http_err:
36
+ status_code = http_err.response.status_code if http_err.response else None
37
+ if status_code and 400 <= status_code < 500:
38
+ self.report_error(
39
+ tr(
40
+ "❗ HTTP {status_code} error for URL: {url}",
41
+ status_code=status_code,
42
+ url=url,
43
+ ),
44
+ ReportAction.READ,
45
+ )
46
+ return tr(
47
+ "Warning: HTTP {status_code} error for URL: {url}",
48
+ status_code=status_code,
49
+ url=url,
50
+ )
51
+ else:
52
+ self.report_error(
53
+ tr(
54
+ "❗ HTTP error for URL: {url}: {err}",
55
+ url=url,
56
+ err=str(http_err),
57
+ ),
58
+ ReportAction.READ,
59
+ )
60
+ return tr(
61
+ "Warning: HTTP error for URL: {url}: {err}",
62
+ url=url,
63
+ err=str(http_err),
64
+ )
65
+ except Exception as err:
66
+ self.report_error(
67
+ tr("❗ Error fetching URL: {url}: {err}", url=url, err=str(err)),
68
+ ReportAction.READ,
69
+ )
70
+ return tr(
71
+ "Warning: Error fetching URL: {url}: {err}", url=url, err=str(err)
72
+ )
73
+ soup = BeautifulSoup(response.text, "html.parser")
74
+ text = soup.get_text(separator="\n")
75
+ if search_strings:
76
+ filtered = []
77
+ for s in search_strings:
78
+ idx = text.find(s)
79
+ if idx != -1:
80
+ start = max(0, idx - 200)
81
+ end = min(len(text), idx + len(s) + 200)
82
+ snippet = text[start:end]
83
+ filtered.append(snippet)
84
+ if filtered:
85
+ text = "\n...\n".join(filtered)
86
+ else:
87
+ text = tr("No lines found for the provided search strings.")
88
+ num_lines = len(text.splitlines())
89
+ self.report_success(
90
+ tr(
91
+ "✅ {num_lines} {line_word}",
92
+ num_lines=num_lines,
93
+ line_word=pluralize("line", num_lines),
94
+ ),
95
+ ReportAction.READ,
96
+ )
97
+ return text