regcode 0.10.0__tar.gz → 0.12.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 (53) hide show
  1. {regcode-0.10.0 → regcode-0.12.0}/GOALS.md +64 -0
  2. regcode-0.10.0/README.md → regcode-0.12.0/PKG-INFO +41 -0
  3. regcode-0.10.0/PKG-INFO → regcode-0.12.0/README.md +18 -22
  4. {regcode-0.10.0 → regcode-0.12.0}/pyproject.toml +2 -1
  5. {regcode-0.10.0 → regcode-0.12.0}/regcode/__init__.py +1 -1
  6. regcode-0.12.0/regcode/agents_backend.py +739 -0
  7. {regcode-0.10.0 → regcode-0.12.0}/regcode/cli.py +12 -1
  8. {regcode-0.10.0 → regcode-0.12.0}/regcode/main.py +390 -634
  9. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/builtins.py +150 -44
  10. regcode-0.12.0/tasks.md +632 -0
  11. {regcode-0.10.0 → regcode-0.12.0}/tests/conftest.py +2 -1
  12. regcode-0.12.0/tests/llm_fakes.py +187 -0
  13. {regcode-0.10.0 → regcode-0.12.0}/tests/test_clipboard.py +9 -12
  14. {regcode-0.10.0 → regcode-0.12.0}/tests/test_dependencies.py +27 -0
  15. {regcode-0.10.0 → regcode-0.12.0}/tests/test_main.py +339 -383
  16. {regcode-0.10.0 → regcode-0.12.0}/tests/test_provider_extra.py +21 -29
  17. regcode-0.12.0/tests/test_task_regression.py +463 -0
  18. {regcode-0.10.0 → regcode-0.12.0}/uv.lock +149 -4
  19. {regcode-0.10.0 → regcode-0.12.0}/.gitignore +0 -0
  20. {regcode-0.10.0 → regcode-0.12.0}/.gitlab-ci.yml +0 -0
  21. {regcode-0.10.0 → regcode-0.12.0}/.python-version +0 -0
  22. {regcode-0.10.0 → regcode-0.12.0}/.qwen/settings.json +0 -0
  23. {regcode-0.10.0 → regcode-0.12.0}/AGENTS.md +0 -0
  24. {regcode-0.10.0 → regcode-0.12.0}/config.yaml.template +0 -0
  25. {regcode-0.10.0 → regcode-0.12.0}/main.py +0 -0
  26. {regcode-0.10.0 → regcode-0.12.0}/regcode/clipboard.py +0 -0
  27. {regcode-0.10.0 → regcode-0.12.0}/regcode/config.py +0 -0
  28. {regcode-0.10.0 → regcode-0.12.0}/regcode/conversation_manager.py +0 -0
  29. {regcode-0.10.0 → regcode-0.12.0}/regcode/dependencies.py +0 -0
  30. {regcode-0.10.0 → regcode-0.12.0}/regcode/mcp_client.py +0 -0
  31. {regcode-0.10.0 → regcode-0.12.0}/regcode/monty_sandbox.py +0 -0
  32. {regcode-0.10.0 → regcode-0.12.0}/regcode/paste.py +0 -0
  33. {regcode-0.10.0 → regcode-0.12.0}/regcode/permissions.py +0 -0
  34. {regcode-0.10.0 → regcode-0.12.0}/regcode/sandbox.py +0 -0
  35. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/__init__.py +0 -0
  36. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/base.py +0 -0
  37. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/registry.py +0 -0
  38. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/review_notes.py +0 -0
  39. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/web_crawl.py +0 -0
  40. {regcode-0.10.0 → regcode-0.12.0}/regcode/tools/web_search.py +0 -0
  41. {regcode-0.10.0 → regcode-0.12.0}/regcode/tracing.py +0 -0
  42. {regcode-0.10.0 → regcode-0.12.0}/regcode/tui.py +0 -0
  43. {regcode-0.10.0 → regcode-0.12.0}/tests/__init__.py +0 -0
  44. {regcode-0.10.0 → regcode-0.12.0}/tests/test_api.py +0 -0
  45. {regcode-0.10.0 → regcode-0.12.0}/tests/test_cli.py +0 -0
  46. {regcode-0.10.0 → regcode-0.12.0}/tests/test_config.py +0 -0
  47. {regcode-0.10.0 → regcode-0.12.0}/tests/test_context_manager.py +0 -0
  48. {regcode-0.10.0 → regcode-0.12.0}/tests/test_mcp.py +0 -0
  49. {regcode-0.10.0 → regcode-0.12.0}/tests/test_mcp_status.py +0 -0
  50. {regcode-0.10.0 → regcode-0.12.0}/tests/test_monty_sandbox.py +0 -0
  51. {regcode-0.10.0 → regcode-0.12.0}/tests/test_osv_cve.py +0 -0
  52. {regcode-0.10.0 → regcode-0.12.0}/tests/test_review_notes.py +0 -0
  53. {regcode-0.10.0 → regcode-0.12.0}/tests/test_web_search.py +0 -0
