janito 0.10.1__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 (32) hide show
  1. {janito-0.10.1 → janito-0.11.0}/.gitignore +2 -1
  2. {janito-0.10.1 → janito-0.11.0}/PKG-INFO +1 -1
  3. janito-0.11.0/janito/__main__.py +205 -0
  4. janito-0.11.0/janito/callbacks.py +132 -0
  5. janito-0.11.0/janito/chat_history.py +117 -0
  6. janito-0.11.0/janito/config.py +121 -0
  7. {janito-0.10.1 → janito-0.11.0}/janito/data/instructions.txt +4 -4
  8. janito-0.11.0/janito/token_report.py +145 -0
  9. janito-0.11.0/janito/tools/__init__.py +21 -0
  10. janito-0.11.0/janito/tools/bash.py +22 -0
  11. {janito-0.10.1 → janito-0.11.0}/janito/tools/decorators.py +101 -84
  12. {janito-0.10.1 → janito-0.11.0}/janito/tools/delete_file.py +47 -44
  13. {janito-0.10.1 → janito-0.11.0}/janito/tools/find_files.py +11 -7
  14. janito-0.11.0/janito/tools/prompt_user.py +26 -0
  15. janito-0.11.0/janito/tools/replace_file.py +36 -0
  16. {janito-0.10.1 → janito-0.11.0}/janito/tools/str_replace_editor/editor.py +52 -43
  17. {janito-0.10.1 → janito-0.11.0}/janito/tools/str_replace_editor/handlers.py +102 -105
  18. janito-0.11.0/janito/tools/str_replace_editor/utils.py +34 -0
  19. {janito-0.10.1 → janito-0.11.0}/pyproject.toml +1 -1
  20. janito-0.10.1/janito/__main__.py +0 -151
  21. janito-0.10.1/janito/callbacks.py +0 -130
  22. janito-0.10.1/janito/cli.py +0 -202
  23. janito-0.10.1/janito/config.py +0 -63
  24. janito-0.10.1/janito/token_report.py +0 -73
  25. janito-0.10.1/janito/tools/__init__.py +0 -10
  26. janito-0.10.1/janito/tools/str_replace_editor/utils.py +0 -88
  27. {janito-0.10.1 → janito-0.11.0}/LICENSE +0 -0
  28. {janito-0.10.1 → janito-0.11.0}/README.md +0 -0
  29. {janito-0.10.1 → janito-0.11.0}/janito/__init__.py +0 -0
  30. {janito-0.10.1 → janito-0.11.0}/janito/test_file.py +0 -0
  31. {janito-0.10.1 → janito-0.11.0}/janito/tools/search_text.py +0 -0
  32. {janito-0.10.1 → janito-0.11.0}/janito/tools/str_replace_editor/__init__.py +0 -0
@@ -107,4 +107,5 @@ venv.bak/
107
107
  *.swo
108
108
 
109
109
  # Janito
110
- .janito/
110
+ .janito/
111
+ janito-env/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: janito
3
- Version: 0.10.1
3
+ Version: 0.11.0
4
4
  Summary: Janito CLI tool
5
5
  Project-URL: Homepage, https://github.com/joaompinto/janito
6
6
  Author-email: João Pinto <lamego.pinto@gmail.com>
