janito 0.10.0__tar.gz → 0.11.0__tar.gz

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 (43) hide show
  1. janito-0.11.0/.gitignore +111 -0
  2. {janito-0.10.0/janito.egg-info → janito-0.11.0}/PKG-INFO +86 -88
  3. {janito-0.10.0 → janito-0.11.0}/README.md +5 -7
  4. janito-0.11.0/janito/__init__.py +5 -0
  5. janito-0.11.0/janito/__main__.py +205 -0
  6. janito-0.11.0/janito/callbacks.py +132 -0
  7. janito-0.11.0/janito/chat_history.py +117 -0
  8. janito-0.11.0/janito/config.py +121 -0
  9. janito-0.11.0/janito/data/instructions.txt +4 -0
  10. janito-0.11.0/janito/token_report.py +145 -0
  11. janito-0.11.0/janito/tools/__init__.py +21 -0
  12. janito-0.11.0/janito/tools/bash.py +22 -0
  13. {janito-0.10.0 → janito-0.11.0}/janito/tools/decorators.py +101 -84
  14. {janito-0.10.0 → janito-0.11.0}/janito/tools/delete_file.py +47 -44
  15. {janito-0.10.0 → janito-0.11.0}/janito/tools/find_files.py +11 -7
  16. janito-0.11.0/janito/tools/prompt_user.py +26 -0
  17. janito-0.11.0/janito/tools/replace_file.py +36 -0
  18. {janito-0.10.0 → janito-0.11.0}/janito/tools/search_text.py +226 -196
  19. {janito-0.10.0 → janito-0.11.0}/janito/tools/str_replace_editor/editor.py +52 -43
  20. {janito-0.10.0 → janito-0.11.0}/janito/tools/str_replace_editor/handlers.py +102 -105
  21. janito-0.11.0/janito/tools/str_replace_editor/utils.py +34 -0
  22. {janito-0.10.0 → janito-0.11.0}/pyproject.toml +11 -5
  23. janito-0.10.0/MANIFEST.in +0 -1
  24. janito-0.10.0/PKG-INFO +0 -88
  25. janito-0.10.0/janito/__init__.py +0 -5
  26. janito-0.10.0/janito/__main__.py +0 -151
  27. janito-0.10.0/janito/callbacks.py +0 -130
  28. janito-0.10.0/janito/cli.py +0 -202
  29. janito-0.10.0/janito/config.py +0 -63
  30. janito-0.10.0/janito/data/instructions.txt +0 -6
  31. janito-0.10.0/janito/token_report.py +0 -73
  32. janito-0.10.0/janito/tools/__init__.py +0 -10
  33. janito-0.10.0/janito/tools/str_replace_editor/utils.py +0 -88
  34. janito-0.10.0/janito.egg-info/SOURCES.txt +0 -28
  35. janito-0.10.0/janito.egg-info/dependency_links.txt +0 -1
  36. janito-0.10.0/janito.egg-info/entry_points.txt +0 -2
  37. janito-0.10.0/janito.egg-info/requires.txt +0 -3
  38. janito-0.10.0/janito.egg-info/top_level.txt +0 -1
  39. janito-0.10.0/setup.cfg +0 -4
  40. janito-0.10.0/setup.py +0 -7
  41. {janito-0.10.0 → janito-0.11.0}/LICENSE +0 -0
  42. {janito-0.10.0 → janito-0.11.0}/janito/test_file.py +0 -0
  43. {janito-0.10.0 → janito-0.11.0}/janito/tools/str_replace_editor/__init__.py +0 -0