@@ -581,3 +581,67 @@ mcp_servers:
581
581
  2. ✅ **TUI integration** — `_run_agent_sync()` and `_run_agent_multimodal()` now pass `on_message` callback to `agent.chat()`. The callback inserts each assistant text response directly into the chat area via `call_from_thread(self._insert_rich, text)`, so the user sees intermediate thinking ("Let me search the internet...") BEFORE tool execution markers appear. This makes the agent feel alive and responsive instead of silent during multi-tool chains.
582
582
 
583
583
  3. ✅ **All 193 tests pass, lint clean.**
584
+
585
+ ## Completed (tasks.md — upstream fixes for GitKnecht)
586
+
587
+ All twelve defects in `tasks.md` are fixed. See the ticked **Task Status** section there
588
+ for the per-task mapping to tests.
589
+
590
+ 1. ✅ **Deleted the two dead tool loops** — the real cause of most of the list was that
591
+ `Agent` carried three tool loops (`_stream`, `_chat_loop`, and the SDK path) and only
592
+ the SDK one was reachable from `chat()`. Tasks 1/2/8/9/12 were all symptoms of the same
593
+ unreachable, never-executed `_stream`. `_stream`, `_chat_loop`,
594
+ `Agent._execute_tool_calls` and `_convert_registry_tools_to_sdk_tools` are deleted;
595
+ `test_module_level_helpers_exist` pins their absence.
596
+
597
+ 2. ✅ **One implementation for both modes** — `Agent.chat()` delegates to `_run_sdk()`,
598
+ which drives the OpenAI Agents SDK `Runner` in either `run()` or `run_streamed()` form.
599
+ `RegCodeModel` (`regcode/agents_backend.py`) is now a **pure model**: one completion in,
600
+ output items out, exactly like the SDK's own `LitellmModel`. The Runner owns the tool
601
+ loop, so `max_tool_calls` (as `max_turns`), `response_format`, the budget and the
602
+ callbacks behave identically streaming or not.
603
+
604
+ 3. ✅ **Streaming actually works** — `stream_response` uses `await litellm.acompletion(
605
+ stream=True)` and hands the async iterator to `ChatCmplStreamHandler` with an empty
606
+ `Response` shell. It previously called the *sync* `completion(stream=True)` and passed
607
+ the result in twice, so `chat(stream=True)` raised
608
+ `TypeError: 'async for' requires an object with __aiter__ method, got ModelResponse`.
609
+
610
+ 4. ✅ `status_callback`/`result_callback` **never fired** — the model loop ignored them
611
+ entirely. They now fire from `_run_tool`, the single place tools execute, with
612
+ `is_error` read from `ToolResult.error`.
613
+
614
+ 5. ✅ **`FunctionTool` wrapper fixed** — it read `ctx.tool_registry` (a
615
+ `RunContextWrapper` has no such attribute) and closed over the loop variable, so every
616
+ tool would have invoked the *last* registered one. The name is now bound via a default
617
+ argument.
618
+
619
+ 6. ✅ **`directory` is now enforced** — `validate_tool_args` rejects any
620
+ `path`/`file_path`/`script_path`/`directory` argument resolving outside the root;
621
+ `shell_command` runs with `cwd=directory` and rejects absolute arguments outside it;
622
+ the CLI gained `--directory` (previously the agent was constructed with no directory at
623
+ all, so the default toolset was unconfined). README documents that `directory` is
624
+ confinement, not a sandbox.
625
+
626
+ 7. ✅ **`AGENTS.md` no longer leaks from the process cwd** — `include_cwd` defaults to
627
+ `False`, closing a prompt-injection surface where the host project's instructions were
628
+ injected into answers about an unrelated repository.
629
+
630
+ 8. ✅ **Per-iteration compaction restored** — `call_model_input_filter` on `RunConfig`
631
+ re-checks the token budget on every Runner iteration, which the SDK had silently
632
+ dropped along with the old loops.
633
+
634
+ 9. ✅ **`MaxTurnsExceeded` is handled, not fatal** — hitting the turn limit is an
635
+ expected outcome for long reviews, so the best text produced so far is recovered from
636
+ `exc.run_data` instead of crashing the caller.
637
+
638
+ 10. ✅ **Test fidelity** — `tests/llm_fakes.py` builds **real** `litellm.types.utils`
639
+ objects instead of `MagicMock`. The streaming bug survived for releases because a
640
+ `MagicMock` answered whatever the test asked it to; a response shape the SDK cannot
641
+ parse now fails the test the way it fails in production. Also fixed
642
+ `tests/test_dependencies.py`, which deleted `regcode.*` from `sys.modules` without
643
+ restoring it, so later tests received a second `AgentStatus` class and enum identity
644
+ comparisons failed purely on execution order.
645
+
646
+ 11. ✅ **270 tests pass** (up from 231), `uv run ruff check` clean.
647
+
@@ -1,3 +1,26 @@
1
+ Metadata-Version: 2.5
2
+ Name: regcode
3
+ Version: 0.12.0
4
+ Summary: Minimalistic coding agent with Python API and CLI
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: boto3>=1.43.40
7
+ Requires-Dist: click>=8.0
8
+ Requires-Dist: crawl4ai>=0.4.0
9
+ Requires-Dist: litellm>=1.83.17
10
+ Requires-Dist: mcp>=1.0.0
11
+ Requires-Dist: mlflow>=3.14.0
12
+ Requires-Dist: openai-agents>=0.18.0
13
+ Requires-Dist: pathspec>=1.1.1
14
+ Requires-Dist: pydantic-monty>=0.0.18
15
+ Requires-Dist: pydantic-settings>=2.14.2
16
+ Requires-Dist: pyperclip>=1.9.0
17
+ Requires-Dist: pytest>=8.0
18
+ Requires-Dist: pyyaml>=6.0
19
+ Requires-Dist: ruff>=0.8
20
+ Requires-Dist: textual>=2.0.0
21
+ Provides-Extra: dev
22
+ Description-Content-Type: text/markdown
23
+
1
24
  # RegCode
