janito 0.10.1__py3-none-any.whl → 0.12.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 (49) hide show
  1. janito/__init__.py +1 -1
  2. janito/__main__.py +3 -147
  3. janito/callbacks.py +13 -109
  4. janito/cli/__init__.py +6 -0
  5. janito/cli/agent.py +287 -0
  6. janito/cli/app.py +86 -0
  7. janito/cli/commands.py +329 -0
  8. janito/cli/output.py +29 -0
  9. janito/cli/utils.py +22 -0
  10. janito/config.py +338 -63
  11. janito/data/instructions_template.txt +27 -0
  12. janito/token_report.py +124 -43
  13. janito/tools/__init__.py +29 -1
  14. janito/tools/bash/bash.py +82 -0
  15. janito/tools/bash/unix_persistent_bash.py +182 -0
  16. janito/tools/bash/win_persistent_bash.py +306 -0
  17. janito/tools/decorators.py +90 -84
  18. janito/tools/delete_file.py +65 -44
  19. janito/tools/fetch_webpage/__init__.py +34 -0
  20. janito/tools/fetch_webpage/chunking.py +76 -0
  21. janito/tools/fetch_webpage/core.py +155 -0
  22. janito/tools/fetch_webpage/extractors.py +276 -0
  23. janito/tools/fetch_webpage/news.py +137 -0
  24. janito/tools/fetch_webpage/utils.py +108 -0
  25. janito/tools/find_files.py +108 -42
  26. janito/tools/move_file.py +72 -0
  27. janito/tools/prompt_user.py +57 -0
  28. janito/tools/replace_file.py +63 -0
  29. janito/tools/rich_console.py +139 -0
  30. janito/tools/search_text.py +33 -21
  31. janito/tools/str_replace_editor/editor.py +55 -43
  32. janito/tools/str_replace_editor/handlers/__init__.py +16 -0
  33. janito/tools/str_replace_editor/handlers/create.py +60 -0
  34. janito/tools/str_replace_editor/handlers/insert.py +100 -0
  35. janito/tools/str_replace_editor/handlers/str_replace.py +92 -0
  36. janito/tools/str_replace_editor/handlers/undo.py +64 -0
  37. janito/tools/str_replace_editor/handlers/view.py +153 -0
  38. janito/tools/str_replace_editor/utils.py +7 -62
  39. janito/tools/usage_tracker.py +136 -0
  40. janito-0.12.0.dist-info/METADATA +203 -0
  41. janito-0.12.0.dist-info/RECORD +47 -0
  42. janito/cli.py +0 -202
  43. janito/data/instructions.txt +0 -4
  44. janito/tools/str_replace_editor/handlers.py +0 -338
  45. janito-0.10.1.dist-info/METADATA +0 -86
  46. janito-0.10.1.dist-info/RECORD +0 -23
  47. {janito-0.10.1.dist-info → janito-0.12.0.dist-info}/WHEEL +0 -0
  48. {janito-0.10.1.dist-info → janito-0.12.0.dist-info}/entry_points.txt +0 -0
  49. {janito-0.10.1.dist-info → janito-0.12.0.dist-info}/licenses/LICENSE +0 -0
@@ -2,19 +2,20 @@
2
2
  Utility functions for the str_replace_editor package.
3
3
  """
4
4
  import os
5
- import pathlib
6
- from typing import Dict, Any, Optional
7
5
  from janito.config import get_config
8
6
 
9
7
  def normalize_path(path: str) -> str:
10
8
  """
11
9
  Normalizes a path relative to the workspace directory.
12
10
 
11
+ For internal operations, converts relative paths to absolute paths
12
+ based on the workspace directory.
13
+
13
14
  Args:
14
15
  path: The original path
15
16
 
16
17
  Returns:
