janito 2.2.0__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 (130) 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 -0
  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 +1 -0
  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 +165 -148
  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 +176 -158
  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 +30 -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/provider_static_info.py +2 -3
  71. janito/tools/adapters/__init__.py +1 -1
  72. janito/tools/adapters/local/adapter.py +33 -11
  73. janito/tools/adapters/local/ask_user.py +102 -102
  74. janito/tools/adapters/local/copy_file.py +84 -84
  75. janito/tools/adapters/local/create_directory.py +69 -69
  76. janito/tools/adapters/local/create_file.py +82 -82
  77. janito/tools/adapters/local/delete_text_in_file.py +4 -7
  78. janito/tools/adapters/local/fetch_url.py +97 -97
  79. janito/tools/adapters/local/find_files.py +138 -138
  80. janito/tools/adapters/local/get_file_outline/__init__.py +1 -1
  81. janito/tools/adapters/local/get_file_outline/core.py +117 -117
  82. janito/tools/adapters/local/get_file_outline/java_outline.py +40 -40
  83. janito/tools/adapters/local/get_file_outline/markdown_outline.py +14 -14
  84. janito/tools/adapters/local/get_file_outline/python_outline.py +303 -303
  85. janito/tools/adapters/local/get_file_outline/python_outline_v2.py +156 -156
  86. janito/tools/adapters/local/get_file_outline/search_outline.py +33 -33
  87. janito/tools/adapters/local/move_file.py +3 -13
  88. janito/tools/adapters/local/python_code_run.py +166 -166
  89. janito/tools/adapters/local/python_command_run.py +164 -164
  90. janito/tools/adapters/local/python_file_run.py +163 -163
  91. janito/tools/adapters/local/remove_directory.py +6 -17
  92. janito/tools/adapters/local/remove_file.py +4 -10
  93. janito/tools/adapters/local/replace_text_in_file.py +6 -9
  94. janito/tools/adapters/local/run_bash_command.py +176 -176
  95. janito/tools/adapters/local/run_powershell_command.py +219 -219
  96. janito/tools/adapters/local/search_text/__init__.py +1 -1
  97. janito/tools/adapters/local/search_text/core.py +201 -201
  98. janito/tools/adapters/local/search_text/match_lines.py +1 -1
  99. janito/tools/adapters/local/search_text/pattern_utils.py +73 -73
  100. janito/tools/adapters/local/search_text/traverse_directory.py +145 -145
  101. janito/tools/adapters/local/validate_file_syntax/__init__.py +1 -1
  102. janito/tools/adapters/local/validate_file_syntax/core.py +106 -106
  103. janito/tools/adapters/local/validate_file_syntax/css_validator.py +35 -35
  104. janito/tools/adapters/local/validate_file_syntax/html_validator.py +93 -93
  105. janito/tools/adapters/local/validate_file_syntax/js_validator.py +27 -27
  106. janito/tools/adapters/local/validate_file_syntax/json_validator.py +6 -6
  107. janito/tools/adapters/local/validate_file_syntax/markdown_validator.py +109 -109
  108. janito/tools/adapters/local/validate_file_syntax/ps1_validator.py +32 -32
  109. janito/tools/adapters/local/validate_file_syntax/python_validator.py +5 -5
  110. janito/tools/adapters/local/validate_file_syntax/xml_validator.py +11 -11
  111. janito/tools/adapters/local/validate_file_syntax/yaml_validator.py +6 -6
  112. janito/tools/adapters/local/view_file.py +167 -167
  113. janito/tools/inspect_registry.py +17 -17
  114. janito/tools/tool_base.py +105 -105
  115. janito/tools/tool_events.py +58 -58
  116. janito/tools/tool_run_exception.py +12 -12
  117. janito/tools/tool_use_tracker.py +81 -81
  118. janito/tools/tool_utils.py +45 -45
  119. janito/tools/tools_adapter.py +78 -6
  120. janito/tools/tools_schema.py +104 -104
  121. janito/version.py +4 -4
  122. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/METADATA +388 -251
  123. janito-2.3.0.dist-info/RECORD +181 -0
  124. janito/drivers/google_genai/driver.py +0 -54
  125. janito/drivers/google_genai/schema_generator.py +0 -67
  126. janito-2.2.0.dist-info/RECORD +0 -182
  127. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/WHEEL +0 -0
  128. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/entry_points.txt +0 -0
  129. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/licenses/LICENSE +0 -0
  130. {janito-2.2.0.dist-info → janito-2.3.0.dist-info}/top_level.txt +0 -0