2
25
 
3
26
  A minimalistic coding agent with Python API bindings and CLI interface.
@@ -101,6 +124,24 @@ RegCode includes several built-in tools the agent can use:
101
124
 
102
125
  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
126
 
127
+ ### Working directory and confinement
128
+
129
+ `Agent(directory=...)` (and the CLI's `--directory`, which defaults to the current
130
+ directory) is the root every tool is confined to:
131
+
132
+ - Every path-like tool argument (`path`, `file_path`, `script_path`, `directory`) is
133
+ resolved against it and **rejected** when it resolves outside — absolute paths and
134
+ `..` escapes alike.
135
+ - `shell_command` runs with `cwd` set to it, and its arguments are checked the same way,
136
+ so `cat /etc/passwd` is rejected even though `cat` is allowlisted.
137
+ - `python_code` and `run_script` execute inside the Monty sandbox, which has no host
138
+ filesystem access at all.
139
+
140
+ > **`directory` is a confinement boundary, not a security sandbox.** `shell_command`
141
+ > still runs a real subprocess as the current user, and the toolset is only as safe as
142
+ > its permission list. Services embedding RegCode behind an authenticated endpoint should
143
+ > restrict `permissions` (or unregister tools) rather than relying on `directory` alone.
144
+
104
145
  ## Project Structure