@@ -0,0 +1,111 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ *.egg-info/
24
+ .installed.cfg
25
+ *.egg
26
+
27
+ # PyInstaller
28
+ *.manifest
29
+ *.spec
30
+
31
+ # Installer logs
32
+ pip-log.txt
33
+ pip-delete-this-directory.txt
34
+
35
+ # Unit test / coverage reports
36
+ htmlcov/
37
+ .tox/
38
+ .coverage
39
+ .coverage.*
40
+ .cache
41
+ nosetests.xml
42
+ coverage.xml
43
+ *.cover
44
+ .hypothesis/
45
+ .pytest_cache/
46
+
47
+ # Translations
48
+ *.mo
49
+ *.pot
50
+
51
+ # Django stuff:
52
+ *.log
53
+ local_settings.py
54
+ db.sqlite3
55
+
56
+ # Flask stuff:
57
+ instance/
58
+ .webassets-cache
59
+
60
+ # Scrapy stuff:
61
+ .scrapy
62
+
63
+ # Sphinx documentation
64
+ docs/_build/
65
+
66
+ # PyBuilder
67
+ target/
68
+
69
+ # Jupyter Notebook
70
+ .ipynb_checkpoints
71
+
72
+ # pyenv
73
+ .python-version
74
+
75
+ # celery beat schedule file
76
+ celerybeat-schedule
77
+
78
+ # SageMath parsed files
79
+ *.sage.py
80
+
81
+ # Environments
82
+ .env
83
+ .venv
84
+ env/
85
+ venv/
86
+ ENV/
87
+ env.bak/
88
+ venv.bak/
89
+
90
+ # Spyder project settings
91
+ .spyderproject
92
+ .spyproject
93
+
94
+ # Rope project settings
95
+ .ropeproject
96
+
97
+ # mkdocs documentation
98
+ /site
99
+
100
+ # mypy
101
+ .mypy_cache/
102
+
103
+ # IDE specific files
104
+ .idea/
105
+ .vscode/
106
+ *.swp
107
+ *.swo
108
+
109
+ # Janito
110
+ .janito/
111
+ janito-env/
@@ -1,88 +1,86 @@
1
- Metadata-Version: 2.2
2
- Name: janito
3
- Version: 0.10.0
4
- Summary: Janito CLI tool
5
- Author-email: João Pinto <lamego.pinto@gmail.com>
6
- Project-URL: Homepage, https://github.com/joaompinto/janito
7
- Requires-Python: >=3.8
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Requires-Dist: typer>=0.9.0
11
- Requires-Dist: rich>=13.0.0
12
- Requires-Dist: claudine>=0.1.0
13
-
14
- # 🤖 Janito
15
-
16
- Janito is a powerful AI-assisted command-line interface (CLI) tool built with Python, leveraging Anthropic's Claude for intelligent code and file management.
17
-
18
- ## ✨ Features
19
-
20
- - 🧠 Intelligent AI assistant powered by Claude
21
- - 📁 File management capabilities
22
- - 🔍 Smart code search and editing
23
- - 💻 Interactive terminal interface with rich formatting
24
- - 📊 Token usage tracking and cost reporting
25
-
26
- ## 🛠️ Installation
27
-
28
- ```bash
29
- # Clone the repository
30
- git clone https://github.com/joaompinto/janito.git
31
- cd janito
32
-
33
- # Install the package
34
- pip install -e .
35
- ```
36
-
37
- ## 🚀 Usage
38
-
39
- After installation, you can use the `janito` command in your terminal:
40
-
41
- ```bash
42
- # Get help
43
- janito --help
44
-
45
-
46
- # Ask the AI assistant a question
47
- janito "Suggest improvements to this project"
48
-
49
- janito "Add a --version to the cli to report he version"
50
-
51
- ```
52
-
53
- ## 🔧 Available Tools
54
-
55
- Janito comes with several built-in tools:
56
- - 📄 `str_replace_editor` - View, create, and edit files
57
- - 🔎 `find_files` - Find files matching patterns
58
- - 🗑️ `delete_file` - Delete files
59
- - 🔍 `search_text` - Search for text patterns in files
60
-
61
- ## ⚙️ Requirements
62
-
63
- - Python 3.8 or higher
64
- - Dependencies:
65
- - typer (>=0.9.0)
66
- - rich (>=13.0.0)
67
- - claudine (for Claude AI integration)
68
-
69
- ## 🔑 API Key
70
-
71
- Janito requires an Anthropic API key to function. You can:
72
- 1. Set it as an environment variable: `export ANTHROPIC_API_KEY=your_api_key`
73
- 2. Or enter it when prompted
74
-
75
- ## 💻 Development
76
-
77
- ```bash
78
- # Create a virtual environment
79
- python -m venv .venv
80
- source .venv/bin/activate # On Windows: .venv\Scripts\activate
81
-
82
- # Install development dependencies
83
- pip install -e ".[dev]"
84
- ```
85
-
86
- ## 📜 License
87
-
88
- [Add your license information here]
1
+ Metadata-Version: 2.4
2
+ Name: janito
3
+ Version: 0.11.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: claudine>=0.1.0
10
+ Requires-Dist: rich>=13.0.0
11
+ Requires-Dist: typer>=0.9.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # 🤖 Janito
15
+
16
+ Janito is a powerful AI-assisted command-line interface (CLI) tool built with Python, leveraging Anthropic's Claude for intelligent code and file management.
17
+
18
+ ## ✨ Features
19
+
20
+ - 🧠 Intelligent AI assistant powered by Claude
21
+ - 📁 File management capabilities
22
+ - 🔍 Smart code search and editing
23
+ - 💻 Interactive terminal interface with rich formatting
24
+ - 📊 Token usage tracking and cost reporting
25
+
26
+ ## 🛠️ Installation
27
+
28
+ ```bash
29
+ # Install directly from PyPI
30
+ pip install janito
31
+ ```
32
+
33
+ For development or installation from source, please see [README_DEV.md](README_DEV.md).
34
+
35
+ ## 🚀 Usage
36
+
37
+ After installation, you can use the `janito` command in your terminal:
38
+
39
+ ```bash
40
+ # Get help
41
+ janito --help
42
+
43
+
44
+ # Ask the AI assistant a question
45
+ janito "Suggest improvements to this project"
46
+
47
+ janito "Add a --version to the cli to report he version"
48
+
49
+ ```
50
+
51
+ ## 🔧 Available Tools
52
+
53
+ Janito comes with several built-in tools:
54
+ - 📄 `str_replace_editor` - View, create, and edit files
55
+ - 🔎 `find_files` - Find files matching patterns
56
+ - 🗑️ `delete_file` - Delete files
57
+ - 🔍 `search_text` - Search for text patterns in files
58
+
59
+ ## ⚙️ Requirements
60
+
61
+ - Python 3.8 or higher
62
+ - Dependencies:
63
+ - typer (>=0.9.0)
64
+ - rich (>=13.0.0)
65
+ - claudine (for Claude AI integration)
66
+
67
+ ## 🔑 API Key
68
+
69
+ Janito requires an Anthropic API key to function. You can:
70
+ 1. Set it as an environment variable: `export ANTHROPIC_API_KEY=your_api_key`
71
+ 2. Or enter it when prompted
72
+
73
+ ## 💻 Development
74
+
75
+ ```bash
76
+ # Create a virtual environment
77
+ python -m venv .venv
78
+ source .venv/bin/activate # On Windows: .venv\Scripts\activate
79
+
80
+ # Install development dependencies
81
+ pip install -e ".[dev]"
82
+ ```
83
+
84
+ ## 📜 License
85
+
86
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -13,14 +13,12 @@ Janito is a powerful AI-assisted command-line interface (CLI) tool built with Py
13
13
  ## 🛠️ Installation