@@ -1,156 +1,156 @@
1
- import re
2
- from typing import List
3
-
4
-
5
- def extract_signature_and_decorators(lines, start_idx):
6
- """
7
- Extracts the signature line and leading decorators for a given function/class/method.
8
- Returns (signature:str, decorators:List[str], signature_lineno:int)
9
- """
10
- decorators = []
11
- sig_line = None
12
- sig_lineno = start_idx
13
- for i in range(start_idx - 1, -1, -1):
14
- striped = lines[i].strip()
15
- if striped.startswith("@"):
16
- decorators.insert(0, striped)
17
- sig_lineno = i
18
- elif not striped:
19
- continue
20
- else:
21
- break
22
- # Find the signature line itself
23
- for k in range(start_idx, len(lines)):
24
- striped = lines[k].strip()
25
- if striped.startswith("def ") or striped.startswith("class "):
26
- sig_line = striped
27
- sig_lineno = k
28
- break
29
- return sig_line, decorators, sig_lineno
30
-
31
-
32
- def extract_docstring(lines, start_idx, end_idx):
33
- """Extracts a docstring from lines[start_idx:end_idx] if present."""
34
- for i in range(start_idx, min(end_idx, len(lines))):
35
- line = lines[i].lstrip()
36
- if not line:
37
- continue
38
- if line.startswith('"""') or line.startswith("'''"):
39
- quote = line[:3]
40
- doc = line[3:]
41
- if doc.strip().endswith(quote):
42
- return doc.strip()[:-3].strip()
43
- docstring_lines = [doc]
44
- for j in range(i + 1, min(end_idx, len(lines))):
45
- line = lines[j]
46
- if line.strip().endswith(quote):
47
- docstring_lines.append(line.strip()[:-3])
48
- return "\n".join([d.strip() for d in docstring_lines]).strip()
49
- docstring_lines.append(line)
50
- break
51
- else:
52
- break
53
- return ""
54
-
55
-
56
- def build_outline_entry(obj, lines, outline):
57
- obj_type, name, start, end, parent, indent = obj
58
- # Determine if this is a method
59
- if obj_type == "function" and parent:
60
- outline_type = "method"
61
- elif obj_type == "function":
62
- outline_type = "function"
63
- else:
64
- outline_type = obj_type
65
- docstring = extract_docstring(lines, start, end)
66
- signature, decorators, signature_lineno = extract_signature_and_decorators(
67
- lines, start - 1
68
- )
69
- outline.append(
70
- {
71
- "type": outline_type,
72
- "name": name,
73
- "start": start,
74
- "end": end,
75
- "parent": parent,
76
- "signature": signature,
77
- "decorators": decorators,
78
- "docstring": docstring,
79
- }
80
- )
81
-
82
-
83
- def parse_python_outline_v2(lines: List[str]):
84
- class_pat = re.compile(r"^(\s*)class\s+(\w+)")
85
- func_pat = re.compile(r"^(\s*)def\s+(\w+)")
86
- assign_pat = re.compile(r"^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=.*")
87
- main_pat = re.compile(r"^\s*if\s+__name__\s*==\s*[\'\"]__main__[\'\"]\s*:")
88
- outline = []
89
- stack = []
90
- obj_ranges = []
91
- last_top_obj = None
92
- for idx, line in enumerate(lines):
93
- class_match = class_pat.match(line)
94
- func_match = func_pat.match(line)
95
- assign_match = assign_pat.match(line)
96
- indent = len(line) - len(line.lstrip())
97
- parent = ""
98
- for s in reversed(stack):
99
- if s[0] == "class" and indent > s[2]:
100
- parent = s[1]
101
- break
102
- if class_match:
103
- obj = ("class", class_match.group(2), idx + 1, None, parent, indent)
104
- stack.append(obj)
105
- last_top_obj = obj
106
- elif func_match:
107
- obj = ("function", func_match.group(2), idx + 1, None, parent, indent)
108
- stack.append(obj)
109
- last_top_obj = obj
110
- elif assign_match and indent == 0:
111
- outline.append(
112
- {
113
- "type": "const" if assign_match.group(2).isupper() else "var",
114
- "name": assign_match.group(2),
115
- "start": idx + 1,
116
- "end": idx + 1,
117
- "parent": "",
118
- "signature": line.strip(),
119
- "decorators": [],
120
- "docstring": "",
121
- }
122
- )
123
- if line.strip().startswith("if __name__ == "):
124
- outline.append(
125
- {
126
- "type": "main",
127
- "name": "__main__",
128
- "start": idx + 1,
129
- "end": idx + 1,
130
- "parent": "",
131
- "signature": line.strip(),
132
- "decorators": [],
133
- "docstring": "",
134
- }
135
- )
136
- # Close stack objects if indent falls back
137
- while stack and indent <= stack[-1][5] and idx + 1 > stack[-1][2]:
138
- finished = stack.pop()
139
- outline_entry = finished[:2] + (
140
- finished[2],
141
- idx + 1,
142
- finished[4],
143
- finished[5],
144
- )
145
- build_outline_entry(outline_entry, lines, outline)
146
- # Close any remaining objects
147
- while stack:
148
- finished = stack.pop()
149
- outline_entry = finished[:2] + (
150
- finished[2],
151
- len(lines),
152
- finished[4],
153
- finished[5],
154
- )
155
- build_outline_entry(outline_entry, lines, outline)
156
- return outline
1
+ import re
2
+ from typing import List
3
+
4
+
5
+ def extract_signature_and_decorators(lines, start_idx):
6
+ """
7
+ Extracts the signature line and leading decorators for a given function/class/method.
8
+ Returns (signature:str, decorators:List[str], signature_lineno:int)
9
+ """
10
+ decorators = []
11
+ sig_line = None
12
+ sig_lineno = start_idx
13
+ for i in range(start_idx - 1, -1, -1):
14
+ striped = lines[i].strip()
15
+ if striped.startswith("@"):
16
+ decorators.insert(0, striped)
17
+ sig_lineno = i
18
+ elif not striped:
19
+ continue
20
+ else:
21
+ break
22
+ # Find the signature line itself
23
+ for k in range(start_idx, len(lines)):
24
+ striped = lines[k].strip()
25
+ if striped.startswith("def ") or striped.startswith("class "):
26
+ sig_line = striped
27
+ sig_lineno = k
28
+ break
29
+ return sig_line, decorators, sig_lineno
30
+
31
+
32
+ def extract_docstring(lines, start_idx, end_idx):
33
+ """Extracts a docstring from lines[start_idx:end_idx] if present."""
34
+ for i in range(start_idx, min(end_idx, len(lines))):
35
+ line = lines[i].lstrip()
36
+ if not line:
37
+ continue
38
+ if line.startswith('"""') or line.startswith("'''"):
39
+ quote = line[:3]
40
+ doc = line[3:]
41
+ if doc.strip().endswith(quote):
42
+ return doc.strip()[:-3].strip()
43
+ docstring_lines = [doc]
44
+ for j in range(i + 1, min(end_idx, len(lines))):
45
+ line = lines[j]
46
+ if line.strip().endswith(quote):
47
+ docstring_lines.append(line.strip()[:-3])
48
+ return "\n".join([d.strip() for d in docstring_lines]).strip()
49
+ docstring_lines.append(line)
50
+ break
51
+ else:
52
+ break
53
+ return ""
54
+
55
+
56
+ def build_outline_entry(obj, lines, outline):
57
+ obj_type, name, start, end, parent, indent = obj
58
+ # Determine if this is a method
59
+ if obj_type == "function" and parent:
60
+ outline_type = "method"
61
+ elif obj_type == "function":
62
+ outline_type = "function"
63
+ else:
64
+ outline_type = obj_type
65
+ docstring = extract_docstring(lines, start, end)
66
+ signature, decorators, signature_lineno = extract_signature_and_decorators(
67
+ lines, start - 1
68
+ )
69
+ outline.append(
70
+ {
71
+ "type": outline_type,
72
+ "name": name,
73
+ "start": start,
74
+ "end": end,
75
+ "parent": parent,
76
+ "signature": signature,
77
+ "decorators": decorators,
78
+ "docstring": docstring,
79
+ }
80
+ )
81
+
82
+
83
+ def parse_python_outline_v2(lines: List[str]):
84
+ class_pat = re.compile(r"^(\s*)class\s+(\w+)")
85
+ func_pat = re.compile(r"^(\s*)def\s+(\w+)")
86
+ assign_pat = re.compile(r"^(\s*)([A-Za-z_][A-Za-z0-9_]*)\s*=.*")
87
+ main_pat = re.compile(r"^\s*if\s+__name__\s*==\s*[\'\"]__main__[\'\"]\s*:")
88
+ outline = []
89
+ stack = []
90
+ obj_ranges = []
91
+ last_top_obj = None
92
+ for idx, line in enumerate(lines):
93
+ class_match = class_pat.match(line)
94
+ func_match = func_pat.match(line)
95
+ assign_match = assign_pat.match(line)
96
+ indent = len(line) - len(line.lstrip())
97
+ parent = ""
98
+ for s in reversed(stack):
99
+ if s[0] == "class" and indent > s[2]:
100
+ parent = s[1]
101
+ break
102
+ if class_match:
103
+ obj = ("class", class_match.group(2), idx + 1, None, parent, indent)
104
+ stack.append(obj)
105
+ last_top_obj = obj
106
+ elif func_match:
107
+ obj = ("function", func_match.group(2), idx + 1, None, parent, indent)
108
+ stack.append(obj)
109
+ last_top_obj = obj
110
+ elif assign_match and indent == 0:
111
+ outline.append(
112
+ {
113
+ "type": "const" if assign_match.group(2).isupper() else "var",
114
+ "name": assign_match.group(2),
115
+ "start": idx + 1,
116
+ "end": idx + 1,
117
+ "parent": "",
118
+ "signature": line.strip(),
119
+ "decorators": [],
120
+ "docstring": "",
121
+ }
122
+ )
123
+ if line.strip().startswith("if __name__ == "):
124
+ outline.append(
125
+ {
126
+ "type": "main",
127
+ "name": "__main__",
128
+ "start": idx + 1,
129
+ "end": idx + 1,
130
+ "parent": "",
131
+ "signature": line.strip(),
132
+ "decorators": [],
133
+ "docstring": "",
134
+ }
135
+ )
136
+ # Close stack objects if indent falls back
137
+ while stack and indent <= stack[-1][5] and idx + 1 > stack[-1][2]:
138
+ finished = stack.pop()
139
+ outline_entry = finished[:2] + (
140
+ finished[2],
141
+ idx + 1,
142
+ finished[4],
143
+ finished[5],
144
+ )
145
+ build_outline_entry(outline_entry, lines, outline)
146
+ # Close any remaining objects
147
+ while stack:
148
+ finished = stack.pop()
149
+ outline_entry = finished[:2] + (
150
+ finished[2],
151
+ len(lines),
152
+ finished[4],
153
+ finished[5],
154
+ )
155
+ build_outline_entry(outline_entry, lines, outline)
156
+ return outline
@@ -1,33 +1,33 @@
1
- from janito.tools.tool_base import ToolBase
2
- from janito.report_events import ReportAction
3
-
4
-
5
- class SearchOutlineTool(ToolBase):
6
- """
7
- Tool for searching outlines in files.
8
-
9
- Args:
10
- file_path (str): Path to the file for which to generate an outline.
11
- Returns:
12
- str: Outline search result or status message.
13
- """
14
-
15
- tool_name = "search_outline"
16
-
17
- def run(self, file_path: str) -> str:
18
- from janito.tools.tool_utils import display_path
19
- from janito.i18n import tr
20
-
21
- self.report_action(
22
- tr(
23
- "🔍 Searching for outline in '{disp_path}'",
24
- disp_path=display_path(file_path),
25
- ),
26
- ReportAction.READ,
27
- )
28
- # ... rest of implementation ...
29
- # Example warnings and successes:
30
- # self.report_warning(tr("No files found with supported extensions."))
31
- # self.report_warning(tr("Error reading {file_path}: {error}", file_path=file_path, error=e))
32
- # self.report_success(tr("✅ {count} {match_word} found", count=len(output), match_word=pluralize('match', len(output))))
33
- pass
1
+ from janito.tools.tool_base import ToolBase
2
+ from janito.report_events import ReportAction
3
+
4
+
5
+ class SearchOutlineTool(ToolBase):
6
+ """
7
+ Tool for searching outlines in files.
8
+
9
+ Args:
10
+ file_path (str): Path to the file for which to generate an outline.
11
+ Returns:
12
+ str: Outline search result or status message.
13
+ """
14
+
15
+ tool_name = "search_outline"
16
+
17
+ def run(self, file_path: str) -> str:
18
+ from janito.tools.tool_utils import display_path
19
+ from janito.i18n import tr
20
+
21
+ self.report_action(
22
+ tr(
23
+ "🔍 Searching for outline in '{disp_path}'",
24
+ disp_path=display_path(file_path),
25
+ ),
26
+ ReportAction.READ,
27
+ )
28
+ # ... rest of implementation ...
29
+ # Example warnings and successes:
30
+ # self.report_warning(tr("No files found with supported extensions."))
31
+ # self.report_warning(tr("Error reading {file_path}: {error}", file_path=file_path, error=e))
32
+ # self.report_success(tr("✅ {count} {match_word} found", count=len(output), match_word=pluralize('match', len(output))))
33
+ pass
@@ -16,7 +16,7 @@ class MoveFileTool(ToolBase):
16
16
  src_path (str): Source file or directory path.