105
146
 
106
147
  ```
@@ -1,25 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: regcode
3
- Version: 0.10.0
4
- Summary: Minimalistic coding agent with Python API and CLI
5
- Requires-Python: >=3.10
6
- Requires-Dist: boto3>=1.43.40
7
- Requires-Dist: click>=8.0
8
- Requires-Dist: crawl4ai>=0.4.0
9
- Requires-Dist: litellm>=1.83.17
10
- Requires-Dist: mcp>=1.0.0
11
- Requires-Dist: mlflow>=3.14.0
12
- Requires-Dist: pathspec>=1.1.1
13
- Requires-Dist: pydantic-monty>=0.0.18
14
- Requires-Dist: pydantic-settings>=2.14.2
15
- Requires-Dist: pyperclip>=1.9.0
16
- Requires-Dist: pytest>=8.0
17
- Requires-Dist: pyyaml>=6.0
18
- Requires-Dist: ruff>=0.8
19
- Requires-Dist: textual>=2.0.0
20
- Provides-Extra: dev
21
- Description-Content-Type: text/markdown
22
-
23
1
  # RegCode
24
2
 
25
3
  A minimalistic coding agent with Python API bindings and CLI interface.
@@ -123,6 +101,24 @@ RegCode includes several built-in tools the agent can use:
123
101
 
124
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.
125
103
 
104
+ ### Working directory and confinement
105
+
106
+ `Agent(directory=...)` (and the CLI's `--directory`, which defaults to the current
107
+ directory) is the root every tool is confined to:
108
+
109
+ - Every path-like tool argument (`path`, `file_path`, `script_path`, `directory`) is
110
+ resolved against it and **rejected** when it resolves outside — absolute paths and
111
+ `..` escapes alike.
112
+ - `shell_command` runs with `cwd` set to it, and its arguments are checked the same way,
113
+ so `cat /etc/passwd` is rejected even though `cat` is allowlisted.
114
+ - `python_code` and `run_script` execute inside the Monty sandbox, which has no host
115
+ filesystem access at all.
116
+
117
+ > **`directory` is a confinement boundary, not a security sandbox.** `shell_command`
118
+ > still runs a real subprocess as the current user, and the toolset is only as safe as
119
+ > its permission list. Services embedding RegCode behind an authenticated endpoint should
120
+ > restrict `permissions` (or unregister tools) rather than relying on `directory` alone.
121
+
126
122
  ## Project Structure
127
123
 
128
124
  ```
@@ -1,12 +1,13 @@
1
1
  [project]
2
2
  name = "regcode"
3
- version = "0.10.0"
3
+ version = "0.12.0"
4
4
  description = "Minimalistic coding agent with Python API and CLI"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  dependencies = [
8
8
  "crawl4ai>=0.4.0",
9
9
  "litellm>=1.83.17",
10
+ "openai-agents>=0.18.0",
10
11
  "pydantic-settings>=2.14.2",
11
12
  "pyyaml>=6.0",
12
13
  "click>=8.0",
@@ -2,4 +2,4 @@ from regcode.config import Config
2
2
  from regcode.main import Agent, AgentStatus, ToolCall
3
3
 
4
4
  __all__ = ["Agent", "Config", "AgentStatus", "ToolCall"]
5
- __version__ = "0.10.0"
5
+ __version__ = "0.12.0"