14
14
 
15
15
  ```bash
16
- # Clone the repository
17
- git clone https://github.com/joaompinto/janito.git
18
- cd janito
19
-
20
- # Install the package
21
- pip install -e .
16
+ # Install directly from PyPI
17
+ pip install janito
22
18
  ```
23
19
 
20
+ For development or installation from source, please see [README_DEV.md](README_DEV.md).
21
+
24
22
  ## 🚀 Usage
25
23
 
26
24
  After installation, you can use the `janito` command in your terminal:
@@ -72,4 +70,4 @@ pip install -e ".[dev]"
72
70
 
73
71
  ## 📜 License
74
72
 
75
- [Add your license information here]
73
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,5 @@
1
+ """
2
+ Janito package.
3
+ """
4
+
5
+ __version__ = "0.11.0"
@@ -0,0 +1,205 @@
1
+ """
2
+ Main entry point for Janito.
3
+ """
4
+ import os
5
+ import sys
6
+ from typing import Optional
7
+ import importlib.resources
8
+ import typer
9
+ from rich.console import Console
10
+ import anthropic
11
+ from janito.config import get_config
12
+ from janito.chat_history import store_conversation, get_chat_history_context
13
+ from janito.callbacks import pre_tool_callback, post_tool_callback, text_callback
14
+ from janito.token_report import generate_token_report
15
+ from janito.tools import str_replace_editor
16
+ from janito.tools.bash import bash_tool
17
+ import claudine
18
+
19
+ app = typer.Typer()
20
+
21
+ @app.command()
22
+ def create_tool(name: str = typer.Argument(..., help="Name of the tool to create")):
23
+ """
24
+ Create a new tool with the given name.
25
+ """
26
+ console = Console()
27
+
28
+ # Ensure workspace is set
29
+ workspace_dir = get_config().workspace_dir
30
+
31
+ # Create the tools directory if it doesn't exist
32
+ tools_dir = os.path.join(workspace_dir, "tools")
33
+ os.makedirs(tools_dir, exist_ok=True)
34
+
35
+ # Create the tool file
36
+ tool_file = os.path.join(tools_dir, f"{name}.py")
37
+
38
+ # Check if the file already exists
39
+ if os.path.exists(tool_file):
40
+ console.print(f"[bold red]Error:[/bold red] Tool file already exists: {tool_file}")
41
+ return
42
+
43
+ # Create the tool file with a template
44
+ template = f'''"""
45
+ {name} tool for Janito.
46
+ """
47
+
48
+ def {name}(param1: str) -> str:
49
+ """
50
+ Description of the {name} tool.
51
+
52
+ Args:
53
+ param1: Description of param1
54
+
55
+ Returns:
56
+ str: Description of return value
57
+ """
58
+ # TODO: Implement the tool
59
+ return f"Executed {name} with param1={{param1}}"
60
+ '''
61
+
62
+ with open(tool_file, "w") as f:
63
+ f.write(template)
64
+
65
+ console.print(f"[bold green]Created tool:[/bold green] {tool_file}")
66
+
67
+ @app.callback(invoke_without_command=True)
68
+ def main(ctx: typer.Context,
69
+ query: Optional[str] = typer.Argument(None, help="Query to send to the claudine agent"),
70
+ verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose mode with detailed output"),
71
+ show_tokens: bool = typer.Option(False, "--show-tokens", "-t", help="Show detailed token usage and pricing information"),
72
+ workspace: Optional[str] = typer.Option(None, "--workspace", "-w", help="Set the workspace directory"),
73
+ config_str: Optional[str] = typer.Option(None, "--set-config", help="Configuration string in format 'key=value', e.g., 'context=5' for number of history messages to include"),
74
+ show_config: bool = typer.Option(False, "--show-config", help="Show current configuration")):
75
+ """
76
+ Janito CLI tool. If a query is provided without a command, it will be sent to the claudine agent.
77
+ """
78
+ console = Console()
79
+
80
+ # Set verbose mode in config
81
+ get_config().verbose = verbose
82
+
83
+ if workspace:
84
+ try:
85
+ print(f"Setting workspace directory to: {workspace}")
86
+ get_config().workspace_dir = workspace
87
+ print(f"Workspace directory set to: {get_config().workspace_dir}")
88
+ except ValueError as e:
89
+ console.print(f"[bold red]Error:[/bold red] {str(e)}")
90
+ sys.exit(1)
91
+
92
+ # Show current configuration if requested
93
+ if show_config:
94
+ config = get_config()
95
+ console.print("[bold blue]Current Configuration:[/bold blue]")
96
+ console.print(f"[bold]Workspace Directory:[/bold] {config.workspace_dir}")
97
+ console.print(f"[bold]Verbose Mode:[/bold] {'Enabled' if config.verbose else 'Disabled'}")
98
+ console.print(f"[bold]Chat History Context Count:[/bold] {config.history_context_count} messages")
99
+ # Exit if this was the only operation requested
100
+ if ctx.invoked_subcommand is None and not query:
101
+ sys.exit(0)
102
+
103
+ # Handle the --set-config parameter
104
+ if config_str is not None:
105
+ try:
106
+ # Parse the config string
107
+ if "context=" in config_str:
108
+ context_value = config_str.split("context=")[1].strip()
109
+ # If there are other configs after context, extract just the number
110
+ if " " in context_value:
111
+ context_value = context_value.split(" ")[0]
112
+
113
+ try:
114
+ context_value = int(context_value)
115
+ if context_value < 0:
116
+ console.print("[bold red]Error:[/bold red] History context count must be a non-negative integer")
117
+ return
118
+
119
+ get_config().history_context_count = context_value
120
+ console.print(f"[bold green]Chat history context count set to {context_value} messages[/bold green]")
121
+ except ValueError:
122
+ console.print(f"[bold red]Error:[/bold red] Invalid context value: {context_value}. Must be an integer.")
123
+ else:
124
+ console.print(f"[bold yellow]Warning:[/bold yellow] Unsupported configuration in: {config_str}")
125
+ except Exception as e:
126
+ console.print(f"[bold red]Error:[/bold red] {str(e)}")
127
+
128
+ if ctx.invoked_subcommand is None:
129
+ # If no query provided in command line, read from stdin
130
+ if not query:
131
+ console.print("[bold blue]No query provided in command line. Reading from stdin...[/bold blue]")
132
+ query = sys.stdin.read().strip()
133
+
134
+ # Only proceed if we have a query (either from command line or stdin)
135
+ if query:
136
+ # Get API key from environment variable or ask the user
137
+ api_key = os.environ.get("ANTHROPIC_API_KEY")
138
+ if not api_key:
139
+ console.print("[bold yellow]Warning:[/bold yellow] ANTHROPIC_API_KEY environment variable not set.")
140
+ console.print("Please set it or provide your API key now:")
141
+ api_key = typer.prompt("Anthropic API Key", hide_input=True)
142
+
143
+ # Load instructions from file
144
+ import importlib.resources as pkg_resources
145
+ try:
146
+ # For Python 3.9+
147
+ try:
148
+ from importlib.resources import files
149
+ instructions = files('janito.data').joinpath('instructions.txt').read_text(encoding='utf-8')
150
+ # Fallback for older Python versions
151
+ except (ImportError, AttributeError):
152
+ instructions = pkg_resources.read_text('janito.data', 'instructions.txt', encoding='utf-8')
153
+ except Exception as e:
154
+ console.print(f"[bold red]Error loading instructions:[/bold red] {str(e)}")
155
+ instructions = "You are Janito, an AI assistant."
156
+
157
+ # Temporarily disable chat history
158
+ # Get chat history context
159
+ # chat_history = get_chat_history_context(get_config().history_context_count)
160
+ # if chat_history:
161
+ # console.print("[dim]Loaded chat history from previous sessions.[/dim]")
162
+ # # Append chat history to instructions
163
+ # instructions = f"{instructions}\n\n{chat_history}"
164
+
165
+ # Get tools
166
+ from janito.tools import get_tools
167
+ tools_list = get_tools()
168
+
169
+ # Initialize the agent with the tools
170
+ agent = claudine.Agent(
171
+ api_key=api_key,
172
+ system_prompt=instructions,
173
+ callbacks={"pre_tool": pre_tool_callback, "post_tool": post_tool_callback, "text": text_callback},
174
+ text_editor_tool=str_replace_editor,
175
+ #bash_tool=bash_tool,
176
+ tools=tools_list,
177
+ verbose=verbose
178
+ )
179
+
180
+ # Send the query to the agent
181
+ try:
182
+ agent.query(query)
183
+
184
+ # Temporarily disable storing conversation in chat history
185
+ # Store the conversation in chat history
186
+ # store_conversation(query, response, agent)
187
+
188
+ # Print token usage report if show_tokens mode is enabled
189
+ if show_tokens:
190
+ generate_token_report(agent, verbose=True)
191
+ else:
192
+ # Show basic token usage
193
+ generate_token_report(agent, verbose=False)
194
+
195
+ except anthropic.APIError as e:
196
+ console.print(f"[bold red]Anthropic API Error:[/bold red] {str(e)}")
197
+
198
+ except Exception as e:
199
+ console.print(f"[bold red]Error:[/bold red] {str(e)}")
200
+ if verbose:
201
+ import traceback
202
+ console.print(traceback.format_exc())
203
+
204
+ if __name__ == "__main__":
205
+ app()
@@ -0,0 +1,132 @@
1
+ """
2
+ Callback functions for tool execution in janito.
3
+ """
4
+
5
+ from typing import Dict, Any, Tuple, Optional, List
6
+ from rich.console import Console
7
+ from rich.markdown import Markdown
8
+
9
+ from janito.config import get_config
10
+ from janito.tools import find_files
11
+ from janito.tools.str_replace_editor.editor import str_replace_editor
12
+ from janito.tools.delete_file import delete_file
13
+ from janito.tools.search_text import search_text
14
+ from janito.tools.decorators import format_tool_label
15
+
16
+ # Note: ConsoleCallback has been removed as we're using pre_tool and post_tool callbacks directly
17
+
18
+ def pre_tool_callback(tool_name: str, tool_input: Dict[str, Any]) -> Tuple[Dict[str, Any], bool]:
19
+ """
20
+ Callback function that runs before a tool is executed.
21
+
22
+ Args:
23
+ tool_name: Name of the tool being called
24
+ tool_input: Input parameters for the tool
25
+
26
+ Returns:
27
+ Tuple of (modified tool input, whether to cancel the tool call)
28
+ """
29
+ console = Console()
30
+
31
+ # Add debug counter only when verbose mode is enabled
32
+ if get_config().verbose:
33
+ if not hasattr(pre_tool_callback, "counter"):
34
+ pre_tool_callback.counter = 1
35
+ console.print(f"[bold green]DEBUG: Starting tool call #{pre_tool_callback.counter}[/bold green]")
36
+
37
+ # Print the tool name and input
38
+ console.print(f"[bold green]Tool:[/bold green] {tool_name}")
39
+ console.print(f"[bold green]Input:[/bold green] {tool_input}")
40
+ else:
41
+ # For non-debug mode, just print a simple message
42
+ # Find the tool function
43
+ tool_func = None
44
+ if tool_name == "find_files":
45
+ tool_func = find_files
46
+ elif tool_name == "str_replace_editor":
47
+ tool_func = str_replace_editor
48
+ elif tool_name == "delete_file":
49
+ tool_func = delete_file
50
+ elif tool_name == "search_text":
51
+ tool_func = search_text
52
+
53
+ # Format the input for display
54
+ display_input = ""
55
+ if "path" in tool_input:
56
+ display_input = tool_input["path"]
57
+ elif "file_path" in tool_input:
58
+ display_input = tool_input["file_path"]
59
+
60
+ # Print formatted tool label if available
61
+ formatted_label = format_tool_label(tool_func, tool_input)
62
+ if formatted_label:
63
+ console.print("[bold cyan] Tool:[/bold cyan]", formatted_label, end=" → ")
64
+ else:
65
+ console.print("[bold cyan] Tool:[/bold cyan]", f"{tool_name} {display_input}", end=" → ")
66
+
67
+ return tool_input, True # Continue with the tool call
68
+
69
+ def post_tool_callback(tool_name: str, tool_input: Dict[str, Any], result: Any) -> Any:
70
+ """
71
+ Callback function that runs after a tool is executed.
72
+
73
+ Args:
74
+ tool_name: Name of the tool that was called
75
+ tool_input: Input parameters for the tool
76
+ result: Result of the tool call
77
+
78
+ Returns:
79
+ Modified result
80
+ """
81
+ console = Console()
82
+
83
+ # Add debug counter only when verbose mode is enabled
84
+ if get_config().verbose:
85
+ if not hasattr(post_tool_callback, "counter"):
86
+ post_tool_callback.counter = 1
87
+ console.print(f"[bold green]DEBUG: Completed tool call #{post_tool_callback.counter}[/bold green]")
88
+ post_tool_callback.counter += 1
89
+
90
+ # Show the number of lines in the result content
91
+ if isinstance(result, tuple) and len(result) >= 1:
92
+ content, is_error = result
93
+ # Define prefix icon based on is_error
94
+ icon_prefix = "❌ " if is_error else "✅ "
95
+
96
+ if isinstance(content, str):
97
+ # Count the number of lines in the content
98
+ line_count = content.count('\n') + 1 if content else 0
99
+ console.print(f"{icon_prefix}{line_count} items")
100
+ else:
101
+ console.print(f"{icon_prefix}{content}")
102
+ else:
103
+ # If result is not a tuple, convert to string and count lines
104
+ result_str = str(result)
105
+ # Default to success icon when no error status is available
106
+ icon_prefix = "✅ "
107
+ line_count = result_str.count('\n') + 1 if result_str else 0
108
+ console.print(f"{icon_prefix}{line_count} lines")
109
+
110
+ return result
111
+
112
+ def text_callback(text: str) -> None:
113
+ """
114
+ Callback function that handles text output from the agent.
115
+
116
+ Args:
117
+ text: Text output from the agent
118
+
119
+ Returns:
120
+ None
121
+ """
122
+ console = Console()
123
+
124
+ # Add debug counter only when debug mode is enabled
125
+ if get_config().debug_mode:
126
+ if not hasattr(text_callback, "counter"):
127
+ text_callback.counter = 1
128
+ console.print(f"[bold blue]DEBUG: Text callback #{text_callback.counter}[/bold blue]")
129
+ text_callback.counter += 1
130
+
131
+ # Print the text with markdown formatting
132
+ console.print("[bold magenta]Janito:[/bold magenta] ", Markdown(text, code_theme="monokai"), end="")