janito 1.4.0__py3-none-any.whl → 1.4.1__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.
janito/__init__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "1.4.0"
1
+ __version__ = "1.4.1"
@@ -45,7 +45,13 @@ class ConversationHandler:
45
45
  if spinner:
46
46
  # Calculate word count for all messages
47
47
  word_count = sum(len(str(m.get('content', '')).split()) for m in messages if 'content' in m)
48
- spinner_msg = f"[bold green]Waiting for AI response... ({word_count} words in conversation)"
48
+ def format_count(n):
49
+ if n >= 1_000_000:
50
+ return f"{n/1_000_000:.1f}m"
51
+ elif n >= 1_000:
52
+ return f"{n/1_000:.1f}k"
53
+ return str(n)
54
+ spinner_msg = f"[bold green]Waiting for AI response... ({format_count(word_count)} words in conversation)"
49
55
  with console.status(spinner_msg, spinner="dots") as status:
50
56
  response = self.client.chat.completions.create(
51
57
  model=self.model,
@@ -8,7 +8,7 @@ from janito.agent.tools.tool_base import ToolBase
8
8
  class FetchUrlTool(ToolBase):
9
9
  """Fetch the content of a web page and extract its text."""
10
10
  def call(self, url: str, search_strings: list[str] = None) -> str:
11
- print_info(f"🌐 Fetching URL: {url} ... ")
11
+ print_info(f"🌐 Fetching URL: {url} ... ", end="")
12
12
  response = requests.get(url, timeout=10)
13
13
  response.raise_for_status()
14
14
  self.update_progress(f"Fetched URL with status {response.status_code}")
@@ -29,7 +29,7 @@ class FetchUrlTool(ToolBase):
29
29
  else:
30
30
  text = "No matches found for the provided search strings."
31
31
 
32
- print_success("\u2705 Success")
32
+ print_success(" Success")
33
33
  return text
34
34
 
35
35
  ToolHandler.register_tool(FetchUrlTool, name="fetch_url")
@@ -31,11 +31,11 @@ class CreateFileTool(ToolBase):
31
31
  old_lines = sum(1 for _ in f)
32
32
  with open(path, "w", encoding="utf-8") as f:
33
33
  f.write(content)
34
- print_success("✅ Success")
34
+ new_lines = content.count('\n') + 1 if content else 0
35
35
  if old_lines is not None:
36
- new_lines = content.count('\n') + 1 if content else 0
36
+ print_success(f"✅ Successfully updated the file at '{disp_path}' ({old_lines} > {new_lines} lines).")
37
37
  return f"✅ Successfully updated the file at '{disp_path}' ({old_lines} > {new_lines} lines)."
38
- new_lines = content.count('\n') + 1 if content else 0
38
+ print_success(f"✅ Successfully created the file at '{disp_path}' ({new_lines} lines).")
39
39
  return f"✅ Successfully created the file at '{disp_path}' ({new_lines} lines)."
40
40
 
41
41
  class CreateDirectoryTool(ToolBase):
@@ -58,57 +58,3 @@ class CreateDirectoryTool(ToolBase):
58
58
  if not os.path.isdir(path):
59
59
  print_error(f"❌ Path '{disp_path}' exists and is not a directory.")
60
60
  return f"❌ Path '{disp_path}' exists and is not a directory."
61
- if not overwrite:
62
- print_error(f"❗ Directory '{disp_path}' already exists and overwrite is False.")
63
- return f"❗ Directory '{disp_path}' already exists and overwrite is False."
64
- # Remove existing directory if overwrite is True
65
- shutil.rmtree(path)
66
- print_info(f"🗑️ Removed existing directory: '{disp_path}'")
67
- os.makedirs(path, exist_ok=True)
68
- print_success(f"✅ Created directory: '{disp_path}'")
69
- return f"✅ Successfully created directory at '{disp_path}'."
70
-
71
- class RemoveFileTool(ToolBase):
72
- """
73
- Remove a file at the specified path.
74
- """
75
- def call(self, path: str) -> str:
76
- original_path = path
77
- path = expand_path(path)
78
- disp_path = display_path(original_path, path)
79
- print_info(f"🗑️ Removing file: '{disp_path}' ... ")
80
- os.remove(path)
81
- print_success("✅ Success")
82
- return f"✅ Successfully deleted the file at '{disp_path}'."
83
-
84
- class MoveFileTool(ToolBase):
85
- """
86
- Move or rename a file from source to destination.
87
- """
88
- def call(self, source_path: str, destination_path: str, overwrite: bool = False) -> str:
89
- orig_source = source_path
90
- orig_dest = destination_path
91
- source_path = expand_path(source_path)
92
- destination_path = expand_path(destination_path)
93
- disp_source = display_path(orig_source, source_path)
94
- disp_dest = display_path(orig_dest, destination_path)
95
- print_info(f"🚚 Moving '{disp_source}' to '{disp_dest}' ... ")
96
- if not os.path.exists(source_path):
97
- print_error(f"❌ Error: source does not exist")
98
- return f"❌ Source path '{disp_source}' does not exist."
99
- if os.path.exists(destination_path):
100
- if not overwrite:
101
- print_error(f"❗ Error: destination exists and overwrite is False")
102
- return f"❗ Destination path '{disp_dest}' already exists and overwrite is False."
103
- if os.path.isdir(destination_path):
104
- print_error(f"❌ Error: destination is a directory")
105
- return f"❌ Destination path '{disp_dest}' is an existing directory."
106
- shutil.move(source_path, destination_path)
107
- print_success("✅ Success")
108
- return f"✅ Successfully moved '{disp_source}' to '{disp_dest}'."
109
-
110
- # register tools
111
- ToolHandler.register_tool(CreateFileTool, name="create_file")
112
- ToolHandler.register_tool(CreateDirectoryTool, name="create_directory")
113
- ToolHandler.register_tool(RemoveFileTool, name="remove_file")
114
- ToolHandler.register_tool(MoveFileTool, name="move_file")
@@ -15,7 +15,7 @@ class FindFilesTool(ToolBase):
15
15
  return os.path.relpath(path)
16
16
  disp_path = _display_path(directory)
17
17
  rec = "recursively" if recursive else "non-recursively"
18
- print_info(f"\U0001F50D Searching '{disp_path}' for pattern '{pattern}' ({rec}, max {max_results})")
18
+ print_info(f"\U0001F50D Searching '{disp_path}' for pattern '{pattern}' ({rec}, max {max_results})", end="")
19
19
  self.update_progress(f"Searching for files in {directory} matching {pattern}")
20
20
  matches = []
21
21
  for root, dirs, files in os.walk(directory):
@@ -6,14 +6,15 @@ from janito.agent.tools.rich_utils import print_info, print_success, print_error
6
6
  class GetFileOutlineTool(ToolBase):
7
7
  """Get an outline of a file's structure."""
8
8
  def call(self, file_path: str) -> str:
9
- print_info(f"📄 Getting outline for: {file_path}")
9
+ print_info(f"\U0001F4C4 Getting outline for: {file_path}", end="")
10
10
  self.update_progress(f"Getting outline for: {file_path}")
11
11
  try:
12
12
  with open(file_path, 'r', encoding='utf-8') as f:
13
13
  lines = f.readlines()
14
14
  outline = [line.strip() for line in lines if line.strip()]
15
- print_success(f"\u2705 Outline generated for {file_path}")
16
- return '\n'.join(outline)
15
+ num_items = len(outline)
16
+ print_success(f"✅ Outline generated ({num_items} items)")
17
+ return f"Outline: {num_items} items\n" + '\n'.join(outline)
17
18
  except Exception as e:
18
19
  print_error(f"\u274c Error reading file: {e}")
19
20
  return f"Error reading file: {e}"
@@ -28,6 +28,9 @@ class GetLinesTool(ToolBase):
28
28
  print_success(f" ✅ {len(lines)} lines read")
29
29
  return ''.join(selected)
30
30
  except Exception as e:
31
+ if isinstance(e, FileNotFoundError):
32
+ print_error(f"❗ not found")
33
+ return "❗ not found"
31
34
  print_error(f" ❌ Error: {e}")
32
35
  return f"Error reading file: {e}"
33
36
 
@@ -7,7 +7,7 @@ import py_compile
7
7
  class PyCompileTool(ToolBase):
8
8
  """Validate a Python file by compiling it with py_compile."""
9
9
  def call(self, file_path: str, doraise: Optional[bool] = True) -> str:
10
- print_info(f"[py_compile] Compiling Python file: {file_path}")
10
+ print_info(f"[py_compile] Compiling Python file: {file_path}", end="")
11
11
  self.update_progress(f"Compiling Python file: {file_path}")
12
12
  try:
13
13
  py_compile.compile(file_path, doraise=doraise)
@@ -31,7 +31,7 @@ class PythonExecTool(ToolBase):
31
31
  str: Formatted stdout, stderr, and return code.
32
32
  """
33
33
  def call(self, code: str) -> str:
34
- print_info(f"🐍 Executing Python code ...")
34
+ print_info(f"🐍 Executing Python code ...", end="")
35
35
  print_info(code)
36
36
  self.update_progress("Starting Python code execution...")
37
37
  result_queue = multiprocessing.Queue()
@@ -45,7 +45,7 @@ class PythonExecTool(ToolBase):
45
45
  self.update_progress(f"Python code execution completed with return code: {result['returncode']}")
46
46
  if result['returncode'] == 0:
47
47
  from janito.agent.tools.rich_utils import print_success
48
- print_success(f"\u2705 Python code executed successfully.")
48
+ print_success(f" Python code executed successfully.")
49
49
  else:
50
50
  from janito.agent.tools.rich_utils import print_error
51
51
  print_error(f"\u274c Python code execution failed with return code {result['returncode']}")
@@ -8,14 +8,14 @@ from janito.agent.tools.rich_utils import print_info, print_success, print_error
8
8
  class RemoveDirectoryTool(ToolBase):
9
9
  """Remove a directory. If recursive=False and directory not empty, raises error."""
10
10
  def call(self, directory: str, recursive: bool = False) -> str:
11
- print_info(f"🗃️ Removing directory: {directory} (recursive={recursive})")
11
+ print_info(f"🗃️ Removing directory: {directory} (recursive={recursive})", end="")
12
12
  self.update_progress(f"Removing directory: {directory} (recursive={recursive})")
13
13
  try:
14
14
  if recursive:
15
15
  shutil.rmtree(directory)
16
16
  else:
17
17
  os.rmdir(directory)
18
- print_success(f"\u2705 Directory removed: {directory}")
18
+ print_success(f" Directory removed: {directory}")
19
19
  return f"Directory removed: {directory}"
20
20
  except Exception as e:
21
21
  print_error(f"\u274c Error removing directory: {e}")
@@ -7,7 +7,7 @@ from janito.agent.tools.rich_utils import print_info, print_success
7
7
  class SearchFilesTool(ToolBase):
8
8
  """Search for a text pattern in all files within a directory and return matching lines."""
9
9
  def call(self, directory: str, pattern: str) -> str:
10
- print_info(f"🔎 Searching for pattern '{pattern}' in directory {directory}")
10
+ print_info(f"🔎 Searching for pattern '{pattern}' in directory {directory}", end="")
11
11
  self.update_progress(f"Searching for pattern '{pattern}' in directory {directory}")
12
12
  matches = []
13
13
  for root, dirs, files in os.walk(directory):
@@ -20,7 +20,7 @@ class SearchFilesTool(ToolBase):
20
20
  matches.append(f"{path}:{lineno}: {line.strip()}")
21
21
  except Exception:
22
22
  continue
23
- print_success(f"\u2705 {len(matches)} matches found")
23
+ print_success(f" {len(matches)} matches found")
24
24
  return '\n'.join(matches)
25
25
 
26
26
  ToolHandler.register_tool(SearchFilesTool, name="search_files")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: janito
3
- Version: 1.4.0
3
+ Version: 1.4.1
4
4
  Summary: A Natural Programming Language Agent,
5
5
  Author-email: João Pinto <joao.pinto@gmail.com>
6
6
  License: MIT
@@ -8,7 +8,6 @@ Project-URL: homepage, https://github.com/joaompinto/janito
8
8
  Project-URL: repository, https://github.com/joaompinto/janito
9
9
  Keywords: agent,framework,tools,automation
10
10
  Classifier: Programming Language :: Python :: 3.10
11
- Classifier: License :: OSI Approved :: MIT License
12
11
  Classifier: Operating System :: OS Independent
13
12
  Requires-Python: >=3.10
14
13
  Description-Content-Type: text/markdown
@@ -1,4 +1,4 @@
1
- janito/__init__.py,sha256=-pa9pj_zJgPDZtE3ena4mjuVS3FEWQWYij1shjLYS80,23
1
+ janito/__init__.py,sha256=nxjQ6mMSJJKqkpX2IY-1BmdpErEa1Lx5hYzk9ULB09w,23
2
2
  janito/__main__.py,sha256=CBScR30Tm-vuhIJM8o5HXKr0q-smICiwSVyuU68BP8U,78
3
3
  janito/render_prompt.py,sha256=xCQgYRqMyz9Pzi7096NoZfC4lFiKEHEaXiTYP6ByViY,513
4
4
  janito/agent/__init__.py,sha256=CByAH5Yk-yH64zo0RU7Z3nsn_7Vmandphqk0JNlpyj8,21
@@ -6,27 +6,27 @@ janito/agent/agent.py,sha256=X5swt-SUKnIxrSQaGfhxPk61M-BXREz4n02ynE0dVVU,4245
6
6
  janito/agent/config.py,sha256=Z-_IeWxJB_1ca5LVR7PtHChZgc5eAsgegyEmVAxr1NY,4472
7
7
  janito/agent/config_defaults.py,sha256=vSif3tJYZ7pMHaNqH6jGb7EKctfE-Kt8ueD17sC0ESY,395
8
8
  janito/agent/config_utils.py,sha256=UmvR236wDrMc-aTy9LxVbop6YeoJaaPb1d2DBMlkSRg,254
9
- janito/agent/conversation.py,sha256=vbCL-1LlJjKRN6q3CjfSe4ENGplP-YQKsAEA1uX3RWU,6184
9
+ janito/agent/conversation.py,sha256=Ih1brlxJ4m3LZS99gqgH9XK2ohTSLPOurCqd0RqCXm8,6453
10
10
  janito/agent/queued_tool_handler.py,sha256=THPymKXnpoXfN49EhW5b4hrwpWZZup73JKFDJ_U03tI,540
11
11
  janito/agent/runtime_config.py,sha256=H6bnRVYR0zC-WhmLpBU-IXikXWKcIiBQqFnc4uGooj4,908
12
12
  janito/agent/tool_handler.py,sha256=h-pxG1lhyIJohZmvwHSsknBSonrJQYGGzBL6Tobgmrg,7414
13
13
  janito/agent/templates/system_instructions.j2,sha256=BtwMcibxnwZmQhGN7p_VGhhyAPzCfqksnW4B-PTWa-8,1532
14
14
  janito/agent/tools/__init__.py,sha256=Vv1oWF6Ur-Tkm3p0KCz5HD7wwar9rUHtY596NGPnn2s,378
15
15
  janito/agent/tools/ask_user.py,sha256=C1YC_gr0kh3-7vw2PgdIi4D8Paw-eNGpaWQy4HD3Gmo,2180
16
- janito/agent/tools/fetch_url.py,sha256=XUHEex1An1Ql4p8H1UKWzaIxo9a6WkZC4uRPkhBQHeU,1418
17
- janito/agent/tools/file_ops.py,sha256=5FnggSPv-Tsgq038T1YK5bpJZE5kPY_biB5fXZg48X0,5476
18
- janito/agent/tools/find_files.py,sha256=jq55uUSfAUJ2gmJ29YQmo8XZ92cptb2C5hpc_pjbrQg,1364
19
- janito/agent/tools/get_file_outline.py,sha256=aLNNWMalvE-3CXLEuBVe4ihDMciP4grbsol6Yw01O44,959
20
- janito/agent/tools/get_lines.py,sha256=0Yg6JFPAOCJuR7HYcFIGwn83BCv_SnuWp0T7v4RtT9Q,1555
16
+ janito/agent/tools/fetch_url.py,sha256=UZ9lv0Ko88eDeu6gvEqqPQ5Yug2aBb1NawaoFAIte8Y,1423
17
+ janito/agent/tools/file_ops.py,sha256=qdcroy6aE0f4ZZERgbFEsxkzc0yJZAvlhtFl_6JIEaM,2884
18
+ janito/agent/tools/find_files.py,sha256=unw82GwaNa6_2kKD2wTzJ9r66-j_FHboi2W3bfCMAaw,1372
19
+ janito/agent/tools/get_file_outline.py,sha256=OUJui1oxKkQUDtGaIHAK-u8xG60Vv8VvO_Idy-7xr6k,1046
20
+ janito/agent/tools/get_lines.py,sha256=QoJGgINpghe87i6j20UhBGPa9rFI1DHEojh8PR1e_ek,1692
21
21
  janito/agent/tools/gitignore_utils.py,sha256=z_IYilabTD_-c14aRxuVasojOzTsg-11xJPJqudWIKA,1306
22
- janito/agent/tools/py_compile.py,sha256=y8f48WaHpsPFCt1Ksi-JEVbFxWvZU-lQzCHsR796pWg,1099
23
- janito/agent/tools/python_exec.py,sha256=TPU1LvRNNJMpsyhy1kD8pe2go5V2fheD93HBjKrXrFM,2188
24
- janito/agent/tools/remove_directory.py,sha256=xcyGyF5vC_AU7dzIVNa65aYUYuF5mBjGZ2MwnLsLafs,1076
22
+ janito/agent/tools/py_compile.py,sha256=fYGR6zRepmV7uHExOEaa61Fr7IdnY7a7HOhtFJ-xnzY,1107
23
+ janito/agent/tools/python_exec.py,sha256=R8PenQliPTdNEazvuW6bW4MYioO9Q46oAMJK-hg3qTI,2193
24
+ janito/agent/tools/remove_directory.py,sha256=UvtTd3pxKRQ2I4hyFBBuOORz2OygvlMgM8akeMHvwSw,1081
25
25
  janito/agent/tools/replace_text_in_file.py,sha256=eO7YumsT8Eq3_SOgl5DW_k9vhXO7egyMaiB6ZgtiHRU,3894
26
26
  janito/agent/tools/rich_live.py,sha256=cuZ3-ZxpuHxR1TvIcp0bi9F3QM1M6Ms0XiOMd8If8gU,1161
27
27
  janito/agent/tools/rich_utils.py,sha256=Lc4phM4DUG-eiiub2PFThc6pBk5aOo_6f09JPdZIdsk,894
28
28
  janito/agent/tools/run_bash_command.py,sha256=rKAx_n6xxpHeBzDg_7BVkAjMgPGiXVLpjx6i2o1lMb0,3883
29
- janito/agent/tools/search_files.py,sha256=ejHDp_I-GGQPucAKcXLgVO3LFPiOXNS77tEHME9QsvQ,1250
29
+ janito/agent/tools/search_files.py,sha256=h6-7DsWdrvzBhBWE0NkmELV0ZzO8Dme1kmfOgYL3x9Y,1255
30
30
  janito/agent/tools/tool_base.py,sha256=nS2FXSw3YY6gJiKh-l1m1udnHT7F3yKwGpGHJHfERbY,836
31
31
  janito/agent/tools/utils.py,sha256=cKZ2qxK-S01mzBmCXYWwQ9zOyT994SaoRZYbD1o57Dk,1113
32
32
  janito/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -47,9 +47,9 @@ janito/cli_chat_shell/ui.py,sha256=9IngH8HFherjatfa9Eu37jb4b2gOP0lsgcUhbnQKCZA,5
47
47
  janito/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  janito/web/__main__.py,sha256=oPXNF332aCeI7aUWr7_8M57oOKugw422VrEubxFp0P4,354
49
49
  janito/web/app.py,sha256=stogs_HaM-axsWTwoiVma9M46Y8dMu0QRjopsekRjQs,6622
50
- janito-1.4.0.dist-info/licenses/LICENSE,sha256=sHBqv0bvtrb29H7WRR-Z603YHm9pLtJIo3nHU_9cmgE,1091
51
- janito-1.4.0.dist-info/METADATA,sha256=_rNaRL-V53vjwrWJVJmgfz5XqRvekKr-Ju2bhi9G7FE,9114
52
- janito-1.4.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
53
- janito-1.4.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
54
- janito-1.4.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
55
- janito-1.4.0.dist-info/RECORD,,
50
+ janito-1.4.1.dist-info/licenses/LICENSE,sha256=sHBqv0bvtrb29H7WRR-Z603YHm9pLtJIo3nHU_9cmgE,1091
51
+ janito-1.4.1.dist-info/METADATA,sha256=NzxCNDao3CIqAETg4KZb0wTBnVD5Ne9T2jrN90zcFFk,9062
52
+ janito-1.4.1.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
53
+ janito-1.4.1.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
54
+ janito-1.4.1.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
55
+ janito-1.4.1.dist-info/RECORD,,
File without changes