regcode 0.3.0__tar.gz → 0.4.1__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.
- {regcode-0.3.0 → regcode-0.4.1}/GOALS.md +9 -6
- regcode-0.4.1/PKG-INFO +237 -0
- regcode-0.4.1/README.md +219 -0
- {regcode-0.3.0 → regcode-0.4.1}/pyproject.toml +7 -5
- {regcode-0.3.0 → regcode-0.4.1}/regcode/__init__.py +1 -1
- {regcode-0.3.0 → regcode-0.4.1}/regcode/cli.py +15 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/config.py +47 -21
- regcode-0.4.1/regcode/dependencies.py +71 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/main.py +45 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/tools/__init__.py +0 -2
- {regcode-0.3.0 → regcode-0.4.1}/regcode/tools/builtins.py +462 -39
- regcode-0.4.1/regcode/tools/web_crawl.py +167 -0
- regcode-0.4.1/regcode/tracing.py +107 -0
- regcode-0.4.1/regcode/tui.py +965 -0
- regcode-0.4.1/repair_tui.md +115 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_api.py +1 -1
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_cli.py +1 -1
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_config.py +3 -3
- regcode-0.4.1/tests/test_dependencies.py +149 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_main.py +2 -1
- regcode-0.4.1/tests/test_osv_cve.py +280 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_provider_extra.py +10 -15
- {regcode-0.3.0 → regcode-0.4.1}/uv.lock +2044 -1
- regcode-0.3.0/PKG-INFO +0 -164
- regcode-0.3.0/README.md +0 -148
- regcode-0.3.0/regcode/tui.py +0 -663
- {regcode-0.3.0 → regcode-0.4.1}/.gitignore +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/.python-version +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/.qwen/settings.json +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/AGENTS.md +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/config.yaml.template +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/main.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/conversation_manager.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/monty_sandbox.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/permissions.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/sandbox.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/tools/base.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/tools/registry.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/regcode/tools/review_notes.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/__init__.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/conftest.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_context_manager.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_monty_sandbox.py +0 -0
- {regcode-0.3.0 → regcode-0.4.1}/tests/test_review_notes.py +0 -0
|
@@ -492,11 +492,14 @@ All phases complete. 50/50 tests passing. Lint clean.
|
|
|
492
492
|
### LLM Hallucinated Tool Calls Fix
|
|
493
493
|
- DONE: Model was hallucinating tool calls (e.g. `<tool_call>`) when budget was exhausted and `tools=None`. Root cause: tool definitions were baked into the system prompt string, so even with `tools=None` the model still saw tool names and hallucinated calling them. Fix: when budget is exhausted, replace the system prompt with a version stripped of tool definitions (`_build_system_prompt_no_tools()`). Additionally set `tool_choice="none"` and stop sequences `["<tool_call>", "</tool_use>"]`. Message history (including tool_call_ids) is preserved intact to maintain proper conversation continuity.
|
|
494
494
|
|
|
495
|
-
## Top Priority To-Dos:
|
|
496
495
|
|
|
497
|
-
|
|
498
|
-
- I think for this agent to be able to work on big repos, we need to add `add_review_note` tool which basically can write review notes into file which can survive compaction. Review notes are supposed to be preleminary findings. Add `read_review_notes` as well. This must work intune with compaction feature
|
|
499
|
-
- Save tokens reported by litellm and use following logic `context_window=max_tokens + message_chain_token_size` and compact based on compaction threshold.
|
|
500
|
-
- _build_system_prompt in regcode/main.py and _build_code_review_system_prompt in the same file share an identical loop that constructs a "tool descriptions" string from registered tools. The same logic appears twice. This should be extracted into a single helper method, e.g. _format_tool_descriptions(self) -> str, called by both.
|
|
496
|
+
### COMPLETED (2026-06-29)
|
|
501
497
|
|
|
502
|
-
|
|
498
|
+
1. ✅ **Remove model config params from AgentConfig** — `model`, `max_tokens`, `temperature` moved from `Config.agent` to `Config.provider`. `AgentConfig` now only holds `context_window`, `compaction_threshold`, and `enable_compaction`. All tests updated to use new format.
|
|
499
|
+
|
|
500
|
+
2. ✅ **TUI complete overhaul** — `tui.py` rewritten from scratch. New layout: (1) top status bar showing `[RegCode <version>] [model] [$cost] [tokens]`, (2) large chat history area with clearly separated user/agent/tool/system message blocks, (3) bottom bar with progress indicator and input field. Streaming works correctly: text chunks stream live, then on completion full Markdown is rendered. Tool calls are interleaved after streaming text (stream buffer flushed before status rendering). Context compaction shows status indicators. All 137 tests pass, lint clean.
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
## To Dos:
|
|
504
|
+
- implement web crawl tool with https://github.com/unclecode/crawl4AI, the api should be straight forward. Use its inbuilt markdown generation and markdown integration.
|
|
505
|
+
- If current Dir has `Agents.MD`, or `AGENTS.md` or `agents.md`, read it and provide it clearly marked as content of Agents.md to the model as extra context about the project.
|
regcode-0.4.1/PKG-INFO
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: regcode
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Minimalistic coding agent with Python API and CLI
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Requires-Dist: click>=8.0
|
|
7
|
+
Requires-Dist: crawl4ai>=0.4.0
|
|
8
|
+
Requires-Dist: litellm>=1.83.17
|
|
9
|
+
Requires-Dist: mlflow>=3.14.0
|
|
10
|
+
Requires-Dist: pydantic-monty>=0.0.18
|
|
11
|
+
Requires-Dist: pydantic-settings>=2.14.2
|
|
12
|
+
Requires-Dist: pytest>=8.0
|
|
13
|
+
Requires-Dist: pyyaml>=6.0
|
|
14
|
+
Requires-Dist: ruff>=0.8
|
|
15
|
+
Requires-Dist: textual>=8.2.7
|
|
16
|
+
Provides-Extra: dev
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# RegCode
|
|
20
|
+
|
|
21
|
+
A minimalistic coding agent with Python API bindings and CLI interface.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- **litellm** as the LLM backbone (supports OpenAI, Anthropic, and 100+ providers)
|
|
26
|
+
- **YAML configuration** for model, tokens, temperature, and provider settings via Pydantic models
|
|
27
|
+
- **Environment variable expansion** in config values (e.g., `${OPENAI_API_KEY}`)
|
|
28
|
+
- **CLI** via click: `chat`, `configure`, `version`
|
|
29
|
+
- **Python API**: `import regcode; agent = regcode.Agent()`
|
|
30
|
+
- **Host filesystem I/O**: `write_file` and `patch_file` operate directly on the host filesystem with path traversal protection
|
|
31
|
+
- **Robust tool call handling**: malformed tool calls and JSON parse errors are gracefully handled
|
|
32
|
+
- **Progressive streaming**: TUI always streams assistant responses progressively rather than all at once
|
|
33
|
+
- **Context window compaction**: Automatically compacts conversation history when approaching token limits, preserving system instructions and review notes
|
|
34
|
+
- **Review notes**: Persistent findings stored across context compaction sessions
|
|
35
|
+
- **Tool budget limits**: Configurable maximum number of tool calls per conversation turn
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Install dependencies
|
|
41
|
+
uv sync
|
|
42
|
+
|
|
43
|
+
# Configure your API key (or set OPENAI_API_KEY in your environment)
|
|
44
|
+
# Edit config.yaml or use environment variables
|
|
45
|
+
|
|
46
|
+
# Chat with the agent (uses Textual TUI)
|
|
47
|
+
uv run regcode chat
|
|
48
|
+
|
|
49
|
+
# Interactive config generator
|
|
50
|
+
uv run regcode configure
|
|
51
|
+
|
|
52
|
+
# View version
|
|
53
|
+
uv run regcode version
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## CLI Chat Options
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Full agent mode (enables write permissions)
|
|
60
|
+
uv run regcode chat --full
|
|
61
|
+
|
|
62
|
+
# Use a specific model
|
|
63
|
+
uv run regcode chat --model "openai/gpt-4o"
|
|
64
|
+
|
|
65
|
+
# Disable colored output
|
|
66
|
+
uv run regcode chat --no-color
|
|
67
|
+
|
|
68
|
+
# Use a custom config file
|
|
69
|
+
uv run regcode chat --config /path/to/config.yaml
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## TUI Slash Commands
|
|
73
|
+
|
|
74
|
+
While chatting, you can use these slash commands in the input bar:
|
|
75
|
+
|
|
76
|
+
- `/exit` or `/quit` — Quit the application
|
|
77
|
+
- `/clear` — Clear the chat history
|
|
78
|
+
- `/reset` — Reset the session (clear history and tools)
|
|
79
|
+
|
|
80
|
+
## Usage as a Library
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import regcode
|
|
84
|
+
|
|
85
|
+
# Load config (reads config.yaml, falls back to ~/.regcode/config.yaml, then defaults)
|
|
86
|
+
config = regcode.Config.load("config.yaml")
|
|
87
|
+
|
|
88
|
+
# Create agent
|
|
89
|
+
agent = regcode.Agent(config=config)
|
|
90
|
+
|
|
91
|
+
# Chat (TUI always streams responses progressively)
|
|
92
|
+
reply = agent.chat("Refactor this function to use async/await.")
|
|
93
|
+
print(reply)
|
|
94
|
+
|
|
95
|
+
# Reset conversation
|
|
96
|
+
agent.reset()
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Tools
|
|
100
|
+
|
|
101
|
+
RegCode includes several built-in tools the agent can use:
|
|
102
|
+
|
|
103
|
+
| Tool | Permission | Description |
|
|
104
|
+
|------|-----------|-------------|
|
|
105
|
+
| `python_code` | `EXECUTE` | Execute Python code in an isolated Monty sandbox with Rust-based security and resource limits |
|
|
106
|
+
| `shell_command` | `EXECUTE` | Execute shell commands (subprocess, not sandbox). Only safe, read-only commands are allowed (ls, cat, echo, head, tail, wc, grep, sort, uniq, date, pwd, whoami, id, uname, df, free, which, type, stat, file, sha256sum, md5sum, base64, xxd, od, hexdump, find) |
|
|
107
|
+
| `run_script` | `EXECUTE` | Execute a Python script file in the Monty sandbox |
|
|
108
|
+
| `read_file` | `READ` | Read the contents of a file from the filesystem |
|
|
109
|
+
| `write_file` | `WRITE` | Write content to a file on the host filesystem |
|
|
110
|
+
| `patch_file` | `WRITE` | Replace a range of lines in an existing file |
|
|
111
|
+
| `list_dir` | `READ` | List contents of a directory |
|
|
112
|
+
| `search_files` | `READ` | Search for files matching a pattern |
|
|
113
|
+
| `search_dir` | `READ` | Search for a pattern inside all files within a directory |
|
|
114
|
+
| `fetch_git_diff` | `READ` | Fetch the git diff of the current repository |
|
|
115
|
+
| `osv_cve_scan` | `READ` | Scan project dependencies for known CVEs via OSV.dev API. Optionally scans the codebase for vulnerable usage patterns |
|
|
116
|
+
| `system_info` | `READ` | Get system information (OS, Python version, etc.) |
|
|
117
|
+
|
|
118
|
+
> **Note**: `browse_dir` is defined in the codebase but **not included in the default tools**. It can be explicitly registered if needed, but is excluded by default because it recursively lists all files in a directory, which can fill the context window in large projects (e.g., `.venv`, `node_modules`).
|
|
119
|
+
|
|
120
|
+
All file-writing tools (`write_file`, `patch_file`) include path traversal protection (`..` is blocked). The `patch_file` tool validates line number bounds and type correctness before performing the replacement.
|
|
121
|
+
|
|
122
|
+
## Project Structure
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
project-root/
|
|
126
|
+
├── main.py # Unused stub (hello world only)
|
|
127
|
+
├── config.yaml # Runtime configuration
|
|
128
|
+
├── config.yaml.template # Template for new configs
|
|
129
|
+
├── pyproject.toml # Project metadata and dependencies
|
|
130
|
+
├── uv.lock # Locked dependencies
|
|
131
|
+
└── regcode/ # Python package
|
|
132
|
+
├── __init__.py # Python API entry point
|
|
133
|
+
├── main.py # Agent core (chat, review, etc.)
|
|
134
|
+
├── cli.py # CLI entry point (click)
|
|
135
|
+
├── config.py # Config loader (yaml + pydantic)
|
|
136
|
+
├── permissions.py # Tool permission definitions
|
|
137
|
+
├── tui.py # Textual-based terminal UI
|
|
138
|
+
├── conversation_manager.py # Context compaction & review notes
|
|
139
|
+
├── sandbox.py # Legacy sandbox support
|
|
140
|
+
├── monty_sandbox.py # Monty sandbox integration
|
|
141
|
+
└── tools/
|
|
142
|
+
├── __init__.py
|
|
143
|
+
├── base.py # Base tool classes
|
|
144
|
+
├── builtins.py # Built-in tool implementations
|
|
145
|
+
├── registry.py # Tool registry management
|
|
146
|
+
└── review_notes.py # Review notes persistence
|
|
147
|
+
├── tests/
|
|
148
|
+
│ ├── conftest.py
|
|
149
|
+
│ ├── test_main.py
|
|
150
|
+
│ ├── test_config.py
|
|
151
|
+
│ ├── test_api.py
|
|
152
|
+
│ ├── test_cli.py
|
|
153
|
+
│ ├── test_context_manager.py
|
|
154
|
+
│ ├── test_monty_sandbox.py
|
|
155
|
+
│ ├── test_provider_extra.py
|
|
156
|
+
│ └── test_review_notes.py
|
|
157
|
+
└── README.md
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Testing & Linting
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
uv run pytest tests/ -v
|
|
164
|
+
uv run ruff check --fix regcode/ tests/
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Configuration
|
|
168
|
+
|
|
169
|
+
Edit `config.yaml` to customize the agent's behavior. The config is loaded from the specified path, `~/.regcode/config.yaml`, or falls back to defaults.
|
|
170
|
+
|
|
171
|
+
```yaml
|
|
172
|
+
agent:
|
|
173
|
+
context_window: 128000 # Maximum context window size
|
|
174
|
+
compaction_threshold: 0.8 # Compact when context > 80% of window
|
|
175
|
+
enable_compaction: true # Enable automatic context compaction
|
|
176
|
+
|
|
177
|
+
provider:
|
|
178
|
+
model: "openai/gpt-4o" # Model identifier (litellm format)
|
|
179
|
+
base_url: "https://api.openai.com/v1"
|
|
180
|
+
api_key: "${OPENAI_API_KEY}" # Environment variable expansion supported
|
|
181
|
+
temperature: 1.0
|
|
182
|
+
max_tokens: 4096
|
|
183
|
+
|
|
184
|
+
system_prompt: | # Custom system prompt (default is provided)
|
|
185
|
+
You are a coding agent.
|
|
186
|
+
|
|
187
|
+
tools: {} # Reserved for future tool configuration
|
|
188
|
+
|
|
189
|
+
sandbox:
|
|
190
|
+
use_monty: true # Enable Monty sandbox for Python execution
|
|
191
|
+
max_duration_secs: 10.0
|
|
192
|
+
max_memory_mb: 64
|
|
193
|
+
max_recursion_depth: 100
|
|
194
|
+
type_check: true
|
|
195
|
+
allowed_imports: []
|
|
196
|
+
|
|
197
|
+
tool_budget: 20 # Max tool calls per agent turn
|
|
198
|
+
|
|
199
|
+
permissions:
|
|
200
|
+
- read # READ: read_file, list_dir, search_files, search_dir, browse_dir, fetch_git_diff, read_review_notes, system_info
|
|
201
|
+
- execute # EXECUTE: python_code, shell_command, run_script
|
|
202
|
+
- write # WRITE: write_file, patch_file, add_review_note
|
|
203
|
+
# - delete # DELETE: no tools currently mapped
|
|
204
|
+
# - all # ALL: grants all permissions
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Permission Levels
|
|
208
|
+
|
|
209
|
+
| Permission | Tools Granted |
|
|
210
|
+
|-----------|---------------|
|
|
211
|
+
| `read` | `read_file`, `list_dir`, `search_files`, `search_dir`, `fetch_git_diff`, `system_info`, `osv_cve_scan` |
|
|
212
|
+
| `write` | `write_file`, `patch_file` |
|
|
213
|
+
| `execute` | `python_code`, `shell_command`, `run_script` |
|
|
214
|
+
| `delete` | *(no tools currently)* |
|
|
215
|
+
| `all` | All permissions |
|
|
216
|
+
|
|
217
|
+
### Key Settings
|
|
218
|
+
|
|
219
|
+
- **`context_window`**: Maximum token budget for the conversation context.
|
|
220
|
+
- **`compaction_threshold`**: Ratio of context window at which compaction triggers (e.g., `0.8` = compact at 80%).
|
|
221
|
+
- **`tool_budget`**: Maximum number of tool calls the agent can make in a single turn before responding.
|
|
222
|
+
- **`permissions`**: List of permission levels granted to the agent. The `chat --full` CLI flag automatically adds `WRITE` permission.
|
|
223
|
+
|
|
224
|
+
### Environment Variables
|
|
225
|
+
|
|
226
|
+
Values in `config.yaml` can reference environment variables using `${VAR_NAME}` syntax. For example:
|
|
227
|
+
|
|
228
|
+
```yaml
|
|
229
|
+
provider:
|
|
230
|
+
api_key: "${OPENAI_API_KEY}"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Supported formats: `${VAR}`, `${VAR:-default}`, and standard shell variable expansion.
|
|
234
|
+
|
|
235
|
+
## License
|
|
236
|
+
|
|
237
|
+
MIT
|
regcode-0.4.1/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# RegCode
|
|
2
|
+
|
|
3
|
+
A minimalistic coding agent with Python API bindings and CLI interface.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **litellm** as the LLM backbone (supports OpenAI, Anthropic, and 100+ providers)
|
|
8
|
+
- **YAML configuration** for model, tokens, temperature, and provider settings via Pydantic models
|
|
9
|
+
- **Environment variable expansion** in config values (e.g., `${OPENAI_API_KEY}`)
|
|
10
|
+
- **CLI** via click: `chat`, `configure`, `version`
|
|
11
|
+
- **Python API**: `import regcode; agent = regcode.Agent()`
|
|
12
|
+
- **Host filesystem I/O**: `write_file` and `patch_file` operate directly on the host filesystem with path traversal protection
|
|
13
|
+
- **Robust tool call handling**: malformed tool calls and JSON parse errors are gracefully handled
|
|
14
|
+
- **Progressive streaming**: TUI always streams assistant responses progressively rather than all at once
|
|
15
|
+
- **Context window compaction**: Automatically compacts conversation history when approaching token limits, preserving system instructions and review notes
|
|
16
|
+
- **Review notes**: Persistent findings stored across context compaction sessions
|
|
17
|
+
- **Tool budget limits**: Configurable maximum number of tool calls per conversation turn
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Install dependencies
|
|
23
|
+
uv sync
|
|
24
|
+
|
|
25
|
+
# Configure your API key (or set OPENAI_API_KEY in your environment)
|
|
26
|
+
# Edit config.yaml or use environment variables
|
|
27
|
+
|
|
28
|
+
# Chat with the agent (uses Textual TUI)
|
|
29
|
+
uv run regcode chat
|
|
30
|
+
|
|
31
|
+
# Interactive config generator
|
|
32
|
+
uv run regcode configure
|
|
33
|
+
|
|
34
|
+
# View version
|
|
35
|
+
uv run regcode version
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## CLI Chat Options
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Full agent mode (enables write permissions)
|
|
42
|
+
uv run regcode chat --full
|
|
43
|
+
|
|
44
|
+
# Use a specific model
|
|
45
|
+
uv run regcode chat --model "openai/gpt-4o"
|
|
46
|
+
|
|
47
|
+
# Disable colored output
|
|
48
|
+
uv run regcode chat --no-color
|
|
49
|
+
|
|
50
|
+
# Use a custom config file
|
|
51
|
+
uv run regcode chat --config /path/to/config.yaml
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## TUI Slash Commands
|
|
55
|
+
|
|
56
|
+
While chatting, you can use these slash commands in the input bar:
|
|
57
|
+
|
|
58
|
+
- `/exit` or `/quit` — Quit the application
|
|
59
|
+
- `/clear` — Clear the chat history
|
|
60
|
+
- `/reset` — Reset the session (clear history and tools)
|
|
61
|
+
|
|
62
|
+
## Usage as a Library
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import regcode
|
|
66
|
+
|
|
67
|
+
# Load config (reads config.yaml, falls back to ~/.regcode/config.yaml, then defaults)
|
|
68
|
+
config = regcode.Config.load("config.yaml")
|
|
69
|
+
|
|
70
|
+
# Create agent
|
|
71
|
+
agent = regcode.Agent(config=config)
|
|
72
|
+
|
|
73
|
+
# Chat (TUI always streams responses progressively)
|
|
74
|
+
reply = agent.chat("Refactor this function to use async/await.")
|
|
75
|
+
print(reply)
|
|
76
|
+
|
|
77
|
+
# Reset conversation
|
|
78
|
+
agent.reset()
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Tools
|
|
82
|
+
|
|
83
|
+
RegCode includes several built-in tools the agent can use:
|
|
84
|
+
|
|
85
|
+
| Tool | Permission | Description |
|
|
86
|
+
|------|-----------|-------------|
|
|
87
|
+
| `python_code` | `EXECUTE` | Execute Python code in an isolated Monty sandbox with Rust-based security and resource limits |
|
|
88
|
+
| `shell_command` | `EXECUTE` | Execute shell commands (subprocess, not sandbox). Only safe, read-only commands are allowed (ls, cat, echo, head, tail, wc, grep, sort, uniq, date, pwd, whoami, id, uname, df, free, which, type, stat, file, sha256sum, md5sum, base64, xxd, od, hexdump, find) |
|
|
89
|
+
| `run_script` | `EXECUTE` | Execute a Python script file in the Monty sandbox |
|
|
90
|
+
| `read_file` | `READ` | Read the contents of a file from the filesystem |
|
|
91
|
+
| `write_file` | `WRITE` | Write content to a file on the host filesystem |
|
|
92
|
+
| `patch_file` | `WRITE` | Replace a range of lines in an existing file |
|
|
93
|
+
| `list_dir` | `READ` | List contents of a directory |
|
|
94
|
+
| `search_files` | `READ` | Search for files matching a pattern |
|
|
95
|
+
| `search_dir` | `READ` | Search for a pattern inside all files within a directory |
|
|
96
|
+
| `fetch_git_diff` | `READ` | Fetch the git diff of the current repository |
|
|
97
|
+
| `osv_cve_scan` | `READ` | Scan project dependencies for known CVEs via OSV.dev API. Optionally scans the codebase for vulnerable usage patterns |
|
|
98
|
+
| `system_info` | `READ` | Get system information (OS, Python version, etc.) |
|
|
99
|
+
|
|
100
|
+
> **Note**: `browse_dir` is defined in the codebase but **not included in the default tools**. It can be explicitly registered if needed, but is excluded by default because it recursively lists all files in a directory, which can fill the context window in large projects (e.g., `.venv`, `node_modules`).
|
|
101
|
+
|
|
102
|
+
All file-writing tools (`write_file`, `patch_file`) include path traversal protection (`..` is blocked). The `patch_file` tool validates line number bounds and type correctness before performing the replacement.
|
|
103
|
+
|
|
104
|
+
## Project Structure
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
project-root/
|
|
108
|
+
├── main.py # Unused stub (hello world only)
|
|
109
|
+
├── config.yaml # Runtime configuration
|
|
110
|
+
├── config.yaml.template # Template for new configs
|
|
111
|
+
├── pyproject.toml # Project metadata and dependencies
|
|
112
|
+
├── uv.lock # Locked dependencies
|
|
113
|
+
└── regcode/ # Python package
|
|
114
|
+
├── __init__.py # Python API entry point
|
|
115
|
+
├── main.py # Agent core (chat, review, etc.)
|
|
116
|
+
├── cli.py # CLI entry point (click)
|
|
117
|
+
├── config.py # Config loader (yaml + pydantic)
|
|
118
|
+
├── permissions.py # Tool permission definitions
|
|
119
|
+
├── tui.py # Textual-based terminal UI
|
|
120
|
+
├── conversation_manager.py # Context compaction & review notes
|
|
121
|
+
├── sandbox.py # Legacy sandbox support
|
|
122
|
+
├── monty_sandbox.py # Monty sandbox integration
|
|
123
|
+
└── tools/
|
|
124
|
+
├── __init__.py
|
|
125
|
+
├── base.py # Base tool classes
|
|
126
|
+
├── builtins.py # Built-in tool implementations
|
|
127
|
+
├── registry.py # Tool registry management
|
|
128
|
+
└── review_notes.py # Review notes persistence
|
|
129
|
+
├── tests/
|
|
130
|
+
│ ├── conftest.py
|
|
131
|
+
│ ├── test_main.py
|
|
132
|
+
│ ├── test_config.py
|
|
133
|
+
│ ├── test_api.py
|
|
134
|
+
│ ├── test_cli.py
|
|
135
|
+
│ ├── test_context_manager.py
|
|
136
|
+
│ ├── test_monty_sandbox.py
|
|
137
|
+
│ ├── test_provider_extra.py
|
|
138
|
+
│ └── test_review_notes.py
|
|
139
|
+
└── README.md
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Testing & Linting
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
uv run pytest tests/ -v
|
|
146
|
+
uv run ruff check --fix regcode/ tests/
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Configuration
|
|
150
|
+
|
|
151
|
+
Edit `config.yaml` to customize the agent's behavior. The config is loaded from the specified path, `~/.regcode/config.yaml`, or falls back to defaults.
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
agent:
|
|
155
|
+
context_window: 128000 # Maximum context window size
|
|
156
|
+
compaction_threshold: 0.8 # Compact when context > 80% of window
|
|
157
|
+
enable_compaction: true # Enable automatic context compaction
|
|
158
|
+
|
|
159
|
+
provider:
|
|
160
|
+
model: "openai/gpt-4o" # Model identifier (litellm format)
|
|
161
|
+
base_url: "https://api.openai.com/v1"
|
|
162
|
+
api_key: "${OPENAI_API_KEY}" # Environment variable expansion supported
|
|
163
|
+
temperature: 1.0
|
|
164
|
+
max_tokens: 4096
|
|
165
|
+
|
|
166
|
+
system_prompt: | # Custom system prompt (default is provided)
|
|
167
|
+
You are a coding agent.
|
|
168
|
+
|
|
169
|
+
tools: {} # Reserved for future tool configuration
|
|
170
|
+
|
|
171
|
+
sandbox:
|
|
172
|
+
use_monty: true # Enable Monty sandbox for Python execution
|
|
173
|
+
max_duration_secs: 10.0
|
|
174
|
+
max_memory_mb: 64
|
|
175
|
+
max_recursion_depth: 100
|
|
176
|
+
type_check: true
|
|
177
|
+
allowed_imports: []
|
|
178
|
+
|
|
179
|
+
tool_budget: 20 # Max tool calls per agent turn
|
|
180
|
+
|
|
181
|
+
permissions:
|
|
182
|
+
- read # READ: read_file, list_dir, search_files, search_dir, browse_dir, fetch_git_diff, read_review_notes, system_info
|
|
183
|
+
- execute # EXECUTE: python_code, shell_command, run_script
|
|
184
|
+
- write # WRITE: write_file, patch_file, add_review_note
|
|
185
|
+
# - delete # DELETE: no tools currently mapped
|
|
186
|
+
# - all # ALL: grants all permissions
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Permission Levels
|
|
190
|
+
|
|
191
|
+
| Permission | Tools Granted |
|
|
192
|
+
|-----------|---------------|
|
|
193
|
+
| `read` | `read_file`, `list_dir`, `search_files`, `search_dir`, `fetch_git_diff`, `system_info`, `osv_cve_scan` |
|
|
194
|
+
| `write` | `write_file`, `patch_file` |
|
|
195
|
+
| `execute` | `python_code`, `shell_command`, `run_script` |
|
|
196
|
+
| `delete` | *(no tools currently)* |
|
|
197
|
+
| `all` | All permissions |
|
|
198
|
+
|
|
199
|
+
### Key Settings
|
|
200
|
+
|
|
201
|
+
- **`context_window`**: Maximum token budget for the conversation context.
|
|
202
|
+
- **`compaction_threshold`**: Ratio of context window at which compaction triggers (e.g., `0.8` = compact at 80%).
|
|
203
|
+
- **`tool_budget`**: Maximum number of tool calls the agent can make in a single turn before responding.
|
|
204
|
+
- **`permissions`**: List of permission levels granted to the agent. The `chat --full` CLI flag automatically adds `WRITE` permission.
|
|
205
|
+
|
|
206
|
+
### Environment Variables
|
|
207
|
+
|
|
208
|
+
Values in `config.yaml` can reference environment variables using `${VAR_NAME}` syntax. For example:
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
provider:
|
|
212
|
+
api_key: "${OPENAI_API_KEY}"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Supported formats: `${VAR}`, `${VAR:-default}`, and standard shell variable expansion.
|
|
216
|
+
|
|
217
|
+
## License
|
|
218
|
+
|
|
219
|
+
MIT
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "regcode"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
description = "Minimalistic coding agent with Python API and CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
7
7
|
dependencies = [
|
|
8
|
+
"crawl4ai>=0.4.0",
|
|
8
9
|
"litellm>=1.83.17",
|
|
9
10
|
"pydantic-settings>=2.14.2",
|
|
10
11
|
"pyyaml>=6.0",
|
|
@@ -13,15 +14,16 @@ dependencies = [
|
|
|
13
14
|
"ruff>=0.8",
|
|
14
15
|
"pydantic-monty>=0.0.18",
|
|
15
16
|
"textual>=8.2.7",
|
|
17
|
+
"mlflow>=3.14.0",
|
|
16
18
|
]
|
|
17
19
|
|
|
18
|
-
[build-system]
|
|
19
|
-
requires = ["hatchling"]
|
|
20
|
-
build-backend = "hatchling.build"
|
|
21
|
-
|
|
22
20
|
[project.scripts]
|
|
23
21
|
regcode = "regcode.cli:cli"
|
|
24
22
|
|
|
23
|
+
[build-system]
|
|
24
|
+
requires = ["hatchling", "setuptools"]
|
|
25
|
+
build-backend = "hatchling.build"
|
|
26
|
+
|
|
25
27
|
[project.optional-dependencies]
|
|
26
28
|
dev = []
|
|
27
29
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import sys
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
@@ -5,9 +6,14 @@ import click
|
|
|
5
6
|
import yaml
|
|
6
7
|
|
|
7
8
|
import regcode
|
|
9
|
+
from regcode.dependencies import ensure_playwright_browsers
|
|
8
10
|
from regcode.permissions import AgentPermission
|
|
9
11
|
from regcode.tui import ChatUI
|
|
10
12
|
|
|
13
|
+
# Configure logging
|
|
14
|
+
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")
|
|
15
|
+
_logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
11
17
|
|
|
12
18
|
def _confirm(prompt_text):
|
|
13
19
|
"""Ask yes/no question, accepting y/n (case insensitive)."""
|
|
@@ -43,6 +49,14 @@ def cli(ctx):
|
|
|
43
49
|
)
|
|
44
50
|
def chat(model, config_path, stream, full, no_color):
|
|
45
51
|
"""Chat with the agent using a Textual TUI with sticky bottom bar."""
|
|
52
|
+
# Ensure Playwright browsers are available for web_crawl tool
|
|
53
|
+
_logger.info("Checking startup dependencies...")
|
|
54
|
+
if not ensure_playwright_browsers():
|
|
55
|
+
_logger.warning(
|
|
56
|
+
"Playwright browsers are not available. "
|
|
57
|
+
"The web_crawl tool will not function."
|
|
58
|
+
)
|
|
59
|
+
|
|
46
60
|
# Pass None if the file doesn't exist so Config.load falls back
|
|
47
61
|
# to ~/.regcode/config.yaml (matching the TUI's expected behaviour).
|
|
48
62
|
_effective_path = config_path if Path(config_path).exists() else None
|
|
@@ -61,6 +75,7 @@ def chat(model, config_path, stream, full, no_color):
|
|
|
61
75
|
status_callback=ui.handle_status,
|
|
62
76
|
result_callback=ui.handle_result,
|
|
63
77
|
context_callback=ui.set_context_progress,
|
|
78
|
+
cost_callback=ui.handle_cost,
|
|
64
79
|
)
|
|
65
80
|
|
|
66
81
|
# Attach agent to the Textual app
|
|
@@ -44,7 +44,15 @@ default_system_prompt = dedent(
|
|
|
44
44
|
logger = logging.getLogger(__name__)
|
|
45
45
|
|
|
46
46
|
class AgentConfig(BaseModel):
|
|
47
|
-
|
|
47
|
+
"""Configuration specific to the agent's behavior (not provider params).
|
|
48
|
+
|
|
49
|
+
Model, temperature, max_tokens belong in ProviderConfig where
|
|
50
|
+
litellm.completion expects them. AgentConfig only holds compaction
|
|
51
|
+
and context-window tuning — passing model params through this object
|
|
52
|
+
caused conflicts with different providers.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
model_config = ConfigDict(extra="forbid")
|
|
48
56
|
context_window: int = 128000
|
|
49
57
|
compaction_threshold: float = 0.8 # Compact when context > 80% of window
|
|
50
58
|
enable_compaction: bool = True
|
|
@@ -81,11 +89,30 @@ class SandboxConfig(BaseModel):
|
|
|
81
89
|
type_check: bool = True
|
|
82
90
|
allowed_imports: list[str] = []
|
|
83
91
|
|
|
92
|
+
class TracingConfig(BaseModel):
|
|
93
|
+
"""Configuration for tracing and logging."""
|
|
94
|
+
|
|
95
|
+
model_config = ConfigDict(extra="allow")
|
|
96
|
+
enable_tracing: bool = False
|
|
97
|
+
mlflow_url: str | None = None
|
|
98
|
+
mlflow_experiment_name: str | None = None
|
|
99
|
+
mlflow_async: bool = True
|
|
100
|
+
mlflow_requires_auth: bool = True
|
|
101
|
+
mlflow_username: str | None = None
|
|
102
|
+
mlflow_password: str | None = None
|
|
103
|
+
|
|
104
|
+
def tracing_enabled(self) -> bool:
|
|
105
|
+
"""Check if tracing is fully configured and enabled."""
|
|
106
|
+
return (
|
|
107
|
+
self.enable_tracing
|
|
108
|
+
and self.mlflow_url is not None
|
|
109
|
+
)
|
|
84
110
|
|
|
85
111
|
class Config(BaseModel):
|
|
86
112
|
model_config = ConfigDict(extra="allow")
|
|
87
113
|
|
|
88
114
|
agent: AgentConfig = AgentConfig()
|
|
115
|
+
tracing: TracingConfig = TracingConfig()
|
|
89
116
|
provider: ProviderConfig = ProviderConfig()
|
|
90
117
|
system_prompt: str = default_system_prompt
|
|
91
118
|
tools: dict = {}
|
|
@@ -96,19 +123,29 @@ class Config(BaseModel):
|
|
|
96
123
|
@classmethod
|
|
97
124
|
def load(cls, path: str | None = None) -> "Config":
|
|
98
125
|
# get default home dir for user first
|
|
126
|
+
_path = None
|
|
99
127
|
if path is None:
|
|
100
|
-
|
|
101
|
-
"
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
128
|
+
possible_paths = [
|
|
129
|
+
Path("./config.yaml"), Path.home() / ".regcode" / "config.yaml"
|
|
130
|
+
]
|
|
131
|
+
for p in possible_paths:
|
|
132
|
+
if p.exists():
|
|
133
|
+
logger.info(f"Loading from config at {p}")
|
|
134
|
+
_path = p
|
|
135
|
+
break
|
|
136
|
+
if _path is None:
|
|
137
|
+
logger.warning(
|
|
138
|
+
"No config file found, using default config, "
|
|
139
|
+
"Use `regcode configure` to configure."
|
|
140
|
+
)
|
|
141
|
+
return cls()
|
|
109
142
|
else:
|
|
110
143
|
_path = Path(path)
|
|
111
144
|
if not _path.exists():
|
|
145
|
+
logger.warning(
|
|
146
|
+
f"Config file {path} not found, using default config, "
|
|
147
|
+
"Use `regcode configure` to configure."
|
|
148
|
+
)
|
|
112
149
|
return cls()
|
|
113
150
|
with open(_path) as f:
|
|
114
151
|
data = yaml.safe_load(f)
|
|
@@ -135,17 +172,6 @@ class Config(BaseModel):
|
|
|
135
172
|
result = self.provider.model_dump()
|
|
136
173
|
if extra_kwargs:
|
|
137
174
|
result.update(extra_kwargs)
|
|
138
|
-
# Agent-level config overrides provider defaults for known keys
|
|
139
|
-
if self.agent.context_window is not None:
|
|
140
|
-
result["context_window"] = self.agent.context_window
|
|
141
|
-
if hasattr(self.agent, "compaction_threshold"):
|
|
142
|
-
result["compaction_threshold"] = self.agent.compaction_threshold
|
|
143
|
-
if hasattr(self.agent, "enable_compaction"):
|
|
144
|
-
result["enable_compaction"] = self.agent.enable_compaction
|
|
145
|
-
# Apply agent-level extra fields (e.g. model, max_tokens, temperature
|
|
146
|
-
# from YAML agent section) as overrides over provider defaults
|
|
147
|
-
if hasattr(self.agent, "model_extra") and self.agent.model_extra:
|
|
148
|
-
result.update(self.agent.model_extra)
|
|
149
175
|
return result
|
|
150
176
|
|
|
151
177
|
|