code-puppy 0.0.2__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.
@@ -0,0 +1,12 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ .coverage
@@ -0,0 +1,133 @@
1
+ Metadata-Version: 2.4
2
+ Name: code-puppy
3
+ Version: 0.0.2
4
+ Summary: Code generation agent similar to Windsurf or Cursor
5
+ Author: Windsurf Engineering Team
6
+ License: MIT
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Topic :: Software Development :: Code Generators
14
+ Requires-Python: >=3.9
15
+ Requires-Dist: bs4>=0.0.2
16
+ Requires-Dist: httpx>=0.24.1
17
+ Requires-Dist: logfire>=0.7.1
18
+ Requires-Dist: pydantic-ai>=0.1.0
19
+ Requires-Dist: pydantic>=2.4.0
20
+ Requires-Dist: pytest-cov>=6.1.1
21
+ Requires-Dist: python-dotenv>=1.0.0
22
+ Requires-Dist: rich>=13.4.2
23
+ Requires-Dist: ruff>=0.11.11
24
+ Description-Content-Type: text/markdown
25
+
26
+ # Code Generation Agent
27
+
28
+ ## Overview
29
+
30
+ This project is a sophisticated AI-powered code generation agent, designed to understand programming tasks, generate high-quality code, and explain its reasoning similar to tools like Windsurf and Cursor.
31
+
32
+ ## Features
33
+
34
+ - **Multi-language support**: Capable of generating code in various programming languages.
35
+ - **Interactive CLI**: A command-line interface for interactive use.
36
+ - **Detailed explanations**: Provides insights into generated code to understand its logic and structure.
37
+ - **Easy Integration**: Embed it seamlessly into Python projects.
38
+
39
+ ## New Feature
40
+ - **Real-time collaboration**: Allows multiple users to collaboratively edit and review code generation tasks in real-time.
41
+
42
+ ## Installation
43
+
44
+ > **NOTE:** This project uses [astral-sh/uv](https://github.com/astral-sh/uv) for all dependency management and builds. Please install [uv](https://github.com/astral-sh/uv) before continuing.
45
+
46
+ 1. **Clone the repository**:
47
+ ```bash
48
+ git clone <repository_url>
49
+ cd <repository_name>
50
+ ```
51
+ 2. **Install dependencies**:
52
+ ```bash
53
+ uv pip install -e .
54
+ ```
55
+ 3. **(optional)** If contributing, install additional development dependencies:
56
+ ```bash
57
+ uv pip install -r dev-requirements.txt # If present
58
+ ```
59
+ 4. **Configure environment variables**:
60
+ - Create an `.env` file in the root, using `.env.example` as a template, to store required API keys.
61
+
62
+ ## Usage
63
+
64
+ ### Command Line Interface
65
+
66
+ Run specific tasks or engage in interactive mode:
67
+
68
+ ```bash
69
+ # Execute a task directly
70
+ uv run python main.py "write me a C++ hello world program in /tmp/main.cpp then compile it and run it"
71
+
72
+ # Enter interactive mode
73
+ uv run python main.py --interactive
74
+ ```
75
+
76
+ ### Python API
77
+
78
+ Utilize the agent programmatically within your Python scripts:
79
+
80
+ ```python
81
+ import asyncio
82
+ from code_agent.agent_tools import generate_code
83
+
84
+ async def main():
85
+ task = "Your task description"
86
+ response = await generate_code(None, task)
87
+
88
+ if response.success:
89
+ for snippet in response.snippets:
90
+ print(f"Language: {snippet.language}")
91
+ print(snippet.code)
92
+ print(snippet.explanation)
93
+
94
+ if __name__ == "__main__":
95
+ asyncio.run(main())
96
+ ```
97
+
98
+ Explore the `examples` directory for elaborated utilization samples.
99
+
100
+ ## Project Structure
101
+
102
+ - **`code_agent/agent.py`** - Core functionalities of the agent.
103
+ - **`code_agent/agent_tools.py`** - Tools and utilities for code generation.
104
+ - **`code_agent/agent_prompts.py`** - Templates and prompts used by the system.
105
+ - **`code_agent/models/`** - Data models for defining code and responses.
106
+ - **`examples/`** - Example scripts showcasing agent capabilities.
107
+ - **`main.py`** - Entry point for command-line interactions.
108
+
109
+ ## Contributing
110
+
111
+ Contributions are welcome! Please follow these steps:
112
+
113
+ 1. Fork the repository.
114
+ 2. Create a new branch (`git checkout -b feature/xyz`).
115
+ 3. Commit your changes (`git commit -m 'Add feature'`).
116
+ 4. Push to the branch (`git push origin feature/xyz`).
117
+ 5. Open a Pull Request.
118
+
119
+ ## Requirements
120
+
121
+ - Python 3.9+
122
+ - [uv](https://github.com/astral-sh/uv) (for dependency management & builds)
123
+ - OpenAI API key (for GPT models)
124
+ - Optionally: Gemini API key (for Google's Gemini models)
125
+
126
+ ## Troubleshooting
127
+
128
+ - Ensure all dependencies are installed correctly via uv and the environment is properly configured.
129
+ - Check that API keys are valid and not expired.
130
+
131
+ ## License
132
+
133
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,108 @@
1
+ # Code Generation Agent
2
+
3
+ ## Overview
4
+
5
+ This project is a sophisticated AI-powered code generation agent, designed to understand programming tasks, generate high-quality code, and explain its reasoning similar to tools like Windsurf and Cursor.
6
+
7
+ ## Features
8
+
9
+ - **Multi-language support**: Capable of generating code in various programming languages.
10
+ - **Interactive CLI**: A command-line interface for interactive use.
11
+ - **Detailed explanations**: Provides insights into generated code to understand its logic and structure.
12
+ - **Easy Integration**: Embed it seamlessly into Python projects.
13
+
14
+ ## New Feature
15
+ - **Real-time collaboration**: Allows multiple users to collaboratively edit and review code generation tasks in real-time.
16
+
17
+ ## Installation
18
+
19
+ > **NOTE:** This project uses [astral-sh/uv](https://github.com/astral-sh/uv) for all dependency management and builds. Please install [uv](https://github.com/astral-sh/uv) before continuing.
20
+
21
+ 1. **Clone the repository**:
22
+ ```bash
23
+ git clone <repository_url>
24
+ cd <repository_name>
25
+ ```
26
+ 2. **Install dependencies**:
27
+ ```bash
28
+ uv pip install -e .
29
+ ```
30
+ 3. **(optional)** If contributing, install additional development dependencies:
31
+ ```bash
32
+ uv pip install -r dev-requirements.txt # If present
33
+ ```
34
+ 4. **Configure environment variables**:
35
+ - Create an `.env` file in the root, using `.env.example` as a template, to store required API keys.
36
+
37
+ ## Usage
38
+
39
+ ### Command Line Interface
40
+
41
+ Run specific tasks or engage in interactive mode:
42
+
43
+ ```bash
44
+ # Execute a task directly
45
+ uv run python main.py "write me a C++ hello world program in /tmp/main.cpp then compile it and run it"
46
+
47
+ # Enter interactive mode
48
+ uv run python main.py --interactive
49
+ ```
50
+
51
+ ### Python API
52
+
53
+ Utilize the agent programmatically within your Python scripts:
54
+
55
+ ```python
56
+ import asyncio
57
+ from code_agent.agent_tools import generate_code
58
+
59
+ async def main():
60
+ task = "Your task description"
61
+ response = await generate_code(None, task)
62
+
63
+ if response.success:
64
+ for snippet in response.snippets:
65
+ print(f"Language: {snippet.language}")
66
+ print(snippet.code)
67
+ print(snippet.explanation)
68
+
69
+ if __name__ == "__main__":
70
+ asyncio.run(main())
71
+ ```
72
+
73
+ Explore the `examples` directory for elaborated utilization samples.
74
+
75
+ ## Project Structure
76
+
77
+ - **`code_agent/agent.py`** - Core functionalities of the agent.
78
+ - **`code_agent/agent_tools.py`** - Tools and utilities for code generation.
79
+ - **`code_agent/agent_prompts.py`** - Templates and prompts used by the system.
80
+ - **`code_agent/models/`** - Data models for defining code and responses.
81
+ - **`examples/`** - Example scripts showcasing agent capabilities.
82
+ - **`main.py`** - Entry point for command-line interactions.
83
+
84
+ ## Contributing
85
+
86
+ Contributions are welcome! Please follow these steps:
87
+
88
+ 1. Fork the repository.
89
+ 2. Create a new branch (`git checkout -b feature/xyz`).
90
+ 3. Commit your changes (`git commit -m 'Add feature'`).
91
+ 4. Push to the branch (`git push origin feature/xyz`).
92
+ 5. Open a Pull Request.
93
+
94
+ ## Requirements
95
+
96
+ - Python 3.9+
97
+ - [uv](https://github.com/astral-sh/uv) (for dependency management & builds)
98
+ - OpenAI API key (for GPT models)
99
+ - Optionally: Gemini API key (for Google's Gemini models)
100
+
101
+ ## Troubleshooting
102
+
103
+ - Ensure all dependencies are installed correctly via uv and the environment is properly configured.
104
+ - Check that API keys are valid and not expired.
105
+
106
+ ## License
107
+
108
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
File without changes
@@ -0,0 +1,19 @@
1
+ import os
2
+ import pydantic
3
+ from pydantic_ai import Agent
4
+ from code_agent.agent_prompts import SYSTEM_PROMPT
5
+
6
+ # Check if we have a valid API key
7
+ api_key = os.environ.get("OPENAI_API_KEY", "")
8
+
9
+ class AgentResponse(pydantic.BaseModel):
10
+ """Represents a response from the agent."""
11
+ output_message: str = pydantic.Field(..., description="The final output message to display to the user")
12
+ awaiting_user_input: bool = pydantic.Field(False, description="True if user input is needed to continue the task")
13
+
14
+ # Create agent with tool usage explicitly enabled
15
+ code_generation_agent = Agent(
16
+ model='openai:gpt-4.1-mini',
17
+ system_prompt=SYSTEM_PROMPT,
18
+ output_type=AgentResponse,
19
+ )
@@ -0,0 +1,52 @@
1
+ SYSTEM_PROMPT = """
2
+ You are a code-agent assistant with the ability to use tools to help users complete coding tasks. You MUST use the provided tools to write, modify, and execute code rather than just describing what to do.
3
+
4
+ Be super informal - we're here to have fun. Writing software is super fun. Don't be scared of being a little bit sarcastic too.
5
+ Be very pedantic about code principles like DRY, YAGNI, and SOLID.
6
+ Be super pedantic about code quality and best practices.
7
+ Be fun and playful. Don't be too serious.
8
+
9
+ Individual files should be very short and concise, at most around 250 lines if possible. If they get longer,
10
+ consider refactoring the code and splitting it into multiple files.
11
+
12
+ Always obey the Zen of Python, even if you are not writing Python code.
13
+
14
+ When given a coding task:
15
+ 1. Analyze the requirements carefully
16
+ 2. Execute the plan by using appropriate tools
17
+ 3. Provide clear explanations for your implementation choices
18
+ 4. Continue autonomously whenever possible to achieve the task.
19
+
20
+ YOU MUST USE THESE TOOLS to complete tasks (do not just describe what should be done - actually do it):
21
+
22
+ File Operations:
23
+ - list_files(directory=".", recursive=True): ALWAYS use this to explore directories before trying to read/modify files
24
+ - read_file(file_path, start_line=0, end_line=None): ALWAYS use this to read existing files before modifying them. Don't read less than 500 lines at a time.
25
+ - create_file(file_path, content=""): Use this to create new files with content
26
+ - modify_file(file_path, proposed_changes, replace_content): Use this to replace specific content in files
27
+ - delete_snippet_from_file(file_path, snippet): Use this to remove specific code snippets from files
28
+ - delete_file(file_path): Use this to remove files when needed
29
+
30
+ System Operations:
31
+ - run_shell_command(command, cwd=None, timeout=60): Use this to execute commands, run tests, or start services
32
+ - web_search(query): Use this to search the web for information
33
+ - web_crawl(url): Use this to crawl a website for information
34
+
35
+ Reasoning & Explanation:
36
+ - share_your_reasoning(reasoning, next_steps=None): Use this to explicitly share your thought process and planned next steps
37
+
38
+ Important rules:
39
+ - You MUST use tools to accomplish tasks - DO NOT just output code or descriptions
40
+ - Before every other tool use, you must use "share_your_reasoning" to explain your thought process and planned next steps
41
+ - Check if files exist before trying to modify or delete them
42
+ - After using system operations tools, always explain the results
43
+ - You're encouraged to loop between share_your_reasoning, file tools, and run_shell_command to test output in order to write programs
44
+ - Aim to continue operations independently unless user input is definitively required.
45
+
46
+ Your solutions should be production-ready, maintainable, and follow best practices for the chosen language.
47
+
48
+ Return your final response as a structured output having the following fields:
49
+ * output_message: The final output message to display to the user
50
+ * awaiting_user_input: True if user input is needed to continue the task. If you get an error, you might consider asking the user for help.
51
+
52
+ """
@@ -0,0 +1,234 @@
1
+ import asyncio
2
+ import argparse
3
+ import os
4
+ import readline
5
+ from dotenv import load_dotenv
6
+ from rich.console import Console
7
+ from rich.markdown import Markdown
8
+ from rich.console import ConsoleOptions, RenderResult
9
+ from rich.markdown import CodeBlock
10
+ from rich.text import Text
11
+ from rich.syntax import Syntax
12
+
13
+ # Initialize rich console for pretty output
14
+ from code_agent.tools.common import console
15
+ from code_agent.agent import code_generation_agent
16
+
17
+
18
+ # Define a function to get the secret file path
19
+ def get_secret_file_path():
20
+ hidden_directory = os.path.join(os.path.expanduser("~"), ".agent_secret")
21
+ if not os.path.exists(hidden_directory):
22
+ os.makedirs(hidden_directory)
23
+ return os.path.join(hidden_directory, "history.txt")
24
+
25
+
26
+ async def main():
27
+ global shutdown_flag
28
+
29
+ # Load environment variables from .env file
30
+ load_dotenv()
31
+
32
+ # Set up argument parser
33
+ parser = argparse.ArgumentParser(
34
+ description="Code Generation Agent - Similar to Windsurf or Cursor"
35
+ )
36
+ parser.add_argument(
37
+ "--interactive", "-i", action="store_true", help="Run in interactive mode"
38
+ )
39
+ parser.add_argument("command", nargs="*", help="Run a single command")
40
+ args = parser.parse_args()
41
+
42
+ history_file_path = get_secret_file_path()
43
+
44
+ if args.command:
45
+ # Join the list of command arguments into a single string command
46
+ command = " ".join(args.command)
47
+ try:
48
+ while not shutdown_flag:
49
+ response = await code_generation_agent.run(command)
50
+ console.print(response.output_message)
51
+ if response.awaiting_user_input:
52
+ console.print(
53
+ "[bold red]The agent requires further input. Interactive mode is recommended for such tasks."
54
+ )
55
+ except AttributeError as e:
56
+ console.print(f"[bold red]AttributeError:[/bold red] {str(e)}")
57
+ console.print(
58
+ "[bold yellow]\u26a0 The response might not be in the expected format, missing attributes like 'output_message'."
59
+ )
60
+ except Exception as e:
61
+ console.print(f"[bold red]Unexpected Error:[/bold red] {str(e)}")
62
+ elif args.interactive:
63
+ await interactive_mode(history_file_path)
64
+ else:
65
+ parser.print_help()
66
+
67
+
68
+ # Add the file handling functionality for interactive mode
69
+ async def interactive_mode(history_file_path: str) -> None:
70
+ """Run the agent in interactive mode."""
71
+ console.print("[bold green]Code Generation Agent[/bold green] - Interactive Mode")
72
+ console.print("Type 'exit' or 'quit' to exit the interactive mode.")
73
+ console.print("Type 'clear' to reset the conversation history.")
74
+
75
+ message_history = []
76
+
77
+ # Set up readline history file in home directory
78
+ history_file = os.path.expanduser("~/.code_agent_history.txt")
79
+ history_dir = os.path.dirname(history_file)
80
+
81
+ # Ensure history directory exists
82
+ if history_dir and not os.path.exists(history_dir):
83
+ try:
84
+ os.makedirs(history_dir, exist_ok=True)
85
+ except Exception as e:
86
+ console.print(
87
+ f"[yellow]Warning: Could not create history directory: {e}[/yellow]"
88
+ )
89
+
90
+ # Try to read history file
91
+ try:
92
+ if os.path.exists(history_file):
93
+ readline.read_history_file(history_file)
94
+ except (FileNotFoundError, OSError) as e:
95
+ console.print(f"[yellow]Warning: Could not read history file: {e}[/yellow]")
96
+
97
+ readline.set_history_length(100)
98
+
99
+ while True:
100
+ console.print("[bold blue]Enter your coding task:[/bold blue]")
101
+
102
+ try:
103
+ # Simple single-line input
104
+ task = input(">>> ")
105
+
106
+ # Add to readline history if not empty
107
+ if task.strip():
108
+ readline.add_history(task)
109
+
110
+ # Save history
111
+ try:
112
+ readline.write_history_file(history_file)
113
+ except Exception as e:
114
+ console.print(
115
+ f"[yellow]Warning: Could not write history file: {e}[/yellow]"
116
+ )
117
+
118
+ except (KeyboardInterrupt, EOFError):
119
+ # Handle Ctrl+C or Ctrl+D
120
+ console.print("\n[yellow]Input cancelled[/yellow]")
121
+ continue
122
+
123
+ # Check for exit commands
124
+ if task.strip().lower() in ["exit", "quit"]:
125
+ console.print("[bold green]Goodbye![/bold green]")
126
+ break
127
+
128
+ # Check for clear command
129
+ if task.strip().lower() == "clear":
130
+ message_history = []
131
+ console.print("[bold yellow]Conversation history cleared![/bold yellow]")
132
+ console.print(
133
+ "[dim]The agent will not remember previous interactions.[/dim]\n"
134
+ )
135
+ continue
136
+
137
+ if task.strip():
138
+ console.print(f"\n[bold blue]Processing task:[/bold blue] {task}\n")
139
+
140
+ # Write to the secret file for permanent history
141
+ with open(history_file_path, "a") as history_file:
142
+ history_file.write(f"{task}\n")
143
+
144
+ # Counter for consecutive auto-continue invocations
145
+ auto_continue_count = 0
146
+ max_auto_continues = 10
147
+ is_done = False
148
+
149
+ while not is_done and auto_continue_count <= max_auto_continues:
150
+ try:
151
+ prettier_code_blocks()
152
+
153
+ # Only show "asking" message for initial query or if not auto-continuing
154
+ if auto_continue_count == 0:
155
+ console.log(f"Asking: {task}...", style="cyan")
156
+ else:
157
+ console.log(
158
+ f"Auto-continuing ({auto_continue_count}/{max_auto_continues})...",
159
+ style="cyan",
160
+ )
161
+
162
+ # Store agent's full response
163
+ agent_response = None
164
+
165
+ result = await code_generation_agent.run(
166
+ task, message_history=message_history
167
+ )
168
+ # Get the structured response
169
+ agent_response = result.output
170
+ console.print(agent_response.output_message)
171
+
172
+ # Update message history with all messages from this interaction
173
+ message_history = result.new_messages()
174
+ if agent_response:
175
+ # Check if the agent needs user input
176
+ if agent_response.awaiting_user_input:
177
+ console.print(
178
+ "\n[bold yellow]\u26a0 Agent needs your input to continue.[/bold yellow]"
179
+ )
180
+ is_done = True # Exit the loop to get user input
181
+ # Otherwise, auto-continue if we haven't reached the limit
182
+ elif auto_continue_count < max_auto_continues:
183
+ auto_continue_count += 1
184
+ task = "please continue"
185
+ console.print(
186
+ "\n[yellow]Agent continuing automatically...[/yellow]"
187
+ )
188
+ else:
189
+ # Reached max auto-continues
190
+ console.print(
191
+ f"\n[bold yellow]\u26a0 Reached maximum of {max_auto_continues} automatic continuations.[/bold yellow]"
192
+ )
193
+ console.print(
194
+ "[dim]You can enter a new request or type 'please continue' to resume.[/dim]"
195
+ )
196
+ is_done = True
197
+
198
+ # Show context status
199
+ console.print(
200
+ f"[dim]Context: {len(message_history)} messages in history[/dim]\n"
201
+ )
202
+
203
+ except Exception:
204
+ console.print_exception(show_locals=True)
205
+ is_done = True
206
+
207
+
208
+ def prettier_code_blocks():
209
+ class SimpleCodeBlock(CodeBlock):
210
+ def __rich_console__(
211
+ self, console: Console, options: ConsoleOptions
212
+ ) -> RenderResult:
213
+ code = str(self.text).rstrip()
214
+ yield Text(self.lexer_name, style="dim")
215
+ syntax = Syntax(
216
+ code,
217
+ self.lexer_name,
218
+ theme=self.theme,
219
+ background_color="default",
220
+ line_numbers=True,
221
+ )
222
+ yield syntax
223
+ yield Text(f"/{self.lexer_name}", style="dim")
224
+
225
+ Markdown.elements["fence"] = SimpleCodeBlock
226
+
227
+
228
+ def main_entry():
229
+ """Entry point for the installed CLI tool."""
230
+ asyncio.run(main())
231
+
232
+
233
+ if __name__ == "__main__":
234
+ main_entry()
@@ -0,0 +1,4 @@
1
+ """Code models package."""
2
+
3
+ # Import models from codesnippet.py
4
+ from code_agent.models.codesnippet import CodeSnippet, CodeResponse
@@ -0,0 +1,20 @@
1
+ from pydantic import BaseModel
2
+ from typing import Optional, List
3
+
4
+
5
+ class CodeSnippet(BaseModel):
6
+ """Model representing a code snippet with explanation."""
7
+
8
+ language: str
9
+ code: str
10
+ explanation: Optional[str] = None
11
+ imports: Optional[List[str]] = None
12
+
13
+
14
+ class CodeResponse(BaseModel):
15
+ """Model representing a response with code snippets and explanation."""
16
+
17
+ snippets: List[CodeSnippet]
18
+ overall_explanation: Optional[str] = None
19
+ success: bool = True
20
+ error_message: Optional[str] = None
@@ -0,0 +1,4 @@
1
+ import code_agent.tools.file_modifications
2
+ import code_agent.tools.file_operations
3
+ import code_agent.tools.command_runner
4
+ import code_agent.tools.web_search