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.
- janito/__init__.py +1 -1
- janito/__main__.py +3 -147
- janito/callbacks.py +13 -109
- janito/cli/__init__.py +6 -0
- janito/cli/agent.py +287 -0
- janito/cli/app.py +86 -0
- janito/cli/commands.py +329 -0
- janito/cli/output.py +29 -0
- janito/cli/utils.py +22 -0
- janito/config.py +338 -63
- janito/data/instructions_template.txt +27 -0
- janito/token_report.py +124 -43
- janito/tools/__init__.py +29 -1
- janito/tools/bash/bash.py +82 -0
- janito/tools/bash/unix_persistent_bash.py +182 -0
- janito/tools/bash/win_persistent_bash.py +306 -0
- janito/tools/decorators.py +90 -84
- janito/tools/delete_file.py +65 -44
- janito/tools/fetch_webpage/__init__.py +34 -0
- janito/tools/fetch_webpage/chunking.py +76 -0
- janito/tools/fetch_webpage/core.py +155 -0
- janito/tools/fetch_webpage/extractors.py +276 -0
- janito/tools/fetch_webpage/news.py +137 -0
- janito/tools/fetch_webpage/utils.py +108 -0
- janito/tools/find_files.py +108 -42
- janito/tools/move_file.py +72 -0
- janito/tools/prompt_user.py +57 -0
- janito/tools/replace_file.py +63 -0
- janito/tools/rich_console.py +139 -0
- janito/tools/search_text.py +33 -21
- janito/tools/str_replace_editor/editor.py +55 -43
- janito/tools/str_replace_editor/handlers/__init__.py +16 -0
- janito/tools/str_replace_editor/handlers/create.py +60 -0
- janito/tools/str_replace_editor/handlers/insert.py +100 -0
- janito/tools/str_replace_editor/handlers/str_replace.py +92 -0
- janito/tools/str_replace_editor/handlers/undo.py +64 -0
- janito/tools/str_replace_editor/handlers/view.py +153 -0
- janito/tools/str_replace_editor/utils.py +7 -62
- janito/tools/usage_tracker.py +136 -0
- janito-0.12.0.dist-info/METADATA +203 -0
- janito-0.12.0.dist-info/RECORD +47 -0
- janito/cli.py +0 -202
- janito/data/instructions.txt +0 -4
- janito/tools/str_replace_editor/handlers.py +0 -338
- janito-0.10.1.dist-info/METADATA +0 -86
- janito-0.10.1.dist-info/RECORD +0 -23
- {janito-0.10.1.dist-info → janito-0.12.0.dist-info}/WHEEL +0 -0
- {janito-0.10.1.dist-info → janito-0.12.0.dist-info}/entry_points.txt +0 -0
- {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
|
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
|
-
#
|
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
|
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
|
+
[](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)
|
janito/data/instructions.txt
DELETED