regcode 0.6.0__tar.gz → 0.6.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.
- regcode-0.6.2/.gitlab-ci.yml +67 -0
- {regcode-0.6.0 → regcode-0.6.2}/GOALS.md +33 -3
- {regcode-0.6.0 → regcode-0.6.2}/PKG-INFO +2 -2
- {regcode-0.6.0 → regcode-0.6.2}/pyproject.toml +2 -2
- {regcode-0.6.0 → regcode-0.6.2}/regcode/__init__.py +1 -1
- {regcode-0.6.0 → regcode-0.6.2}/regcode/main.py +52 -2
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tracing.py +17 -7
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tui.py +273 -284
- regcode-0.6.2/tests/conftest.py +37 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_context_manager.py +1 -1
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_osv_cve.py +98 -55
- {regcode-0.6.0 → regcode-0.6.2}/uv.lock +5 -5
- regcode-0.6.0/tests/conftest.py +0 -7
- {regcode-0.6.0 → regcode-0.6.2}/.gitignore +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/.python-version +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/.qwen/settings.json +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/AGENTS.md +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/README.md +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/config.yaml.template +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/main.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/cli.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/config.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/conversation_manager.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/dependencies.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/monty_sandbox.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/permissions.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/sandbox.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/__init__.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/base.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/builtins.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/registry.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/review_notes.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/web_crawl.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/regcode/tools/web_search.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/__init__.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_api.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_cli.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_config.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_dependencies.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_main.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_monty_sandbox.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_provider_extra.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_review_notes.py +0 -0
- {regcode-0.6.0 → regcode-0.6.2}/tests/test_web_search.py +0 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# .gitlab-ci.yml
|
|
2
|
+
|
|
3
|
+
stages:
|
|
4
|
+
- test
|
|
5
|
+
- build
|
|
6
|
+
- publish
|
|
7
|
+
|
|
8
|
+
variables:
|
|
9
|
+
UV_PIP_PREVENT_WRITE_BACK: "1"
|
|
10
|
+
|
|
11
|
+
lint:
|
|
12
|
+
stage: test
|
|
13
|
+
image: python:3.12-slim
|
|
14
|
+
before_script:
|
|
15
|
+
- pip install uv
|
|
16
|
+
script:
|
|
17
|
+
- uv venv .venv
|
|
18
|
+
- source .venv/bin/activate
|
|
19
|
+
- uv pip install ".[dev]"
|
|
20
|
+
- uv run ruff check regcode/ tests/
|
|
21
|
+
|
|
22
|
+
pytest:
|
|
23
|
+
stage: test
|
|
24
|
+
image: python:3.12-slim
|
|
25
|
+
before_script:
|
|
26
|
+
- pip install uv
|
|
27
|
+
script:
|
|
28
|
+
- uv venv .venv
|
|
29
|
+
- source .venv/bin/activate
|
|
30
|
+
- uv pip install ".[dev]"
|
|
31
|
+
- uv run pytest tests/ -v --tb=short
|
|
32
|
+
|
|
33
|
+
build:
|
|
34
|
+
stage: build
|
|
35
|
+
image: python:3.12-slim
|
|
36
|
+
before_script:
|
|
37
|
+
- pip install uv
|
|
38
|
+
script:
|
|
39
|
+
- uv build
|
|
40
|
+
artifacts:
|
|
41
|
+
paths:
|
|
42
|
+
- dist/
|
|
43
|
+
expire_in: 1 week
|
|
44
|
+
rules:
|
|
45
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
46
|
+
changes:
|
|
47
|
+
paths:
|
|
48
|
+
- "regcode/**/*"
|
|
49
|
+
- "pyproject.toml"
|
|
50
|
+
when: on_success
|
|
51
|
+
- when: never
|
|
52
|
+
|
|
53
|
+
publish:
|
|
54
|
+
stage: publish
|
|
55
|
+
image: python:3.12-slim
|
|
56
|
+
before_script:
|
|
57
|
+
- pip install uv
|
|
58
|
+
script:
|
|
59
|
+
- uv publish --token $UV_PUBLISH_TOKEN
|
|
60
|
+
rules:
|
|
61
|
+
- if: $CI_COMMIT_BRANCH == "main"
|
|
62
|
+
changes:
|
|
63
|
+
paths:
|
|
64
|
+
- "regcode/**/*"
|
|
65
|
+
- "pyproject.toml"
|
|
66
|
+
when: on_success
|
|
67
|
+
- when: never
|
|
@@ -497,7 +497,7 @@ All phases complete. 50/50 tests passing. Lint clean.
|
|
|
497
497
|
|
|
498
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
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
|
|
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 RichLog widget and 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. RichLog renders Rich markup for colors; text selection is available via terminal scrollback. All 164 tests pass, lint clean.
|
|
501
501
|
|
|
502
502
|
3. ✅ **WebSearchTool** — New `regcode/tools/web_search.py` tool connecting to SearXNG instances. Defaults to `https://search.regmi.dev`, supports custom SearXNG URL, language code, and result count (1-20). Uses only stdlib `urllib` — no extra dependencies. Registered in `create_default_tools()`. 15 tests pass.
|
|
503
503
|
|
|
@@ -505,5 +505,35 @@ All phases complete. 50/50 tests passing. Lint clean.
|
|
|
505
505
|
|
|
506
506
|
- ✅ WebSearchTool: connects to SearXNG, defaults to https://search.regmi.dev, no extra deps needed
|
|
507
507
|
|
|
508
|
-
##
|
|
509
|
-
|
|
508
|
+
## Completed (2026-06-30 — TUI fixes)
|
|
509
|
+
|
|
510
|
+
1. ✅ AGENTS.md injection — Agent now reads AGENTS.md/agents.md from CWD or allowed directory and injects it into system prompt (both `_build_system_prompt` and `_build_system_prompt_no_tools`). Appended after base system_prompt, before tool descriptions.
|
|
511
|
+
|
|
512
|
+
2. ✅ TUI text selectability — Replaced RichLog with TextArea for the chat area. TextArea is the only Textual widget with real text selection and copy support (`action_copy`, `action_select_all`, `selected_text`). All write paths use `_append_text()` which converts Rich markup to ANSI escape codes via Rich's `Console.print()`, so text displays with colors AND remains selectable/copyable.
|
|
513
|
+
|
|
514
|
+
3. ✅ Context window config — Hardcoded `_context_window: int = 128000` replaced with 0 default, with fallback chain in `_update_progress()`: `_context_window` → `self._agent.config.agent.context_window` → 128000.
|
|
515
|
+
|
|
516
|
+
4. ✅ Hardcoded context window — Fixed `_update_progress()` to check `self._agent.config.agent.context_window` before falling back to 128000.
|
|
517
|
+
|
|
518
|
+
## Completed (2026-06-30 — TUI overhaul)
|
|
519
|
+
|
|
520
|
+
- ✅ `tui.py` rewritten: 3-zone layout (status bar, chat area, input bar). Chat area uses TextArea (selectable/copyable) instead of RichLog. All Rich markup tags are stripped before insertion so text is readable. Agent runs in background thread, callbacks use `call_from_thread`.
|
|
521
|
+
- ✅ All 164 tests pass, lint clean.
|
|
522
|
+
|
|
523
|
+
## Completed (2026-06-30 — TUI cleanup)
|
|
524
|
+
|
|
525
|
+
1. ✅ **Added `textual>=2.0.0` dependency** — was imported but missing from `pyproject.toml`.
|
|
526
|
+
2. ✅ **Replaced top-bar `TextArea` with `Label`** — the status bar only displays plain text; Label is lighter-weight and semantically correct. Same for progress bar widget.
|
|
527
|
+
3. ✅ **Simplified streaming state machine** — reduced from 7 state variables (`_streaming`, `_streaming_started`, `_stream_pending`, `_stream_has_label`, `_stream_line_open`, `_stream_trim_leading`, `_current_response`) and 5 flushing methods down to 2 (`_streaming`, `_current_response`) and 1 flush method (`_flush_stream_for_status`). The old code buffered partial lines with complex state tracking; the new approach simply accumulates chunks in `_current_response` and flushes them as a single block when needed.
|
|
528
|
+
4. ✅ **Optimized `_rich_to_ansi`** — replaced per-call `Console()` instantiation with a cached `_rich_console` instance created once in `__init__`, eliminating redundant object allocation on every text write.
|
|
529
|
+
5. ✅ **All 164 tests pass**, lint clean.
|
|
530
|
+
|
|
531
|
+
## Completed (2026-06-30 — TUI rewrite)
|
|
532
|
+
|
|
533
|
+
Complete rewrite of `tui.py` from scratch using Textual's `RichLog` widget instead of `TextArea`:
|
|
534
|
+
|
|
535
|
+
1. ✅ **`RichLog` instead of `TextArea`** — RichLog natively renders Rich markup (`[bold]`, `[dim]`, etc.) so no fragile Rich→ANSI conversion is needed. Users see properly colored, styled text. RichLog also supports scrollback selection/copy via terminal features.
|
|
536
|
+
2. ✅ **Clean Catppuccin Mocha dark theme** — uses the Catppuccin color palette (`#1e1e2e` background, `#cdd6f4` text, `#313244` surfaces, `#89b4fa` accents) for a modern, polished look.
|
|
537
|
+
3. ✅ **Proper three-zone layout** — status bar (version | model | cost | tokens), scrollable chat history, bottom input bar with progress indicator. No raw markup tags visible.
|
|
538
|
+
4. ✅ **Same backward-compatible API** — `ChatUI` facade, `ChatApp` class, `_ColorFormatter`, all callback methods (`handle_status`, `handle_result`, `handle_cost`, `print_text_chunk`, etc.) preserved exactly as before for CLI integration.
|
|
539
|
+
5. ✅ **All 164 tests pass**, lint clean.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: regcode
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.2
|
|
4
4
|
Summary: Minimalistic coding agent with Python API and CLI
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: click>=8.0
|
|
@@ -12,7 +12,7 @@ Requires-Dist: pydantic-settings>=2.14.2
|
|
|
12
12
|
Requires-Dist: pytest>=8.0
|
|
13
13
|
Requires-Dist: pyyaml>=6.0
|
|
14
14
|
Requires-Dist: ruff>=0.8
|
|
15
|
-
Requires-Dist: textual>=
|
|
15
|
+
Requires-Dist: textual>=2.0.0
|
|
16
16
|
Provides-Extra: dev
|
|
17
17
|
Description-Content-Type: text/markdown
|
|
18
18
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "regcode"
|
|
3
|
-
version = "0.6.
|
|
3
|
+
version = "0.6.2"
|
|
4
4
|
description = "Minimalistic coding agent with Python API and CLI"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -13,8 +13,8 @@ dependencies = [
|
|
|
13
13
|
"pytest>=8.0",
|
|
14
14
|
"ruff>=0.8",
|
|
15
15
|
"pydantic-monty>=0.0.18",
|
|
16
|
-
"textual>=8.2.7",
|
|
17
16
|
"mlflow>=3.14.0",
|
|
17
|
+
"textual>=2.0.0",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
[project.scripts]
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import warnings
|
|
7
|
+
from datetime import datetime, timezone
|
|
7
8
|
from enum import Enum
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Any, Callable
|
|
@@ -444,11 +445,48 @@ class Agent:
|
|
|
444
445
|
self._history = [m for m in messages if m.get("role") != "system"]
|
|
445
446
|
return final_text or response_message.get("content", "") or ""
|
|
446
447
|
|
|
448
|
+
@staticmethod
|
|
449
|
+
def _read_agents_md(directory: str | None = None) -> str:
|
|
450
|
+
"""Read AGENTS.md from the given directory if it exists.
|
|
451
|
+
|
|
452
|
+
Returns the file contents with a header, or an empty string if
|
|
453
|
+
the file is not found.
|
|
454
|
+
"""
|
|
455
|
+
search_dirs: list[Path] = []
|
|
456
|
+
if directory:
|
|
457
|
+
search_dirs.append(Path(directory))
|
|
458
|
+
search_dirs.append(Path.cwd())
|
|
459
|
+
for candidate in search_dirs:
|
|
460
|
+
for name in ("AGENTS.md", "agents.md", "Agents.md"):
|
|
461
|
+
p = candidate / name
|
|
462
|
+
if p.exists():
|
|
463
|
+
try:
|
|
464
|
+
return p.read_text(encoding="utf-8")
|
|
465
|
+
except OSError:
|
|
466
|
+
continue
|
|
467
|
+
return ""
|
|
468
|
+
|
|
447
469
|
def _build_system_prompt(self) -> str:
|
|
448
470
|
"""Build the full system prompt including tool definitions."""
|
|
471
|
+
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
472
|
+
date_section = f"\n\nCurrent time: {now}\n"
|
|
473
|
+
agents_md = self._read_agents_md(self._allowed_dir)
|
|
474
|
+
agents_md_section = ""
|
|
475
|
+
if agents_md:
|
|
476
|
+
agents_md_section = (
|
|
477
|
+
f"\n\n{'=' * 60}\n"
|
|
478
|
+
"AGENT INSTRUCTIONS (injected from AGENTS.md):\n"
|
|
479
|
+
f"{'=' * 60}\n\n{agents_md}"
|
|
480
|
+
)
|
|
449
481
|
tool_descriptions = self._format_tool_descriptions()
|
|
450
482
|
notes_section = self._format_review_notes()
|
|
451
|
-
return
|
|
483
|
+
return (
|
|
484
|
+
f"{self.system_prompt}"
|
|
485
|
+
f"{date_section}"
|
|
486
|
+
f"{agents_md_section}"
|
|
487
|
+
f"{tool_descriptions}"
|
|
488
|
+
f"{notes_section}"
|
|
489
|
+
)
|
|
452
490
|
|
|
453
491
|
def _build_system_prompt_no_tools(self) -> str:
|
|
454
492
|
"""Build the system prompt WITHOUT tool definitions.
|
|
@@ -460,7 +498,19 @@ class Agent:
|
|
|
460
498
|
stripped, because the accumulated review findings remain relevant
|
|
461
499
|
context for the LLM's final response.
|
|
462
500
|
"""
|
|
463
|
-
|
|
501
|
+
now = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S UTC")
|
|
502
|
+
date_section = f"\n\nCurrent time: {now}\n"
|
|
503
|
+
agents_md = self._read_agents_md(self._allowed_dir)
|
|
504
|
+
agents_md_section = ""
|
|
505
|
+
if agents_md:
|
|
506
|
+
agents_md_section = (
|
|
507
|
+
f"\n\n{'=' * 60}\n"
|
|
508
|
+
"AGENT INSTRUCTIONS (injected from AGENTS.md):\n"
|
|
509
|
+
f"{'=' * 60}\n\n{agents_md}"
|
|
510
|
+
)
|
|
511
|
+
parts = [self.system_prompt, date_section, agents_md_section]
|
|
512
|
+
parts.append(self._format_review_notes())
|
|
513
|
+
return "".join(parts)
|
|
464
514
|
|
|
465
515
|
def _stream(
|
|
466
516
|
self,
|
|
@@ -39,9 +39,17 @@ def _initialize_tracing(config: Config | None = None) -> None:
|
|
|
39
39
|
if not _tracing_config.tracing_enabled():
|
|
40
40
|
return
|
|
41
41
|
|
|
42
|
-
if
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
if (
|
|
43
|
+
_tracing_config.mlflow_requires_auth
|
|
44
|
+
and _tracing_config.mlflow_username
|
|
45
|
+
and _tracing_config.mlflow_password
|
|
46
|
+
):
|
|
47
|
+
MLFLOW_TRACKING_USERNAME.set(
|
|
48
|
+
_tracing_config.mlflow_username
|
|
49
|
+
)
|
|
50
|
+
MLFLOW_TRACKING_PASSWORD.set(
|
|
51
|
+
_tracing_config.mlflow_password
|
|
52
|
+
)
|
|
45
53
|
|
|
46
54
|
_logger.info(f"Setting up MLflow tracing with URL: {_tracing_config.mlflow_url}")
|
|
47
55
|
|
|
@@ -76,14 +84,16 @@ def agent_trace(user_message: str, tool_calls_count: int = 0) -> Iterator[None]:
|
|
|
76
84
|
with agent_trace("Fix the bug", 3):
|
|
77
85
|
result = agent.chat("Fix the bug")
|
|
78
86
|
"""
|
|
79
|
-
if
|
|
87
|
+
if (
|
|
88
|
+
not _tracing_initialized
|
|
89
|
+
or not _tracing_config
|
|
90
|
+
or not _tracing_config.tracing_enabled()
|
|
91
|
+
):
|
|
80
92
|
yield
|
|
81
93
|
return
|
|
82
94
|
|
|
83
|
-
trace_name = f"agent.turn.{tool_calls_count}tools"
|
|
84
|
-
|
|
85
95
|
try:
|
|
86
|
-
with mlflow.start_trace()
|
|
96
|
+
with mlflow.start_trace():
|
|
87
97
|
# Log input attributes for better trace UI
|
|
88
98
|
mlflow.set_tag("user_message", user_message[:200])
|
|
89
99
|
mlflow.set_tag("tool_calls", tool_calls_count)
|