17
- The normalized path relative to the workspace directory
18
+ The normalized absolute path
18
19
  """
19
20
  # If path is absolute, return it as is
20
21
  if os.path.isabs(path):
@@ -24,65 +25,9 @@ def normalize_path(path: str) -> str:
24
25
  if path.startswith('./'):
25
26
  path = path[2:]
26
27
 
27
- # For relative paths, we should keep them relative
28
- # Only prepend workspace_dir if we need to resolve the path
29
- # against the workspace directory
30
- return path
31
-
32
- def backup_file(file_path: str, content: str) -> None:
33
- """
34
- Backup a file before editing it.
35
-
36
- Args:
37
- file_path: Path to the file being edited
38
- content: Current content of the file
39
- """
40
- # Get workspace directory
41
- workspace_dir = get_config().workspace_dir
42
-
43
- # Create .janito/undo directory in the workspace if it doesn't exist
44
- backup_dir = pathlib.Path(workspace_dir) / ".janito" / "undo"
45
- backup_dir.mkdir(parents=True, exist_ok=True)
46
-
47
- # Store the original path
48
- path_file = backup_dir / "path"
49
- with open(path_file, 'w', encoding='utf-8') as f:
50
- f.write(file_path)
51
-
52
- # Store the original content
53
- content_file = backup_dir / "content"
54
- with open(content_file, 'w', encoding='utf-8') as f:
55
- f.write(content)
56
-
57
- def get_backup_info() -> Optional[Dict[str, str]]:
58
- """
59
- Get the backup information for the last edited file.
60
-
61
- Returns:
62
- Dictionary with 'path' and 'content' keys, or None if no backup exists
63
- """
64
- # Get workspace directory
28
+ # Convert relative paths to absolute paths for internal operations
65
29
  workspace_dir = get_config().workspace_dir
66
-
67
- path_file = pathlib.Path(workspace_dir) / ".janito" / "undo" / "path"
68
- content_file = pathlib.Path(workspace_dir) / ".janito" / "undo" / "content"
69
-
70
- if not path_file.exists() or not content_file.exists():
71
- return None
72
-
73
- try:
74
- with open(path_file, 'r', encoding='utf-8') as f:
75
- path = f.read()
76
-
77
- with open(content_file, 'r', encoding='utf-8') as f:
78
- content = f.read()
79
-
80
- return {
81
- 'path': path,
82
- 'content': content
83
- }
84
- except Exception:
85
- return None
30
+ return os.path.normpath(os.path.join(workspace_dir, path))
86
31
 
87
- # Store file history for undo operations (in-memory backup, will be deprecated)
32
+ # Store file history for undo operations (in-memory backup)
88
33
  _file_history = {}
@@ -0,0 +1,136 @@
1
+ """
2
+ Tool usage tracking module for Janito.
3
+
4
+ This module provides functionality to track tool usage statistics
5
+ such as files modified, created, deleted, and lines replaced.
6
+ """
7
+
8
+ from functools import wraps
9
+ from typing import Dict, Any, Callable
10
+ import threading
11
+
12
+ # Global tracker instance
13
+ _tracker = None
14
+ _tracker_lock = threading.Lock()
15
+
16
+ class ToolUsageTracker:
17
+ """Tracks usage statistics for Janito tools."""
18
+
19
+ def __init__(self):
20
+ self.reset()
21
+
22
+ def reset(self):
23
+ """Reset all counters to zero."""
24
+ self.files_modified = 0
25
+ self.files_created = 0
26
+ self.files_deleted = 0
27
+ self.files_moved = 0
28
+ self.lines_replaced = 0
29
+ self.lines_delta = 0 # Track the net change in number of lines
30
+ self.web_requests = 0
31
+ self.bash_commands = 0
32
+ self.user_prompts = 0
33
+ self.search_operations = 0
34
+ self.file_views = 0
35
+ self.partial_file_views = 0
36
+
37
+ def increment(self, counter_name: str, value: int = 1):
38
+ """Increment a specific counter by the given value."""
39
+ if hasattr(self, counter_name):
40
+ setattr(self, counter_name, getattr(self, counter_name) + value)
41
+
42
+ def get_stats(self) -> Dict[str, int]:
43
+ """Get all non-zero statistics as a dictionary."""
44
+ stats = {}
45
+ for attr_name in dir(self):
46
+ if not attr_name.startswith('_') and not callable(getattr(self, attr_name)):
47
+ value = getattr(self, attr_name)
48
+ if value > 0:
49
+ # Convert attribute_name to "Attribute Name" format
50
+ display_name = ' '.join(word.capitalize() for word in attr_name.split('_'))
51
+ stats[display_name] = value
52
+ return stats
53
+
54
+
55
+ def get_tracker() -> ToolUsageTracker:
56
+ """Get the global tracker instance."""
57
+ global _tracker
58
+ with _tracker_lock:
59
+ if _tracker is None:
60
+ _tracker = ToolUsageTracker()
61
+ return _tracker
62
+
63
+
64
+ def reset_tracker():
65
+ """Reset the global tracker."""
66
+ get_tracker().reset()
67
+
68
+
69
+ def track_usage(counter_name: str, increment_value: int = 1):
70
+ """
71
+ Decorator to track tool usage.
72
+
73
+ Args:
74
+ counter_name: The name of the counter to increment
75
+ increment_value: Value to increment the counter by (default: 1)
76
+ """
77
+ def decorator(func):
78
+ @wraps(func)
79
+ def wrapper(*args, **kwargs):
80
+ result = func(*args, **kwargs)
81
+ # Only track successful operations
82
+ if isinstance(result, tuple) and len(result) >= 2:
83
+ message, is_error = result[0], result[1]
84
+ if not is_error:
85
+ get_tracker().increment(counter_name, increment_value)
86
+ return result
87
+ return wrapper
88
+ return decorator
89
+
90
+
91
+ def count_lines_in_string(old_str: str, new_str: str) -> tuple[int, int]:
92
+ """
93
+ Count the number of lines that differ between old_str and new_str.
94
+
95
+ Args:
96
+ old_str: Original string
97
+ new_str: New string
98
+
99
+ Returns:
100
+ Tuple of (number of lines that differ, line delta)
101
+ """
102
+ old_lines = old_str.splitlines()
103
+ new_lines = new_str.splitlines()
104
+
105
+ # Calculate the line delta (positive for added lines, negative for removed lines)
106
+ line_delta = len(new_lines) - len(old_lines)
107
+
108
+ # Simple approach: count the total number of lines changed
109
+ # For tracking purposes, we'll use the max to ensure we don't undercount
110
+ return max(len(old_lines), len(new_lines)), line_delta
111
+
112
+
113
+ def print_usage_stats():
114
+ """Print the current usage statistics if any values are non-zero."""
115
+ stats = get_tracker().get_stats()
116
+ if stats:
117
+ from rich.console import Console
118
+
119
+ console = Console()
120
+
121
+ # Create a single-line summary of tool usage
122
+ summary_parts = []
123
+ for name, value in stats.items():
124
+ # Format lines delta with a sign
125
+ if name == "Lines Delta":
126
+ sign = "+" if value > 0 else "" if value == 0 else "-"
127
+ formatted_value = f"{sign}{abs(value)}"
128
+ summary_parts.append(f"{name}: {formatted_value}")
129
+ else:
130
+ summary_parts.append(f"{name}: {value}")
131
+
132
+ summary = " | ".join(summary_parts)
133
+
134
+ # Display with a rule similar to token usage
135
+ console.rule("[blue]Tool Usage[/blue]")
136
+ console.print(f"[blue]{summary}[/blue]", justify="center")
@@ -0,0 +1,203 @@
1
+ Metadata-Version: 2.4
2
+ Name: janito
3
+ Version: 0.12.0
4
+ Summary: Janito CLI tool
5
+ Project-URL: Homepage, https://github.com/joaompinto/janito
6
+ Author-email: João Pinto <lamego.pinto@gmail.com>
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.8
9
+ Requires-Dist: anthropic>=0.5.0
10
+ Requires-Dist: beautifulsoup4>=4.13.0
11
+ Requires-Dist: claudine>=0.1.0
12
+ Requires-Dist: jinja2>=3.0.0
13
+ Requires-Dist: lxml-html-clean>=0.4.1
14
+ Requires-Dist: newspaper3k>=0.2.8
15
+ Requires-Dist: requests>=2.32.0
16
+ Requires-Dist: rich>=13.0.0
17
+ Requires-Dist: trafilatura>=1.6.0
18
+ Requires-Dist: typer>=0.9.0
19
+ Description-Content-Type: text/markdown
20
+
21
+ # 🤖 Janito
22
+
23
+ Janito is a powerful AI-assisted command-line interface (CLI) tool built with Python, leveraging Anthropic's Claude for intelligent code and file management.
24
+
25
+ [![GitHub Repository](https://img.shields.io/badge/GitHub-Repository-blue?logo=github)](https://github.com/joaompinto/janito)
26
+
27
+ ## ✨ Features
28
+
29
+ - 🧠 Intelligent AI assistant powered by Claude
30
+ - 📁 File management capabilities with real-time output
31
+ - 🔍 Smart code search and editing
32
+ - 💻 Interactive terminal interface with rich formatting
33
+ - 📊 Detailed token usage tracking and cost reporting with cache savings analysis
34
+ - 🛑 Token and tool usage reporting even when interrupted with Ctrl+C
35
+ - 🌐 Web page fetching with content extraction capabilities
36
+ - 🔄 Parameter profiles for optimizing Claude's behavior for different tasks
37
+ - 📋 Line delta tracking to monitor net changes in files
38
+
39
+ ## 🛠️ System Requirements
40
+
41
+ - **Python 3.8+** - Janito requires Python 3.8 or higher
42
+ - **Operating Systems**:
43
+ - Linux/macOS: Native support
44
+ - Windows: Requires Git Bash for proper operation of CLI tools
45
+ - **Anthropic API Key** - Required for Claude AI integration
46
+
47
+ ## 🛠️ Installation
48
+
49
+ ```bash
50
+ # Install directly from PyPI
51
+ pip install janito
52
+ ```
53
+
54
+ ### Setting up your API Key
55
+
56
+ Janito requires an Anthropic API key to function. You can:
57
+ 1. Set the API key: `janito --set-api-key your_api_key`
58
+
59
+ For development or installation from source, please see [README_DEV.md](README_DEV.md).
60
+
61
+ ## 🚀 Usage Tutorial
62
+
63
+ After installation, you can start using Janito right away. Let's walk through a simple tutorial:
64
+
65
+ ### Getting Started
66
+
67
+ First, let's check that everything is working:
68
+
69
+ ```bash
70
+ # Get help and see available commands
71
+ janito --help
72
+ ```
73
+
74
+ ### Tutorial: Creating a Simple Project
75
+
76
+ Let's create a simple HTML project with Janito's help:
77
+
78
+ After installing Janito, using your prefered editor and/or terminal, go to a new empty folder.
79
+
80
+ Use the janito command to create a new project.
81
+
82
+ ```bash
83
+ # Step 1: Create a new project structure
84
+ janito "Create a simple HTML page with a calculator and 3 columns with text for the 3 main activities of the Kazakh culture"
85
+ ```
86
+ Browse the resulting html page.
87
+
88
+ ### Tutorial: Adding Features
89
+
90
+ Now, let's enhance our example
91
+
92
+ ```bash
93
+ # Step 2: Add multiplication and division features
94
+ janito "Add some svg icons and remove the calculator"
95
+
96
+ ```
97
+
98
+ Refresh the page
99
+
100
+ ### Exploring More Features
101
+
102
+ Janito offers many more capabilities:
103
+
104
+ ```bash
105
+ # Show detailed token usage and cost information
106
+ janito --show-tokens "Explain what is in the project"
107
+
108
+ # Use a specific parameter profile for creative tasks
109
+ janito --profile creative "Write a fun description for our project"
110
+
111
+ # Continue previous conversation
112
+ janito --continue "Plese add one more line"
113
+
114
+ # Show current configuration and available profiles
115
+ janito --show-config
116
+
117
+ # You can press Ctrl+C at any time to interrupt a query
118
+ # Janito will still display token and tool usage information
119
+ ```
120
+
121
+ ## 🔧 Available Tools
122
+
123
+ Janito comes with several built-in tools:
124
+ - 📄 `str_replace_editor` - View, create, and edit files
125
+ - 🔎 `find_files` - Find files matching patterns
126
+ - 🗑️ `delete_file` - Delete files
127
+ - 🔍 `search_text` - Search for text patterns in files
128
+ - 🌐 `fetch_webpage` - Fetch and extract content from web pages
129
+ - 📋 `move_file` - Move files from one location to another
130
+ - 💻 `bash` - Execute bash commands with real-time output display
131
+
132
+ ## 📊 Usage Tracking
133
+
134
+ Janito includes a comprehensive token usage tracking system that helps you monitor API costs:
135
+
136
+ - **Basic tracking**: By default, Janito displays a summary of token usage and cost after each query
137
+ - **Detailed reporting**: Use the `--show-tokens` or `-t` flag to see detailed breakdowns including:
138
+ - Input and output token counts
139
+ - Per-tool token usage statistics
140
+ - Precise cost calculations
141
+ - Cache performance metrics with savings analysis
142
+ - Line delta tracking for file modifications
143
+
144
+ ```bash
145
+ # Show detailed token usage and cost information
146
+ janito --show-tokens "Write a Python function to sort a list"
147
+
148
+ # Basic usage (shows simplified token usage summary)
149
+ janito "Explain Docker containers"
150
+ ```
151
+
152
+ The usage tracker automatically calculates cache savings, showing you how much you're saving by reusing previous responses.
153
+
154
+ ## 📋 Parameter Profiles
155
+
156
+ Janito offers predefined parameter profiles to optimize Claude's behavior for different tasks:
157
+
158
+ - **precise**: Factual answers, documentation, structured data (temperature: 0.2)
159
+ - **balanced**: Professional writing, summarization, everyday tasks (temperature: 0.5)
160
+ - **conversational**: Natural dialogue, educational content (temperature: 0.7)
161
+ - **creative**: Storytelling, brainstorming, marketing copy (temperature: 0.9)
162
+ - **technical**: Code generation, debugging, technical problem-solving (temperature: 0.3)
163
+
164
+ ```bash
165
+ # Use a specific profile
166
+ janito --profile creative "Write a poem about coding"
167
+
168
+ # View available profiles
169
+ janito --show-config
170
+ ```
171
+
172
+ ## ⚙️ Dependencies
173
+
174
+ Janito automatically installs the following dependencies:
175
+ - typer (>=0.9.0) - For CLI interface
176
+ - rich (>=13.0.0) - For rich text formatting
177
+ - claudine - For Claude AI integration
178
+ - Additional packages for file handling and web content extraction
179
+
180
+ ## 🔑 API Key Configuration
181
+
182
+ You can configure your Anthropic API key in several ways:
183
+
184
+ ```bash
185
+ # Option 1: Set as environment variable
186
+ export ANTHROPIC_API_KEY=your_api_key
187
+
188
+ # Option 2: Configure globally within Janito
189
+ janito --set-api-key your_api_key
190
+
191
+ # Option 3: Let Janito prompt you on first use
192
+ janito "Hello, I'm new to Janito!"
193
+ ```
194
+
195
+ Your API key is securely stored and used for all future sessions.
196
+
197
+ ## 💻 Development
198
+
199
+ For development instructions, please refer to [README_DEV.md](README_DEV.md).
200
+
201
+ ## 📜 License
202
+
203
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,47 @@
1
+ janito/__init__.py,sha256=UhMcaPInS2sBvYxOLldeLu7sKy-ZZxndtrf6NPqQBgI,53
2
+ janito/__main__.py,sha256=Oy-Nc1tZkpyvTKuq1R8oHSuJTkvptN6H93kIHBu7DKY,107
3
+ janito/callbacks.py,sha256=E1FPXYHZUgiEGMabYuf999PSf_Su4ByHOWlc1-hMqWE,915
4
+ janito/config.py,sha256=haIErp8tVL6e_5h4fsgLqFib2aCAZZ3sIXa8wStn_yo,12424
5
+ janito/test_file.py,sha256=c6GWGdTYG3z-Y5XBao9Tmhmq3G-v0L37OfwLgBo8zIU,126
6
+ janito/token_report.py,sha256=Mks7o2yTxPChgQyBJNoQ5eMmrhSgEM4LKCKi2tHJbVo,9580
7
+ janito/cli/__init__.py,sha256=dVi9l3E86YyukjxQ-XSUnMZkghnNasXex-X5XAOBiwk,85
8
+ janito/cli/agent.py,sha256=AYJhSqPbz1Ywz_RBzHxfXIK6x-aZrqA8-C2QzmxZ3J8,10533
9
+ janito/cli/app.py,sha256=RghsHSmvnECGWzoAeQOJdxHTZM_Xcw6Y4jgbJ5I6-5M,4131
10
+ janito/cli/commands.py,sha256=c1EHJ_VZR_3aA3zRvCLaBn9yfdj5emQpTI0Z_bXcIyc,12664
11
+ janito/cli/output.py,sha256=mo3hUokhrD4SWexUjCbLGGQeCDUf0369DA_i9BW7HjU,933
12
+ janito/cli/utils.py,sha256=gO4NtCNwtEzYDsQesrFlqB5FtYuw87yGwo4iG3nINgw,661
13
+ janito/data/instructions_template.txt,sha256=oXmjVEajwLuTjcyXyD123CGSjNG1QLbfzbw9iEq-w5w,1411
14
+ janito/tools/__init__.py,sha256=hio75FRkxLSQB13We-SCCM7Qa9lMqWCfWhEonHlTr8M,1405
15
+ janito/tools/decorators.py,sha256=Tp48n5y4LKsjyV3HeOA9wk2dV413RrEG-23kRyQVlKs,2522
16
+ janito/tools/delete_file.py,sha256=UrZ5q59SIxWfuJcqgol6yPBqL-RhO9lFCF4MqAc6o00,2252
17
+ janito/tools/find_files.py,sha256=c_N9ETcRPprQeuZYanwFnl-9E05ZqUYhNVoCRS5uqQg,8300
18
+ janito/tools/move_file.py,sha256=FCs1ghalfHlXmcbAA_IlLcUll9hTOU1MMFGrTWopXvM,2741
19
+ janito/tools/prompt_user.py,sha256=OnTiWVBCbL_2MYu7oThlKr8X_pnYdG-dzxXSOgJF41c,1942
20
+ janito/tools/replace_file.py,sha256=i4GoLtS14eKSU5lYI18mJ96S0_ekeHMwlQfazg-fxrM,2296
21
+ janito/tools/rich_console.py,sha256=VyLStA7fCgMGp9KZ0TYHAC3FOOAWKKHx1XTWWWF2ISI,4560
22
+ janito/tools/search_text.py,sha256=hZLgKlF_cC5JRQ2XsussndSZMmptwr8d0tTKCyCXFwg,9755
23
+ janito/tools/usage_tracker.py,sha256=IE7GVBDYsX2EDLjsVaVqTeAnT2SAYfcOJvBaH__wHdU,4613
24
+ janito/tools/bash/bash.py,sha256=gOYhp2CexuEjSSpHGhVQLr-Ooc67Etl7Br1TbRtY6vc,3577
25
+ janito/tools/bash/unix_persistent_bash.py,sha256=tFFhbG9rk1KcONmG0j6SZHrqYxCXELhzobRSTEHPFm0,6868
26
+ janito/tools/bash/win_persistent_bash.py,sha256=mMgAdRi7jlznq7ssNmgiSMEqzEI-rIV0kgYpndcum6U,12758
27
+ janito/tools/fetch_webpage/__init__.py,sha256=0RG0ev-yrfo8gPzt-36WMpVdY2qtMhk2Z-mVpq-7m1o,1076
28
+ janito/tools/fetch_webpage/chunking.py,sha256=mMtrZeirZ_GnKOOzeG8BijLVpSUI0-TA5Ioqi2HKb1A,2971
29
+ janito/tools/fetch_webpage/core.py,sha256=3XDvYnC_UbQUNumwWw32hfJhjJUEaPzzoF2yhxhwxos,7764
30
+ janito/tools/fetch_webpage/extractors.py,sha256=-jrLDRWfWyF2SNOATdRWrqETqnnDLbe2JUWtuyHKFOU,12043
31
+ janito/tools/fetch_webpage/news.py,sha256=Hp0uNTnRzTa-4hyegQbHSmLeSbkiSpx4cP2oP_hKLEQ,5378
32
+ janito/tools/fetch_webpage/utils.py,sha256=mkfwefD7U9HOktIwo1eP63v7dpVY-q06COUjaqnTT5M,3412
33
+ janito/tools/str_replace_editor/__init__.py,sha256=kYmscmQgft3Jzt3oCNz7k2FiRbJvku6OFDDC3Q_zoAA,144
34
+ janito/tools/str_replace_editor/editor.py,sha256=BckYfiMRUYDfDrbu871qMt2AfZexth_02QhwYYOd53g,2489
35
+ janito/tools/str_replace_editor/utils.py,sha256=akiPqCHjky_RwL9OitHJJ7uQ-3fNaA8wt_K_YO1EP6I,954
36
+ janito/tools/str_replace_editor/handlers/__init__.py,sha256=RP6JCeDRIL4R-lTpGowIoOAi64gg6VxZvJGp8Q2UOVU,373
37
+ janito/tools/str_replace_editor/handlers/create.py,sha256=s8RQE04kDAL7OLZA8WxJkDqTmJlGmCNiit4tIHnmNMo,2470
38
+ janito/tools/str_replace_editor/handlers/insert.py,sha256=eKHodm2ozKUlRMxWMLAsu9ca6unUo1jfXWwHSld-pSU,4061
39
+ janito/tools/str_replace_editor/handlers/str_replace.py,sha256=quHQ1vOqvXCPaC14W5iub01kKB4XNMqwh1odnXnhhxY,4459
40
+ janito/tools/str_replace_editor/handlers/undo.py,sha256=3OIdAWkpXC2iDe94_sfx_WxEFh3a1cRzoP0NtPXq1Ks,2491
41
+ janito/tools/str_replace_editor/handlers/view.py,sha256=ZWcx7r5VwxWG3ImQxK2lzONL9xlqctM-hy2kMF-huT0,6616
42
+ janito/data/instructions_template.txt,sha256=oXmjVEajwLuTjcyXyD123CGSjNG1QLbfzbw9iEq-w5w,1411
43
+ janito-0.12.0.dist-info/METADATA,sha256=oR3nvTukvj3uPVcZ2LbAA4lx46W08elLhWphDWXpAAs,6458
44
+ janito-0.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
45
+ janito-0.12.0.dist-info/entry_points.txt,sha256=JMbF_1jg-xQddidpAYkzjOKdw70fy_ymJfcmerY2wIY,47
46
+ janito-0.12.0.dist-info/licenses/LICENSE,sha256=6-H8LXExbBIAuT4cyiE-Qy8Bad1K4pagQRVTWr6wkhk,1096
47
+ janito-0.12.0.dist-info/RECORD,,
janito/cli.py DELETED
@@ -1,202 +0,0 @@
1
- """
2
- CLI functionality for the janito tool.
3
- """
4
-
5
- import os
6
- import sys
7
- from pathlib import Path
8
- from typing import Optional
9
- import typer
10
- from rich.console import Console
11
- from rich.markdown import Markdown
12
- from rich import print as rprint
13
- import claudine
14
- from claudine.exceptions import MaxTokensExceededException, MaxRoundsExceededException
15
-
16
- from janito.config import get_config
17
- from janito.tools import find_files
18
- from janito.tools.str_replace_editor.editor import str_replace_editor
19
- from janito.tools.delete_file import delete_file
20
- from janito.tools.search_text import search_text
21
- from janito.callbacks import pre_tool_callback, post_tool_callback
22
-
23
- app = typer.Typer(help="Janito CLI tool")
24
-
25
- @app.command()
26
- def hello(name: str = typer.Argument("World", help="Name to greet")):
27
- """
28
- Say hello to someone.
29
- """
30
- rprint(f"[bold green]Hello {name}[/bold green]")
31
-
32
-
33
-
34
- def debug_tokens(agent):
35
- """
36
- Display detailed token usage and pricing information.
37
- """
38
- from claudine.token_tracking import MODEL_PRICING, DEFAULT_MODEL
39
-
40
- console = Console()
41
- usage = agent.get_token_usage()
42
- text_usage = usage.text_usage
43
- tools_usage = usage.tools_usage
44
- total_usage = usage.total_usage
45
-
46
- # Get the pricing model
47
- pricing = MODEL_PRICING.get(DEFAULT_MODEL)
48
-
49
- # Calculate costs manually
50
- text_input_cost = pricing.input_tokens.calculate_cost(text_usage.input_tokens)
51
- text_output_cost = pricing.output_tokens.calculate_cost(text_usage.output_tokens)
52
- tools_input_cost = pricing.input_tokens.calculate_cost(tools_usage.input_tokens)
53
- tools_output_cost = pricing.output_tokens.calculate_cost(tools_usage.output_tokens)
54
-
55
- # Format costs
56
- format_cost = lambda cost: f"{cost * 100:.2f}¢" if cost < 1.0 else f"${cost:.6f}"
57
-
58
- console.print("\n[bold blue]Detailed Token Usage:[/bold blue]")
59
- console.print(f"Text Input tokens: {text_usage.input_tokens}")
60
- console.print(f"Text Output tokens: {text_usage.output_tokens}")
61
- console.print(f"Text Total tokens: {text_usage.input_tokens + text_usage.output_tokens}")
62
- console.print(f"Tool Input tokens: {tools_usage.input_tokens}")
63
- console.print(f"Tool Output tokens: {tools_usage.output_tokens}")
64
- console.print(f"Tool Total tokens: {tools_usage.input_tokens + tools_usage.output_tokens}")
65
- console.print(f"Total tokens: {total_usage.input_tokens + total_usage.output_tokens}")
66
-
67
- console.print("\n[bold blue]Pricing Information:[/bold blue]")
68
- console.print(f"Input pricing: ${pricing.input_tokens.cost_per_million_tokens}/million tokens")
69
- console.print(f"Output pricing: ${pricing.output_tokens.cost_per_million_tokens}/million tokens")
70
- console.print(f"Text Input cost: {format_cost(text_input_cost)}")
71
- console.print(f"Text Output cost: {format_cost(text_output_cost)}")
72
- console.print(f"Text Total cost: {format_cost(text_input_cost + text_output_cost)}")
73
- console.print(f"Tool Input cost: {format_cost(tools_input_cost)}")
74
- console.print(f"Tool Output cost: {format_cost(tools_output_cost)}")
75
- console.print(f"Tool Total cost: {format_cost(tools_input_cost + tools_output_cost)}")
76
- console.print(f"Total cost: {format_cost(text_input_cost + text_output_cost + tools_input_cost + tools_output_cost)}")
77
-
78
- # Display per-tool breakdown if available
79
- if usage.by_tool:
80
- console.print("\n[bold blue]Per-Tool Breakdown:[/bold blue]")
81
- for tool_name, tool_usage in usage.by_tool.items():
82
- tool_input_cost = pricing.input_tokens.calculate_cost(tool_usage.input_tokens)
83
- tool_output_cost = pricing.output_tokens.calculate_cost(tool_usage.output_tokens)
84
- console.print(f" Tool: {tool_name}")
85
- console.print(f" Input tokens: {tool_usage.input_tokens}")
86
- console.print(f" Output tokens: {tool_usage.output_tokens}")
87
- console.print(f" Total tokens: {tool_usage.input_tokens + tool_usage.output_tokens}")
88
- console.print(f" Total cost: {format_cost(tool_input_cost + tool_output_cost)}")
89
-
90
- def process_query(query: str, debug: bool, verbose: bool):
91
- """
92
- Process a query using the claudine agent.
93
- """
94
- console = Console()
95
-
96
- # Get API key from environment variable or ask the user
97
- api_key = os.environ.get("ANTHROPIC_API_KEY")
98
- if not api_key:
99
- console.print("[bold yellow]Warning:[/bold yellow] ANTHROPIC_API_KEY environment variable not set.")
100
- console.print("Please set it or provide your API key now:")
101
- api_key = typer.prompt("Anthropic API Key", hide_input=True)
102
-
103
- # Load instructions from file
104
- import importlib.resources as pkg_resources
105
- try:
106
- # For Python 3.9+
107
- try:
108
- from importlib.resources import files
109
- instructions = files('janito.data').joinpath('instructions.txt').read_text()
110
- # Fallback for older Python versions
111
- except (ImportError, AttributeError):
112
- instructions = pkg_resources.read_text('janito.data', 'instructions.txt')
113
- instructions = instructions.strip()
114
- except Exception as e:
115
- console.print(f"[bold yellow]Warning:[/bold yellow] Could not load instructions file: {str(e)}")
116
- console.print("[dim]Using default instructions instead.[/dim]")
117
- instructions = "You are a helpful AI assistant. Answer the user's questions to the best of your ability."
118
-
119
- # Initialize the agent with the tools
120
- agent = claudine.Agent(
121
- api_key=api_key,
122
- tools=[
123
- delete_file,
124
- find_files,
125
- search_text
126
- ],
127
- text_editor_tool=str_replace_editor,
128
- tool_callbacks=(pre_tool_callback, post_tool_callback),
129
- max_tokens=4096,
130
- temperature=0.7,
131
- instructions=instructions,
132
- debug_mode=debug # Enable debug mode
133
- )
134
-
135
- # Process the query
136
- console.print(f"[bold blue]Query:[/bold blue] {query}")
137
- console.print("[bold blue]Generating response...[/bold blue]")
138
-
139
- try:
140
- response = agent.process_prompt(query)
141
-
142
- console.print("\n[bold magenta]Janito:[/bold magenta] ", end="")
143
- # Use rich's enhanced Markdown rendering for the response
144
- console.print(Markdown(response, code_theme="monokai"))
145
-
146
- except MaxTokensExceededException as e:
147
- # Display the partial response if available
148
- if e.response_text:
149
- console.print("\n[bold magenta]Janito:[/bold magenta] ", end="")
150
- console.print(Markdown(e.response_text, code_theme="monokai"))
151
-
152
- console.print("\n[bold red]Error:[/bold red] Response was truncated because it reached the maximum token limit.")
153
- console.print("[dim]Consider increasing the max_tokens parameter or simplifying your query.[/dim]")
154
-
155
- except MaxRoundsExceededException as e:
156
- # Display the final response if available
157
- if e.response_text:
158
- console.print("\n[bold magenta]Janito:[/bold magenta] ", end="")
159
- console.print(Markdown(e.response_text, code_theme="monokai"))
160
-
161
- console.print(f"\n[bold red]Error:[/bold red] Maximum number of tool execution rounds ({e.rounds}) reached. Some tasks may be incomplete.")
162
- console.print("[dim]Consider increasing the max_rounds parameter or breaking down your task into smaller steps.[/dim]")
163
-
164
- # Show token usage
165
- usage = agent.get_token_usage()
166
- text_usage = usage.text_usage
167
- tools_usage = usage.tools_usage
168
-
169
- if verbose:
170
- debug_tokens(agent)
171
- else:
172
- total_tokens = text_usage.input_tokens + text_usage.output_tokens + tools_usage.input_tokens + tools_usage.output_tokens
173
- cost_info = agent.get_cost()
174
- cost_display = cost_info.format_total_cost() if hasattr(cost_info, 'format_total_cost') else ""
175
- # Consolidated tokens and cost in a single line with a ruler
176
- console.print(Rule(f"Tokens: {total_tokens} | Cost: {cost_display}", style="dim", align="center"))
177
-
178
- @app.callback(invoke_without_command=True)
179
- def main(ctx: typer.Context,
180
- query: Optional[str] = typer.Argument(None, help="Query to send to the claudine agent"),
181
- debug: bool = typer.Option(False, "--debug", "-d", help="Enable debug mode"),
182
- verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed token usage and pricing information"),
183
- workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Set the workspace directory")):
184
- """
185
- Janito CLI tool. If a query is provided without a command, it will be sent to the claudine agent.
186
- """
187
- console = Console()
188
-
189
- # Set debug mode in config
190
- get_config().debug_mode = debug
191
-
192
- if workspace:
193
- try:
194
- print(f"Setting workspace directory to: {workspace}")
195
- get_config().workspace_dir = workspace
196
- print(f"Workspace directory set to: {get_config().workspace_dir}")
197
- except ValueError as e:
198
- console.print(f"[bold red]Error:[/bold red] {str(e)}")
199
- sys.exit(1)
200
-
201
- if ctx.invoked_subcommand is None and query:
202
- process_query(query, debug, verbose)
@@ -1,4 +0,0 @@
1
- You are an expert software engineer, working in a project.
2
- When using str_replace_editor be aware that our files starting path is "." .
3
-
4
- Before performing any action, always check the structure of the project for paths that might be related to the request.