janito 2.1.1__py3-none-any.whl → 2.3.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 (137) hide show
  1. janito/__init__.py +6 -6
  2. janito/agent/setup_agent.py +14 -5
  3. janito/agent/templates/profiles/system_prompt_template_main.txt.j2 +3 -1
  4. janito/cli/chat_mode/bindings.py +6 -0
  5. janito/cli/chat_mode/session.py +16 -0
  6. janito/cli/chat_mode/shell/autocomplete.py +21 -21
  7. janito/cli/chat_mode/shell/commands/__init__.py +3 -2
  8. janito/cli/chat_mode/shell/commands/clear.py +12 -12
  9. janito/cli/chat_mode/shell/commands/exec.py +27 -0
  10. janito/cli/chat_mode/shell/commands/multi.py +51 -51
  11. janito/cli/chat_mode/shell/commands/tools.py +17 -6
  12. janito/cli/chat_mode/shell/input_history.py +62 -62
  13. janito/cli/chat_mode/shell/session/manager.py +1 -0
  14. janito/cli/chat_mode/toolbar.py +3 -1
  15. janito/cli/cli_commands/list_models.py +35 -35
  16. janito/cli/cli_commands/list_providers.py +9 -9
  17. janito/cli/cli_commands/list_tools.py +53 -53
  18. janito/cli/cli_commands/model_selection.py +50 -50
  19. janito/cli/cli_commands/model_utils.py +13 -2
  20. janito/cli/cli_commands/set_api_key.py +19 -19
  21. janito/cli/cli_commands/show_config.py +51 -51
  22. janito/cli/cli_commands/show_system_prompt.py +62 -62
  23. janito/cli/config.py +2 -1
  24. janito/cli/core/__init__.py +4 -4
  25. janito/cli/core/event_logger.py +59 -59
  26. janito/cli/core/getters.py +3 -1
  27. janito/cli/core/runner.py +27 -6
  28. janito/cli/core/setters.py +5 -1
  29. janito/cli/core/unsetters.py +54 -54
  30. janito/cli/main_cli.py +12 -1
  31. janito/cli/prompt_core.py +5 -2
  32. janito/cli/rich_terminal_reporter.py +22 -3
  33. janito/cli/single_shot_mode/__init__.py +6 -6
  34. janito/cli/single_shot_mode/handler.py +11 -1
  35. janito/cli/verbose_output.py +1 -1
  36. janito/config.py +5 -5
  37. janito/config_manager.py +2 -0
  38. janito/driver_events.py +14 -0
  39. janito/drivers/anthropic/driver.py +113 -113
  40. janito/drivers/azure_openai/driver.py +38 -3
  41. janito/drivers/driver_registry.py +0 -2
  42. janito/drivers/openai/driver.py +196 -36
  43. janito/formatting_token.py +54 -54
  44. janito/i18n/__init__.py +35 -35
  45. janito/i18n/messages.py +23 -23
  46. janito/i18n/pt.py +47 -47
  47. janito/llm/__init__.py +5 -5
  48. janito/llm/agent.py +443 -443
  49. janito/llm/auth.py +1 -0
  50. janito/llm/driver.py +7 -1
  51. janito/llm/driver_config.py +1 -0
  52. janito/llm/driver_config_builder.py +34 -34
  53. janito/llm/driver_input.py +12 -12
  54. janito/llm/message_parts.py +60 -60
  55. janito/llm/model.py +38 -38
  56. janito/llm/provider.py +196 -196
  57. janito/provider_config.py +7 -3
  58. janito/provider_registry.py +29 -5
  59. janito/providers/__init__.py +1 -0
  60. janito/providers/anthropic/model_info.py +22 -22
  61. janito/providers/anthropic/provider.py +2 -2
  62. janito/providers/azure_openai/model_info.py +7 -6
  63. janito/providers/azure_openai/provider.py +44 -2
  64. janito/providers/deepseek/__init__.py +1 -1
  65. janito/providers/deepseek/model_info.py +16 -16
  66. janito/providers/deepseek/provider.py +91 -91
  67. janito/providers/google/model_info.py +21 -29
  68. janito/providers/google/provider.py +49 -38
  69. janito/providers/mistralai/provider.py +2 -2
  70. janito/providers/openai/model_info.py +0 -11
  71. janito/providers/openai/provider.py +1 -1
  72. janito/providers/provider_static_info.py +2 -3
  73. janito/providers/registry.py +26 -26
  74. janito/tools/adapters/__init__.py +1 -1
  75. janito/tools/adapters/local/__init__.py +62 -62
  76. janito/tools/adapters/local/adapter.py +33 -11
  77. janito/tools/adapters/local/ask_user.py +102 -102
  78. janito/tools/adapters/local/copy_file.py +84 -84
  79. janito/tools/adapters/local/create_directory.py +69 -69
  80. janito/tools/adapters/local/create_file.py +82 -82
  81. janito/tools/adapters/local/delete_text_in_file.py +4 -7
  82. janito/tools/adapters/local/fetch_url.py +97 -97
  83. janito/tools/adapters/local/find_files.py +138 -140
  84. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  85. janito/tools/adapters/local/get_file_outline/core.py +117 -151
  86. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -0
  87. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  88. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  89. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  90. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  91. janito/tools/adapters/local/move_file.py +3 -13
  92. janito/tools/adapters/local/open_html_in_browser.py +24 -29
  93. janito/tools/adapters/local/open_url.py +3 -2
  94. janito/tools/adapters/local/python_code_run.py +166 -166
  95. janito/tools/adapters/local/python_command_run.py +164 -164
  96. janito/tools/adapters/local/python_file_run.py +163 -163
  97. janito/tools/adapters/local/remove_directory.py +6 -17
  98. janito/tools/adapters/local/remove_file.py +9 -15
  99. janito/tools/adapters/local/replace_text_in_file.py +6 -9
  100. janito/tools/adapters/local/run_bash_command.py +176 -176
  101. janito/tools/adapters/local/run_powershell_command.py +219 -219
  102. janito/tools/adapters/local/search_text/__init__.py +1 -1
  103. janito/tools/adapters/local/search_text/core.py +201 -201
  104. janito/tools/adapters/local/search_text/match_lines.py +1 -1
  105. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  106. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  107. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  108. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  109. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  110. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  111. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  112. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  113. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  114. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  115. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  116. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  117. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  118. janito/tools/adapters/local/view_file.py +167 -167
  119. janito/tools/inspect_registry.py +17 -17
  120. janito/tools/tool_base.py +105 -105
  121. janito/tools/tool_events.py +58 -58
  122. janito/tools/tool_run_exception.py +12 -12
  123. janito/tools/tool_use_tracker.py +81 -81
  124. janito/tools/tool_utils.py +45 -45
  125. janito/tools/tools_adapter.py +78 -6
  126. janito/tools/tools_schema.py +104 -104
  127. janito/version.py +4 -4
  128. {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/METADATA +388 -232
  129. janito-2.3.0.dist-info/RECORD +181 -0
  130. janito-2.3.0.dist-info/licenses/LICENSE +21 -0
  131. janito/cli/chat_mode/shell/commands/last.py +0 -137
  132. janito/drivers/google_genai/driver.py +0 -54
  133. janito/drivers/google_genai/schema_generator.py +0 -67
  134. janito-2.1.1.dist-info/RECORD +0 -181
  135. {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/WHEEL +0 -0
  136. {janito-2.1.1.dist-info → janito-2.3.0.dist-info}/entry_points.txt +0 -0
  137. {janito-2.1.1.dist-info → janito-2.3.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
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
+ )
@@ -15,7 +15,7 @@ class DeleteTextInFileTool(ToolBase):
15
15
  file_path (str): Path to the file to modify.
16
16
  start_marker (str): The starting delimiter string.
17
17
  end_marker (str): The ending delimiter string.
18
- backup (bool, optional): If True, create a backup (.bak) before deleting. Defaults to False.
18
+
19
19
  Returns:
20
20
  str: Status message indicating the result.
21
21
  """
@@ -52,9 +52,7 @@ class DeleteTextInFileTool(ToolBase):
52
52
  "No blocks found between markers in {file_path}.",
53
53
  file_path=file_path,
54
54
  )
55
- backup_path = file_path + ".bak"
56
- if backup:
57
- self._backup_file(file_path, backup_path)
55
+
58
56
  new_content, deleted_blocks = self._delete_blocks(
59
57
  content, start_marker, end_marker
60
58
  )
@@ -62,10 +60,9 @@ class DeleteTextInFileTool(ToolBase):
62
60
  validation_result = validate_file_syntax(file_path)
63
61
  self._report_success(match_lines)
64
62
  return tr(
65
- "Deleted {count} block(s) between markers in {file_path}. (backup at {backup_path})",
63
+ "Deleted {count} block(s) between markers in {file_path}. ",
66
64
  count=deleted_blocks,
67
- file_path=file_path,
68
- backup_path=backup_path if backup else "N/A",
65
+ file_path=file_path
69
66
  ) + (f"\n{validation_result}" if validation_result else "")
70
67
  except Exception as e:
71
68
  self.report_error(tr(" ❌ Error: {error}", error=e), ReportAction.REPLACE)
@@ -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
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