@@ -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="")
@@ -0,0 +1,117 @@
1
+ """
2
+ Chat history module for Janito.
3
+ Handles storing and loading chat history.
4
+ """
5
+ import os
6
+ import json
7
+ import datetime
8
+ from pathlib import Path
9
+ from typing import List, Dict, Any, Optional
10
+ from janito.config import get_config
11
+
12
+ def ensure_chat_history_dir() -> Path:
13
+ """
14
+ Ensure the chat history directory exists.
15
+
16
+ Returns:
17
+ Path: Path to the chat history directory
18
+ """
19
+ workspace_dir = get_config().workspace_dir
20
+ chat_history_dir = Path(workspace_dir) / ".janito" / "chat_history"
21
+ chat_history_dir.mkdir(parents=True, exist_ok=True)
22
+ return chat_history_dir
23
+
24
+
25
+
26
+ def store_conversation(query: str, response: str, agent=None) -> None:
27
+ """
28
+ Store a conversation in the chat history.
29
+
30
+ Args:
31
+ query: The user's query
32
+ response: The agent's response
33
+ agent: Optional agent instance for using get_messages method
34
+ """
35
+ chat_history_dir = ensure_chat_history_dir()
36
+ timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
37
+ filename = f"{timestamp}.json"
38
+
39
+ # Create the conversation data
40
+ conversation = {
41
+ "timestamp": timestamp,
42
+ "query": query,
43
+ "response": response
44
+ }
45
+
46
+ # Write to file
47
+ with open(chat_history_dir / filename, "w", encoding="utf-8") as f:
48
+ json.dump(conversation, f, ensure_ascii=False, indent=2)
49
+
50
+ def load_recent_conversations(count: int = 5) -> List[Dict[str, str]]:
51
+ """
52
+ Load the most recent conversations from the chat history.
53
+
54
+ Args:
55
+ count: Number of conversations to load
56
+
57
+ Returns:
58
+ List[Dict[str, str]]: List of conversations
59
+ """
60
+ chat_history_dir = ensure_chat_history_dir()
61
+
62
+ # Get all JSON files in the chat history directory
63
+ history_files = list(chat_history_dir.glob("*.json"))
64
+
65
+ # Sort by filename (which includes timestamp)
66
+ history_files.sort(reverse=True)
67
+
68
+ # Load the most recent conversations
69
+ conversations = []
70
+ for file_path in history_files[:count]:
71
+ try:
72
+ with open(file_path, "r", encoding="utf-8") as f:
73
+ conversation = json.load(f)
74
+ conversations.append(conversation)
75
+ except Exception as e:
76
+ print(f"Error loading chat history file {file_path}: {e}")
77
+
78
+ return conversations
79
+
80
+ def format_conversation_for_context(conversation: Dict[str, str]) -> str:
81
+ """
82
+ Format a conversation for inclusion in the context.
83
+
84
+ Args:
85
+ conversation: The conversation to format
86
+
87
+ Returns:
88
+ str: The formatted conversation
89
+ """
90
+ timestamp = conversation.get("timestamp", "Unknown time")
91
+ query = conversation.get("query", "")
92
+ response = conversation.get("response", "")
93
+
94
+ formatted_time = datetime.datetime.strptime(timestamp, "%Y%m%d_%H%M%S").strftime("%Y-%m-%d %H:%M:%S")
95
+
96
+ return f"--- Conversation from {formatted_time} ---\nUser: {query}\n\nAssistant: {response}\n\n"
97
+
98
+ def get_chat_history_context(count: int = 5) -> str:
99
+ """
100
+ Get the chat history formatted for inclusion in the agent's context.
101
+
102
+ Args:
103
+ count: Number of conversations to include
104
+
105
+ Returns:
106
+ str: The formatted chat history
107
+ """
108
+ conversations = load_recent_conversations(count)
109
+
110
+ if not conversations:
111
+ return ""
112
+
113
+ context = "# Previous conversations:\n\n"
114
+ for conversation in conversations:
115
+ context += format_conversation_for_context(conversation)
116
+
117
+ return context
@@ -0,0 +1,121 @@
1
+ """
2
+ Configuration module for Janito.
3
+ Provides a singleton Config class to access configuration values.
4
+ """
5
+ import os
6
+ import json
7
+ from pathlib import Path
8
+ from typing import Optional, Any, Dict
9
+ import typer
10
+
11
+ class Config:
12
+ """Singleton configuration class for Janito."""
13
+ _instance = None
14
+
15
+ def __new__(cls):
16
+ if cls._instance is None:
17
+ cls._instance = super(Config, cls).__new__(cls)
18
+ cls._instance._workspace_dir = os.getcwd()
19
+ cls._instance._verbose = False
20
+ cls._instance._history_context_count = 5
21
+ cls._instance._load_config()
22
+ return cls._instance
23
+
24
+ def _load_config(self) -> None:
25
+ """Load configuration from file."""
26
+ config_path = Path(self._workspace_dir) / ".janito" / "config.json"
27
+ if config_path.exists():
28
+ try:
29
+ with open(config_path, "r", encoding="utf-8") as f:
30
+ config_data = json.load(f)
31
+ if "history_context_count" in config_data:
32
+ self._history_context_count = config_data["history_context_count"]
33
+ if "debug_mode" in config_data:
34
+ self._verbose = config_data["debug_mode"]
35
+ except Exception as e:
36
+ print(f"Warning: Failed to load configuration: {str(e)}")
37
+
38
+ def _save_config(self) -> None:
39
+ """Save configuration to file."""
40
+ config_dir = Path(self._workspace_dir) / ".janito"
41
+ config_dir.mkdir(parents=True, exist_ok=True)
42
+ config_path = config_dir / "config.json"
43
+
44
+ config_data = {
45
+ "history_context_count": self._history_context_count,
46
+ "verbose": self._verbose
47
+ }
48
+
49
+ try:
50
+ with open(config_path, "w", encoding="utf-8") as f:
51
+ json.dump(config_data, f, indent=2)
52
+ except Exception as e:
53
+ print(f"Warning: Failed to save configuration: {str(e)}")
54
+
55
+ @property
56
+ def workspace_dir(self) -> str:
57
+ """Get the current workspace directory."""
58
+ return self._workspace_dir
59
+
60
+ @workspace_dir.setter
61
+ def workspace_dir(self, path: str) -> None:
62
+ """Set the workspace directory."""
63
+ # Convert to absolute path if not already
64
+ if not os.path.isabs(path):
65
+ path = os.path.normpath(os.path.abspath(path))
66
+ else:
67
+ # Ensure Windows paths are properly formatted
68
+ path = os.path.normpath(path)
69
+
70
+ # Check if the directory exists
71
+ if not os.path.isdir(path):
72
+ create_dir = typer.confirm(f"Workspace directory does not exist: {path}\nDo you want to create it?")
73
+ if create_dir:
74
+ try:
75
+ os.makedirs(path, exist_ok=True)
76
+ print(f"Created workspace directory: {path}")
77
+ except Exception as e:
78
+ raise ValueError(f"Failed to create workspace directory: {str(e)}")
79
+ else:
80
+ raise ValueError(f"Workspace directory does not exist: {path}")
81
+
82
+ self._workspace_dir = path
83
+
84
+ @property
85
+ def verbose(self) -> bool:
86
+ """Get the verbose mode status."""
87
+ return self._verbose
88
+
89
+ @verbose.setter
90
+ def verbose(self, value: bool) -> None:
91
+ """Set the verbose mode status."""
92
+ self._verbose = value
93
+
94
+ # For backward compatibility
95
+ @property
96
+ def debug_mode(self) -> bool:
97
+ """Get the debug mode status (alias for verbose)."""
98
+ return self._verbose
99
+
100
+ @debug_mode.setter
101
+ def debug_mode(self, value: bool) -> None:
102
+ """Set the debug mode status (alias for verbose)."""
103
+ self._verbose = value
104
+
105
+ @property
106
+ def history_context_count(self) -> int:
107
+ """Get the number of previous conversations to include in context."""
108
+ return self._history_context_count
109
+
110
+ @history_context_count.setter
111
+ def history_context_count(self, count: int) -> None:
112
+ """Set the number of previous conversations to include in context."""
113
+ if count < 0:
114
+ raise ValueError("History context count must be a non-negative integer")
115
+ self._history_context_count = count
116
+ self._save_config()
117
+
118
+ # Convenience function to get the config instance
119
+ def get_config() -> Config:
120
+ """Get the singleton Config instance."""
121
+ return Config()
@@ -1,4 +1,4 @@
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.
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
+ If creating or editing files with a large number of lines, organize them into smaller files.