janito 1.4.0__py3-none-any.whl → 1.5.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 (58) hide show
  1. janito/__init__.py +1 -1
  2. janito/agent/__init__.py +0 -1
  3. janito/agent/agent.py +7 -25
  4. janito/agent/config.py +4 -6
  5. janito/agent/config_defaults.py +2 -2
  6. janito/agent/content_handler.py +0 -0
  7. janito/agent/conversation.py +63 -37
  8. janito/agent/message_handler.py +18 -0
  9. janito/agent/openai_schema_generator.py +116 -0
  10. janito/agent/queued_message_handler.py +32 -0
  11. janito/agent/rich_tool_handler.py +43 -0
  12. janito/agent/runtime_config.py +1 -1
  13. janito/agent/templates/system_instructions.j2 +10 -4
  14. janito/agent/tool_registry.py +92 -0
  15. janito/agent/tools/append_text_to_file.py +41 -0
  16. janito/agent/tools/ask_user.py +16 -3
  17. janito/agent/tools/create_directory.py +31 -0
  18. janito/agent/tools/create_file.py +52 -0
  19. janito/agent/tools/fetch_url.py +23 -8
  20. janito/agent/tools/find_files.py +40 -21
  21. janito/agent/tools/get_file_outline.py +26 -8
  22. janito/agent/tools/get_lines.py +53 -19
  23. janito/agent/tools/move_file.py +50 -0
  24. janito/agent/tools/py_compile.py +27 -11
  25. janito/agent/tools/python_exec.py +43 -14
  26. janito/agent/tools/remove_directory.py +23 -7
  27. janito/agent/tools/remove_file.py +38 -0
  28. janito/agent/tools/replace_text_in_file.py +40 -17
  29. janito/agent/tools/run_bash_command.py +107 -80
  30. janito/agent/tools/search_files.py +38 -19
  31. janito/agent/tools/tool_base.py +30 -3
  32. janito/agent/tools/tools_utils.py +11 -0
  33. janito/agent/tools/utils.py +0 -1
  34. janito/cli/_print_config.py +1 -1
  35. janito/cli/arg_parser.py +2 -1
  36. janito/cli/config_commands.py +3 -6
  37. janito/cli/main.py +2 -2
  38. janito/cli/runner.py +18 -14
  39. janito/cli_chat_shell/chat_loop.py +10 -15
  40. janito/cli_chat_shell/commands.py +8 -3
  41. janito/cli_chat_shell/config_shell.py +0 -3
  42. janito/cli_chat_shell/session_manager.py +11 -0
  43. janito/cli_chat_shell/ui.py +12 -113
  44. janito/render_prompt.py +0 -1
  45. janito/rich_utils.py +30 -0
  46. janito/web/app.py +10 -12
  47. janito-1.5.0.dist-info/METADATA +176 -0
  48. janito-1.5.0.dist-info/RECORD +64 -0
  49. janito/agent/queued_tool_handler.py +0 -16
  50. janito/agent/tool_handler.py +0 -196
  51. janito/agent/tools/file_ops.py +0 -114
  52. janito/agent/tools/rich_utils.py +0 -31
  53. janito-1.4.0.dist-info/METADATA +0 -142
  54. janito-1.4.0.dist-info/RECORD +0 -55
  55. {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/WHEEL +0 -0
  56. {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/entry_points.txt +0 -0
  57. {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/licenses/LICENSE +0 -0
  58. {janito-1.4.0.dist-info → janito-1.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,64 @@
1
+ janito/__init__.py,sha256=TJdX3kZk_MYc3dWRgST-ZjHyS_SdJ3N_VqRvVAVCkc4,23
2
+ janito/__main__.py,sha256=CBScR30Tm-vuhIJM8o5HXKr0q-smICiwSVyuU68BP8U,78
3
+ janito/render_prompt.py,sha256=y2pqntkfC34bh5psNobW2Vv1YAI3se04-ZcFCaoWU1s,457
4
+ janito/rich_utils.py,sha256=g5D-McYEUhzhPFpZGML41sw4w75eT51gu0x7anMQjxA,1048
5
+ janito/agent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ janito/agent/agent.py,sha256=j0ZffOAbeRpFMfAlIllEt5EjWRNTvkVuukbcdTpY6Z0,3517
7
+ janito/agent/config.py,sha256=jmGQAvVvFKE4V2nZHUeLRLyneydQNfEnUu8TmxDLxq0,4428
8
+ janito/agent/config_defaults.py,sha256=73tmwpICsgpWEnpCasSR97g59LXKQBB5xQFut7ZepTE,438
9
+ janito/agent/config_utils.py,sha256=UmvR236wDrMc-aTy9LxVbop6YeoJaaPb1d2DBMlkSRg,254
10
+ janito/agent/content_handler.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ janito/agent/conversation.py,sha256=qwfQeM8Rv-Tl-pBVzlTIHrFyl20vgMO82W82JLYmTjk,7550
12
+ janito/agent/message_handler.py,sha256=6g-cQg-jR-93nZIku3dNLJhLL8nZtHSbMwQqmfpyBRA,673
13
+ janito/agent/openai_schema_generator.py,sha256=dE3gUPX_ZqYzuY9rWY5Ygo9imXvy-Mn1rqPsm59Tle8,4329
14
+ janito/agent/queued_message_handler.py,sha256=raz_tQLooWpWvx1qqPrl1s4F4Xx_-wyCxQPfwcDI4II,1365
15
+ janito/agent/rich_tool_handler.py,sha256=L0YGZTnkD_iISAUdP6sLdZ8fuKKQQrRlATIlmhInPQs,1906
16
+ janito/agent/runtime_config.py,sha256=ztmU0Ajd2NS7olJxhXjHPtndqIZKuWMqFXuQm-TqCUE,891
17
+ janito/agent/tool_registry.py,sha256=4vDVdAzm_a12M2h94h_IgYeAkIVGMwDlIRohS8SydBA,3376
18
+ janito/agent/templates/system_instructions.j2,sha256=Y24edrqLydMTcbaZYSW8_xJMMEbTNVS3Iy4IHrBe0-Q,1885
19
+ janito/agent/tools/__init__.py,sha256=Vv1oWF6Ur-Tkm3p0KCz5HD7wwar9rUHtY596NGPnn2s,378
20
+ janito/agent/tools/append_text_to_file.py,sha256=sSklc9Ifo7tTKB81yRgfU7yWfeHsRBNdUQVbOYw52EE,1881
21
+ janito/agent/tools/ask_user.py,sha256=36pZLy3WPEIQyKKallbH9Bq-8ASLWb-Eza4g1VbYZ-c,2482
22
+ janito/agent/tools/create_directory.py,sha256=fFMXIqSFRx6NyRtbJvgUId-rN83mYHsAQqP-2sBjGMA,1340
23
+ janito/agent/tools/create_file.py,sha256=YQISWGBUOMFTFA_hKqanYjXNJMHK22jDSrGIxOAMWDY,2551
24
+ janito/agent/tools/fetch_url.py,sha256=RuicvHm8uQJSCPwfLv6KV9my1HCJd0ehl3yutjKyd3g,2068
25
+ janito/agent/tools/find_files.py,sha256=3jQAJTOeh8eqjnajX-jIPsTJmKablHw5c_OvPfkmqZ4,2283
26
+ janito/agent/tools/get_file_outline.py,sha256=NwyIY2XAJr9REmeyX6Lyd6SyQiLdAiSzN4dii_iltM0,1447
27
+ janito/agent/tools/get_lines.py,sha256=Y7tHnHZB0PFylcRIXtDvmFPXdoWTeXUmVrENpBgVBdM,3364
28
+ janito/agent/tools/gitignore_utils.py,sha256=z_IYilabTD_-c14aRxuVasojOzTsg-11xJPJqudWIKA,1306
29
+ janito/agent/tools/move_file.py,sha256=x-A3g6D_tdboVhsBkA-jWYm6h6K7uCYglFoY_9agbuM,2270
30
+ janito/agent/tools/py_compile.py,sha256=WzaPRoJcNtAwtyNTg5jNRSXuKGUkbqDWGYkbJuUX-vk,1470
31
+ janito/agent/tools/python_exec.py,sha256=lbOhguPDSR3xru8XrHoB5_sT_Wx8PBiS4qxWami6LpA,2932
32
+ janito/agent/tools/remove_directory.py,sha256=fcfm9nLYiLEjbaeSHC-fCH5DqvurJZS6lh4v5brlblk,1384
33
+ janito/agent/tools/remove_file.py,sha256=qVfuAJXThA4UR7iCU5DLc_UMY81iextp0_zXTgHQYg4,1506
34
+ janito/agent/tools/replace_text_in_file.py,sha256=0w5cG_MvXcxwQI-i8hX-GedW0qnEwn-eYXYaNlv4NxA,4969
35
+ janito/agent/tools/rich_live.py,sha256=cuZ3-ZxpuHxR1TvIcp0bi9F3QM1M6Ms0XiOMd8If8gU,1161
36
+ janito/agent/tools/run_bash_command.py,sha256=1LcoNNhRHH65tCmGmdEFtpA5S4L1kmODuvBQUl7LGnA,5246
37
+ janito/agent/tools/search_files.py,sha256=Po6Xnngqq95WVIkQkKLkpjugom7D4E4-RnaE50jBtc8,2222
38
+ janito/agent/tools/tool_base.py,sha256=ch08PaWMEC8hC0UmWC7fEXmRBdnsmqXn6pXhoXbGXFU,1898
39
+ janito/agent/tools/tools_utils.py,sha256=G_Ib8QamhHbBzpKDW3TeoaxGDQgjs8_Zj8TFUInl78k,354
40
+ janito/agent/tools/utils.py,sha256=cKPE9HVA1yHmKzML8Uz4YCVLNDK13MQw9ThvhC9COCI,1101
41
+ janito/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ janito/cli/_print_config.py,sha256=keQ0XJN2w5ZDG4SSQxMPaayE436mn8eSUSRuB57pGCI,3254
43
+ janito/cli/_utils.py,sha256=Q_OCFZmbr78qW4hSSUUhjondVc0ao7-iUHE7Ig8IP1g,289
44
+ janito/cli/arg_parser.py,sha256=CLHv2sbHxbSwnPvnDk10-cyasCvR9lPv4Yc96QoW1qA,3885
45
+ janito/cli/config_commands.py,sha256=lhlutyVM2lBbXTeZ2FXW9iWOvFG35uDr9Rjoksx3iJY,7957
46
+ janito/cli/logging_setup.py,sha256=dWQ0wFf4YuF5lxZlhpN6lis7G56LeFYUwQdh9nA5NmA,1141
47
+ janito/cli/main.py,sha256=O483LhcDMxNqwr5PWsVNOf-ms6DRTfUKawB9MVMJIfM,1418
48
+ janito/cli/runner.py,sha256=aQvbxzOaRQ44ZP6CutDdpms0K8inOeI1pKRyCPYPIkQ,5193
49
+ janito/cli_chat_shell/__init__.py,sha256=PDGl7xK_vgkROoXvUxGZqVQFfuL9U4TjdexpP8E2JKg,41
50
+ janito/cli_chat_shell/chat_loop.py,sha256=35BJeKLhAkdARrMUADK2qRP-Q2bQPB2P7JSUrQ8bUxY,5501
51
+ janito/cli_chat_shell/commands.py,sha256=gBdfvujRDchRl_M5HZO-eO55dmKvDi3twS8jo3qo-a4,7301
52
+ janito/cli_chat_shell/config_shell.py,sha256=vBKAJvDRaqC2uSjTFBZ2KgQJT0FoTqbCI8u1N6VoPF4,3208
53
+ janito/cli_chat_shell/load_prompt.py,sha256=B7C_IhMk3n1XBQcfOwFVDnjrj1278JL3kV4UtkeeZx8,604
54
+ janito/cli_chat_shell/session_manager.py,sha256=mdmt6mWOZOYqBiqKJ_8D2ff_31RdeJhFB_xp3g3P6B4,2164
55
+ janito/cli_chat_shell/ui.py,sha256=sPuDhRapcdJ8MRyi1DKkaU8Vot_O29RVLqOjDZPpFaU,2354
56
+ janito/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ janito/web/__main__.py,sha256=oPXNF332aCeI7aUWr7_8M57oOKugw422VrEubxFp0P4,354
58
+ janito/web/app.py,sha256=kJhrKDI7X2Ujzk_SVxctvq1loiAXHil0ckn3RQ8e3gg,6549
59
+ janito-1.5.0.dist-info/licenses/LICENSE,sha256=sHBqv0bvtrb29H7WRR-Z603YHm9pLtJIo3nHU_9cmgE,1091
60
+ janito-1.5.0.dist-info/METADATA,sha256=gyl65Ab0HqC08D1hJ0P3_ghOG6-3aqE9josu449WOFQ,7539
61
+ janito-1.5.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
62
+ janito-1.5.0.dist-info/entry_points.txt,sha256=wIo5zZxbmu4fC-ZMrsKD0T0vq7IqkOOLYhrqRGypkx4,48
63
+ janito-1.5.0.dist-info/top_level.txt,sha256=m0NaVCq0-ivxbazE2-ND0EA9Hmuijj_OGkmCbnBcCig,7
64
+ janito-1.5.0.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- from janito.agent.tool_handler import ToolHandler
2
-
3
- class QueuedToolHandler(ToolHandler):
4
- def __init__(self, queue, *args, **kwargs):
5
- super().__init__(*args, **kwargs)
6
- self._queue = queue
7
-
8
- def handle_tool_call(self, tool_call, on_progress=None):
9
- def enqueue_progress(data):
10
-
11
- self._queue.put(('tool_progress', data))
12
-
13
- if on_progress is None:
14
- on_progress = enqueue_progress
15
-
16
- return super().handle_tool_call(tool_call, on_progress=on_progress)
@@ -1,196 +0,0 @@
1
- import os
2
- import json
3
- import traceback
4
- from janito.agent.tools.tool_base import ToolBase
5
-
6
- class ToolHandler:
7
- _tool_registry = {}
8
-
9
- def __init__(self, verbose=False, enable_tools=True):
10
- self.verbose = verbose
11
- self.tools = []
12
- self.enable_tools = enable_tools
13
-
14
- @classmethod
15
- def register_tool(cls, tool=None, *, name: str = None):
16
- """
17
- Register a tool class derived from ToolBase.
18
- Args:
19
- tool: The tool class (must inherit from ToolBase).
20
- name: Optional override for the tool name.
21
- Raises:
22
- TypeError: If the tool is not a subclass of ToolBase.
23
- """
24
- if tool is None:
25
- return lambda t: cls.register_tool(t, name=name)
26
- import inspect
27
- import typing
28
- from typing import get_origin, get_args
29
-
30
- override_name = name
31
- if not (isinstance(tool, type) and issubclass(tool, ToolBase)):
32
- raise TypeError("Tool must be a class derived from ToolBase.")
33
- instance = tool()
34
- func = instance.call
35
- default_name = tool.__name__
36
- name = override_name or default_name
37
- description = tool.__doc__ or func.__doc__ or ""
38
-
39
- sig = inspect.signature(func)
40
- params_schema = {
41
- "type": "object",
42
- "properties": {},
43
- "required": []
44
- }
45
-
46
- for param_name, param in sig.parameters.items():
47
- if param.annotation is param.empty:
48
- raise TypeError(f"Parameter '{param_name}' in tool '{name}' is missing a type hint.")
49
- param_type = param.annotation
50
- schema = {}
51
-
52
- # Handle typing.Optional, typing.List, typing.Literal, etc.
53
- origin = get_origin(param_type)
54
- args = get_args(param_type)
55
-
56
- if origin is typing.Union and type(None) in args:
57
- # Optional[...] type
58
- main_type = args[0] if args[1] is type(None) else args[1]
59
- origin = get_origin(main_type)
60
- args = get_args(main_type)
61
- param_type = main_type
62
- else:
63
- main_type = param_type
64
-
65
- if origin is list or origin is typing.List:
66
- item_type = args[0] if args else str
67
- item_schema = {"type": _pytype_to_json_type(item_type)}
68
- schema = {"type": "array", "items": item_schema}
69
- elif origin is typing.Literal:
70
- schema = {"type": _pytype_to_json_type(type(args[0])), "enum": list(args)}
71
- elif main_type == int:
72
- schema = {"type": "integer"}
73
- elif main_type == float:
74
- schema = {"type": "number"}
75
- elif main_type == bool:
76
- schema = {"type": "boolean"}
77
- elif main_type == dict:
78
- schema = {"type": "object"}
79
- elif main_type == list:
80
- schema = {"type": "array", "items": {"type": "string"}}
81
- else:
82
- schema = {"type": "string"}
83
-
84
- # Add description from call method docstring if available (Google-style Args parsing)
85
- if func.__doc__:
86
- import re
87
- doc = func.__doc__
88
- args_section = re.search(r"Args:\s*(.*?)(?:\n\s*\w|Returns:|$)", doc, re.DOTALL)
89
- param_descs = {}
90
- if args_section:
91
- args_text = args_section.group(1)
92
- for match in re.finditer(r"(\w+) \([^)]+\): ([^\n]+)", args_text):
93
- pname, pdesc = match.groups()
94
- param_descs[pname] = pdesc.strip()
95
- if param_name in param_descs:
96
- schema["description"] = param_descs[param_name]
97
- params_schema["properties"][param_name] = schema
98
- if param.default is param.empty:
99
- params_schema["required"].append(param_name)
100
-
101
- # register the bound call function
102
- cls._tool_registry[name] = {
103
- "function": func,
104
- "description": description,
105
- "parameters": params_schema
106
- }
107
- return tool
108
-
109
- def register(self, func):
110
- self.tools.append(func)
111
- return func
112
-
113
- def get_tools(self):
114
- return self.tools
115
-
116
- def get_tool_schemas(self):
117
- if not getattr(self, 'enable_tools', True):
118
- return []
119
- schemas = []
120
- for name, entry in self._tool_registry.items():
121
- schemas.append({
122
- "type": "function",
123
- "function": {
124
- "name": name,
125
- "description": entry["description"],
126
- "parameters": entry["parameters"]
127
- }
128
- })
129
- return schemas
130
-
131
- def handle_tool_call(self, tool_call, on_progress=None):
132
- import uuid
133
- call_id = getattr(tool_call, 'id', None) or str(uuid.uuid4())
134
- tool_entry = self._tool_registry.get(tool_call.function.name)
135
- if not tool_entry:
136
- return f"Unknown tool: {tool_call.function.name}"
137
- func = tool_entry["function"]
138
- args = json.loads(tool_call.function.arguments)
139
- if self.verbose:
140
- print(f"[Tool Call] {tool_call.function.name} called with arguments: {args}")
141
- import inspect
142
- sig = inspect.signature(func)
143
- # Set progress callback on tool instance if possible
144
- instance = None
145
- if hasattr(func, '__self__') and isinstance(func.__self__, ToolBase):
146
- instance = func.__self__
147
- instance._progress_callback = on_progress
148
- if on_progress:
149
- on_progress({
150
- 'event': 'start',
151
- 'call_id': call_id,
152
- 'tool': tool_call.function.name,
153
- 'args': args
154
- })
155
- try:
156
- result = func(**args)
157
- except Exception as e:
158
- import traceback
159
- error_message = f"[Tool Error] {type(e).__name__}: {e}\n" + traceback.format_exc()
160
- result = error_message
161
- if self.verbose:
162
- preview = result
163
- if isinstance(result, str):
164
- lines = result.splitlines()
165
- if len(lines) > 10:
166
- preview = "\n".join(lines[:10]) + "\n... (truncated)"
167
- elif len(result) > 500:
168
- preview = result[:500] + "... (truncated)"
169
- print(f"[Tool Result] {tool_call.function.name} returned:\n{preview}")
170
- if on_progress:
171
- on_progress({
172
- 'event': 'finish',
173
- 'call_id': call_id,
174
- 'tool': tool_call.function.name,
175
- 'args': args,
176
- 'result': result
177
- })
178
- # Clean up progress callback
179
- if instance is not None:
180
- instance._progress_callback = None
181
- return result
182
-
183
- def _pytype_to_json_type(pytype):
184
- import typing
185
- if pytype == int:
186
- return "integer"
187
- elif pytype == float:
188
- return "number"
189
- elif pytype == bool:
190
- return "boolean"
191
- elif pytype == dict:
192
- return "object"
193
- elif pytype == list or pytype == typing.List:
194
- return "array"
195
- else:
196
- return "string"
@@ -1,114 +0,0 @@
1
- import os
2
- import shutil
3
- from janito.agent.tool_handler import ToolHandler
4
- from janito.agent.tools.rich_utils import print_info, print_success, print_error
5
- from janito.agent.tools.utils import expand_path, display_path
6
- from janito.agent.tools.tool_base import ToolBase
7
-
8
- class CreateFileTool(ToolBase):
9
- """
10
- Create a new file or update an existing file with the given content.
11
- """
12
- def call(self, path: str, content: str, overwrite: bool = False) -> str:
13
- original_path = path
14
- path = expand_path(path)
15
- updating = os.path.exists(path) and not os.path.isdir(path)
16
- disp_path = display_path(original_path, path)
17
- if os.path.exists(path):
18
- if os.path.isdir(path):
19
- print_error(f"❌ Error: is a directory")
20
- return f"❌ Cannot create file: '{disp_path}' is an existing directory."
21
- if not overwrite:
22
- print_error(f"❗ Error: file '{disp_path}' exists and overwrite is False")
23
- return f"❗ Cannot create file: '{disp_path}' already exists and overwrite is False."
24
- if updating and overwrite:
25
- print_info(f"📝 Updating file: '{disp_path}' ... ")
26
- else:
27
- print_info(f"📝 Creating file: '{disp_path}' ... ")
28
- old_lines = None
29
- if updating and overwrite:
30
- with open(path, "r", encoding="utf-8") as f:
31
- old_lines = sum(1 for _ in f)
32
- with open(path, "w", encoding="utf-8") as f:
33
- f.write(content)
34
- print_success("✅ Success")
35
- if old_lines is not None:
36
- new_lines = content.count('\n') + 1 if content else 0
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
39
- return f"✅ Successfully created the file at '{disp_path}' ({new_lines} lines)."
40
-
41
- class CreateDirectoryTool(ToolBase):
42
- """
43
- Create a new directory at the specified path.
44
- """
45
- def call(self, path: str, overwrite: bool = False) -> str:
46
- """
47
- Create a new directory at the specified path.
48
- Args:
49
- path (str): Path to the directory to create.
50
- overwrite (bool): Whether to remove the directory if it exists.
51
- Returns:
52
- str: Result message.
53
- """
54
- original_path = path
55
- path = expand_path(path)
56
- disp_path = display_path(original_path, path)
57
- if os.path.exists(path):
58
- if not os.path.isdir(path):
59
- print_error(f"❌ Path '{disp_path}' exists and is not a directory.")
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")
@@ -1,31 +0,0 @@
1
- from rich.console import Console
2
- from rich.text import Text
3
-
4
- console = Console()
5
-
6
- def print_info(message: str, end="\n"):
7
- console.print(message, style="cyan", end=end)
8
-
9
- def print_success(message: str, end="\n"):
10
- console.print(message, style="bold green", end=end)
11
-
12
- def print_error(message: str, end="\n"):
13
- console.print(message, style="bold red", end=end)
14
-
15
- def print_warning(message: str):
16
- console.print(message, style="yellow")
17
-
18
- def print_magenta(message: str):
19
- console.print(message, style="magenta")
20
-
21
- def print_bash_stdout(message: str):
22
- console.print(message, style="bold white on blue")
23
-
24
- def print_bash_stderr(message: str):
25
- console.print(message, style="bold white on red")
26
-
27
- def format_path(path: str) -> Text:
28
- return Text(path, style="cyan")
29
-
30
- def format_number(number) -> Text:
31
- return Text(str(number), style="magenta")
@@ -1,142 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: janito
3
- Version: 1.4.0
4
- Summary: A Natural Programming Language Agent,
5
- Author-email: João Pinto <joao.pinto@gmail.com>
6
- License: MIT
7
- Project-URL: homepage, https://github.com/joaompinto/janito
8
- Project-URL: repository, https://github.com/joaompinto/janito
9
- Keywords: agent,framework,tools,automation
10
- Classifier: Programming Language :: Python :: 3.10
11
- Classifier: License :: OSI Approved :: MIT License
12
- Classifier: Operating System :: OS Independent
13
- Requires-Python: >=3.10
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: beautifulsoup4
17
- Requires-Dist: flask
18
- Requires-Dist: jinja2
19
- Requires-Dist: openai
20
- Requires-Dist: pathspec
21
- Requires-Dist: prompt_toolkit
22
- Requires-Dist: requests
23
- Requires-Dist: rich
24
- Dynamic: license-file
25
-
26
- # 🚀 Janito: Natural Programming Language Agent
27
-
28
- Janito is an AI-powered assistant for the command line and web that interprets natural language instructions to edit code, manage files, and analyze projects using patterns and tools designed by experienced software engineers. It prioritizes transparency, interactive clarification, and precise, reviewable changes.
29
-
30
- ---
31
-
32
- ## ⚡ Quick Start
33
-
34
- Run a one-off prompt:
35
- ```bash
36
- python -m janito "Refactor the data processing module to improve readability."
37
- ```
38
-
39
- Or start the interactive chat shell:
40
- ```bash
41
- python -m janito
42
- ```
43
-
44
- Launch the web UI:
45
- ```bash
46
- python -m janito.web
47
- ```
48
-
49
- ---
50
-
51
- ## ✨ Key Features
52
- - 📝 **Code Editing via Natural Language:** Modify, create, or delete code files simply by describing the changes.
53
- - 📁 **File & Directory Management:** Navigate, create, move, or remove files and folders.
54
- - 🧠 **Context-Aware:** Understands your project structure for precise edits.
55
- - 💬 **Interactive User Prompts:** Asks for clarification when needed.
56
- - 🧩 **Extensible Tooling:** Built-in tools for file operations, shell commands, directory listing, Python file validation, text replacement, code execution, and more. Recent tools include:
57
- - `find_files`: Search for files matching a pattern in directories.
58
- - `get_lines`: Retrieve specific lines from files for efficient context.
59
- - `py_compile_file`: Validate Python files for syntax correctness.
60
- - `replace_text_in_file`: Replace exact text fragments in files.
61
- - `search_files`: Search for text patterns across files.
62
- - `python_exec`: Execute Python code and capture output.
63
- - And more built-in operations for code and file management.
64
- - 🌐 **Web Interface (In Development):** Upcoming simple web UI for streaming responses and tool progress.
65
-
66
- ---
67
-
68
-
69
- ## 📦 Installation
70
-
71
- ### Requirements
72
- - Python 3.10+
73
-
74
- ...
75
-
76
- ### Configuration & CLI Options
77
-
78
- Below are the supported configuration parameters and CLI flags. Some options can be set via config files, CLI flags, or both. Use `python -m janito --help` for a full list, or `python -m janito --help-config` to see all config keys and their descriptions.
79
-
80
- | Key / Flag | Description | How to set | Default |
81
- |---------------------------|---------------------------------------------------------------------------------------------|-----------------------------------------------------------------|--------------------------------------------|
82
- | `api_key` | API key for a compatible language model service | `--set-api-key`, config file | _None_ (required) |
83
- | `model` | Model name to use for this session | `--model` (session only), `--set-local-config model=...`, or `--set-global-config` | _(example: gpt-4)_ |
84
- | `base_url` | API base URL for your language model service | `--set-local-config base_url=...` or `--set-global-config` | _(example: https://api.your-model.com)_ |
85
- | `role` | Role description for the system prompt | `--role` or config | "software engineer" |
86
- | `system_prompt` | Override the entire system prompt as a raw string | `--system-prompt` or config | _Default prompt_ |
87
- | `system_file` | Use a plain text file as the system prompt (takes precedence over `system_prompt`) | `--system-file` (CLI only) | _None_ |
88
- | `temperature` | Sampling temperature (float, e.g., 0.0 - 2.0) | `--temperature` or config | 0.2 |
89
- | `max_tokens` | Maximum tokens for model response | `--max-tokens` or config | 200000 |
90
- | `max_rounds` | Maximum number of agent rounds per prompt/session | `--max-rounds` or config | 50 |
91
- | `max_tools` | Maximum number of tool calls allowed within a chat session | `--max-tools` or config | _None_ (unlimited) |
92
- | `no_tools` | Disable tool use (no tools passed to agent) | `-n`, `--no-tools` (CLI only) | False |
93
- | `trust` | Trust mode: suppresses run_bash_command output, only shows output file locations | `--trust` (CLI only) | False |
94
- | `template` / `template.*` | Template context dictionary for prompt rendering (nested or flat keys) | Config only | _None_ |
95
-
96
- Other config-related CLI flags:
97
-
98
- - `--set-local-config key=val` Set a local config value
99
- - `--set-global-config key=val` Set a global config value
100
- - `--run-config key=val` Set a runtime (in-memory only) config value (can be repeated)
101
- - `--show-config` Show effective configuration and exit
102
- - `--config-reset-local` Remove the local config file
103
- - `--config-reset-global` Remove the global config file
104
- - `--set-api-key KEY` Set and save the API key globally
105
- - `--help-config` Show all configuration options and exit
106
-
107
- Session & shell options:
108
-
109
- - `--continue-session` Continue from the last saved conversation
110
- - `--web` Launch the Janito web server instead of CLI
111
-
112
- Verbose/debugging flags:
113
-
114
- - `--verbose-http` Enable verbose HTTP logging
115
- - `--verbose-http-raw` Enable raw HTTP wire-level logging
116
- - `--verbose-response` Pretty print the full response object
117
- - `--verbose-tools` Print tool call parameters and results
118
- - `--show-system` Show model, parameters, system prompt, and tool definitions, then exit
119
- - `--version` Show program's version number and exit
120
-
121
-
122
-
123
- ---
124
-
125
- ## 🧩 System Prompt & Role
126
-
127
- Janito operates using a system prompt template that defines its behavior, communication style, and capabilities. By default, Janito assumes the role of a "software engineer"—this means its responses and actions are tailored to the expectations and best practices of professional software engineering.
128
-
129
- - **Role:** You can customize the agent's role (e.g., "data scientist", "DevOps engineer") using the `--role` flag or config. The default is `software engineer`.
130
- - **System Prompt Template:** The system prompt is rendered from a Jinja2 template (see `janito/agent/templates/system_instructions.j2` (now located directly under the agent directory)). This template governs how the agent interprets instructions, interacts with files, and communicates with users.
131
- - **Customization:** Advanced users can override the system prompt with the `--system-prompt` flag (raw string), or point to a custom file using `--system-file`.
132
-
133
- The default template ensures the agent:
134
- - Prioritizes safe, reviewable, and minimal changes
135
- - Asks for clarification when instructions are ambiguous
136
- - Provides concise plans before taking action
137
- - Documents any changes made
138
-
139
- For more details or to customize the prompt, see the template file at `janito/agent/templates/system_instructions.j2`.
140
-
141
- ---
142
-
@@ -1,55 +0,0 @@
1
- janito/__init__.py,sha256=-pa9pj_zJgPDZtE3ena4mjuVS3FEWQWYij1shjLYS80,23
2
- janito/__main__.py,sha256=CBScR30Tm-vuhIJM8o5HXKr0q-smICiwSVyuU68BP8U,78
3
- janito/render_prompt.py,sha256=xCQgYRqMyz9Pzi7096NoZfC4lFiKEHEaXiTYP6ByViY,513
4
- janito/agent/__init__.py,sha256=CByAH5Yk-yH64zo0RU7Z3nsn_7Vmandphqk0JNlpyj8,21
5
- janito/agent/agent.py,sha256=X5swt-SUKnIxrSQaGfhxPk61M-BXREz4n02ynE0dVVU,4245
6
- janito/agent/config.py,sha256=Z-_IeWxJB_1ca5LVR7PtHChZgc5eAsgegyEmVAxr1NY,4472
7
- janito/agent/config_defaults.py,sha256=vSif3tJYZ7pMHaNqH6jGb7EKctfE-Kt8ueD17sC0ESY,395
8
- janito/agent/config_utils.py,sha256=UmvR236wDrMc-aTy9LxVbop6YeoJaaPb1d2DBMlkSRg,254
9
- janito/agent/conversation.py,sha256=vbCL-1LlJjKRN6q3CjfSe4ENGplP-YQKsAEA1uX3RWU,6184
10
- janito/agent/queued_tool_handler.py,sha256=THPymKXnpoXfN49EhW5b4hrwpWZZup73JKFDJ_U03tI,540
11
- janito/agent/runtime_config.py,sha256=H6bnRVYR0zC-WhmLpBU-IXikXWKcIiBQqFnc4uGooj4,908
12
- janito/agent/tool_handler.py,sha256=h-pxG1lhyIJohZmvwHSsknBSonrJQYGGzBL6Tobgmrg,7414
13
- janito/agent/templates/system_instructions.j2,sha256=BtwMcibxnwZmQhGN7p_VGhhyAPzCfqksnW4B-PTWa-8,1532
14
- janito/agent/tools/__init__.py,sha256=Vv1oWF6Ur-Tkm3p0KCz5HD7wwar9rUHtY596NGPnn2s,378
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
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
25
- janito/agent/tools/replace_text_in_file.py,sha256=eO7YumsT8Eq3_SOgl5DW_k9vhXO7egyMaiB6ZgtiHRU,3894
26
- janito/agent/tools/rich_live.py,sha256=cuZ3-ZxpuHxR1TvIcp0bi9F3QM1M6Ms0XiOMd8If8gU,1161
27
- janito/agent/tools/rich_utils.py,sha256=Lc4phM4DUG-eiiub2PFThc6pBk5aOo_6f09JPdZIdsk,894
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
30
- janito/agent/tools/tool_base.py,sha256=nS2FXSw3YY6gJiKh-l1m1udnHT7F3yKwGpGHJHfERbY,836
31
- janito/agent/tools/utils.py,sha256=cKZ2qxK-S01mzBmCXYWwQ9zOyT994SaoRZYbD1o57Dk,1113
32
- janito/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- janito/cli/_print_config.py,sha256=vMMlCY-hJPsLHUxx9TJuOY9iyYVBH8C4nVACCwY4l5U,3294
34
- janito/cli/_utils.py,sha256=Q_OCFZmbr78qW4hSSUUhjondVc0ao7-iUHE7Ig8IP1g,289
35
- janito/cli/arg_parser.py,sha256=4dSxHk02VD2_-utR5XCDt6Xs7tsye2HeQmTbaJiWFME,3724
36
- janito/cli/config_commands.py,sha256=kYZ_SlHkZRlg-hLAdYKj50qnJgPCZUbW7zU4FykE7XQ,8098
37
- janito/cli/logging_setup.py,sha256=dWQ0wFf4YuF5lxZlhpN6lis7G56LeFYUwQdh9nA5NmA,1141
38
- janito/cli/main.py,sha256=ONmn_lIPu8_Rd57j3YfWEx46fWj8gAkONPLdctABwy0,1333
39
- janito/cli/runner.py,sha256=64BErYxTvJjzFPKpbQvOoq6ARiEbPp03ZGFZBVogkgg,5043
40
- janito/cli_chat_shell/__init__.py,sha256=PDGl7xK_vgkROoXvUxGZqVQFfuL9U4TjdexpP8E2JKg,41
41
- janito/cli_chat_shell/chat_loop.py,sha256=AcryIgXb36g6214XKj75Xx4VxOYG-i8_IC_ROZyOLdk,5516
42
- janito/cli_chat_shell/commands.py,sha256=ytt_5dym2sKOIlTjwAmfMg2jQVBlenDbPNwKJasPsDg,7245
43
- janito/cli_chat_shell/config_shell.py,sha256=WlOxt7YOTIJluD3hURXbtOSodPHPnCwcO0LaH8_XXJE,3301
44
- janito/cli_chat_shell/load_prompt.py,sha256=B7C_IhMk3n1XBQcfOwFVDnjrj1278JL3kV4UtkeeZx8,604
45
- janito/cli_chat_shell/session_manager.py,sha256=PdqmFw4jZaCtQpazjgkKk_yhleZrzZOz_QqFeIf9Km4,1818
46
- janito/cli_chat_shell/ui.py,sha256=9IngH8HFherjatfa9Eu37jb4b2gOP0lsgcUhbnQKCZA,5557
47
- janito/web/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
- janito/web/__main__.py,sha256=oPXNF332aCeI7aUWr7_8M57oOKugw422VrEubxFp0P4,354
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,,
File without changes