17
17
  dest_path (str): Destination file or directory path.
18
18
  overwrite (bool, optional): Whether to overwrite if the destination exists. Defaults to False.
19
- backup (bool, optional): If True, create a backup (.bak for files, .bak.zip for directories) of the destination before moving if it exists. Recommend using backup=True only in the first call to avoid redundant backups. Defaults to False.
19
+ backup (bool, optional): Deprecated. No backups are created anymore. This flag is ignored. Defaults to False.
20
20
  Returns:
21
21
  str: Status message indicating the result.
22
22
  """
@@ -60,11 +60,7 @@ class MoveFileTool(ToolBase):
60
60
  shutil.move(src, dest)
61
61
  self.report_success(tr("✅ Move complete."))
62
62
  msg = tr("✅ Move complete.")
63
- if backup_path:
64
- msg += tr(
65
- " (backup at {backup_disp})",
66
- backup_disp=display_path(backup_path),
67
- )
63
+
68
64
  return msg
69
65
  except Exception as e:
70
66
  self.report_error(tr("❌ Error moving: {error}", error=e))
@@ -116,13 +112,7 @@ class MoveFileTool(ToolBase):
116
112
  "❗ Destination '{disp_dest}' already exists and overwrite is False.",
117
113
  disp_dest=disp_dest,
118
114
  )
119
- if backup:
120
- if os.path.isfile(dest):
121
- backup_path = dest + ".bak"
122
- shutil.copy2(dest, backup_path)
123
- elif os.path.isdir(dest):
124
- backup_path = dest.rstrip("/\\") + ".bak.zip"
125
- shutil.make_archive(dest.rstrip("/\\") + ".bak", "zip", dest)
115
+
126
116
  try:
127
117
  if os.path.isfile(dest):
128
118
  os.remove(dest)