adjust new core classes for CI (#43)

* add README for CI tool
* adjust new core classes for CI
This commit is contained in:
XianBW
2024-07-03 16:34:47 +08:00
committed by GitHub
parent 833e7ce1b9
commit ab2f61fe9d
2 changed files with 78 additions and 23 deletions
+38
View File
@@ -0,0 +1,38 @@
# CI 检查
`.github/workflows/ci.yml`配置了提交时自动运行`Makefile`: 91~103行的命令,可以在这调整执行的命令
`.env`中设置`USE_CHAT_CACHE=True`可以让第二次修复快一些
# Rules
`pyproject.toml`中配置全局屏蔽的规则
- ruff: `[tool.ruff.lint].ignore`
- mypy: `[tool.mypy]`
## ruff rules
ruff rules 比较好修改, 大多可以自动修复
对于一些规则可以在代码中添加注释来局部屏蔽, 例如添加 `# noqa E234,ANN001`
遇到的不好修改的规则:
- 捕获异常时应该处理每一种异常,不应该统一当作`Exception`处理
- `subprogress()` 调用命令应该先判断命令是否安全
- ...
规则列表: [ruff rules](https://docs.astral.sh/ruff/rules/)
## mypy rules
Mypy检查Python中类型标注, 常遇到需要修改结构/同时修改其他文件的情况, 自动修复效果不好
局部屏蔽: `# type: ignore`
规则列表: [mypy rules](https://mypy.readthedocs.io/en/stable/error_code_list.html)
# Optimization (Maybe)
- 添加指定文件夹检查的功能
- 增加一个修改选项: 调用`vim`, 用户直接修改此部分代码
- 显示时把`Original Code`部分去掉, 直接在输出的表示修改的diff部分用`^^^^^^`在代码行下标注出错误位置,这样能更直观地观察错误修复情况
- 当前为线性执行完所有修复后交给用户检查, 可修改成 后台多线程 / 进程处理修复的任务, 终端实时展示处理完的修复让用户检查
- ...
+40 -23
View File
@@ -13,16 +13,6 @@ from pathlib import Path
from typing import Any, Literal
import tree_sitter_python
from rich import print
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn
from rich.prompt import Prompt
from rich.rule import Rule
from rich.syntax import Syntax
from rich.table import Table
from rich.text import Text
from tree_sitter import Language, Node, Parser
from rdagent.core.evaluation import Evaluator
from rdagent.core.evolving_agent import EvoAgent
from rdagent.core.evolving_framework import (
@@ -34,6 +24,15 @@ from rdagent.core.evolving_framework import (
)
from rdagent.core.prompts import Prompts
from rdagent.oai.llm_utils import APIBackend
from rich import print
from rich.panel import Panel
from rich.progress import Progress, SpinnerColumn, TimeElapsedColumn
from rich.prompt import Prompt
from rich.rule import Rule
from rich.syntax import Syntax
from rich.table import Table
from rich.text import Text
from tree_sitter import Language, Node, Parser
py_parser = Parser(Language(tree_sitter_python.language()))
CI_prompts = Prompts(file_path=Path(__file__).parent / "prompts.yaml")
@@ -304,7 +303,7 @@ class RuffEvaluator(Evaluator):
return RuffRule(**json.loads(out))
def evaluate(self, evo: Repo, **kwargs: Any) -> CIFeedback: # noqa: ARG002
def evaluate(self, evo: Repo, **kwargs: dict) -> CIFeedback:
"""Simply run ruff to get the feedbacks."""
try:
out = subprocess.check_output(
@@ -356,13 +355,14 @@ class RuffEvaluator(Evaluator):
class MypyEvaluator(Evaluator):
def __init__(self, command: str | None = None) -> None:
if command is None:
self.command = "mypy . --pretty --no-error-summary --show-column-numbers"
else:
self.command = command
def evaluate(self, evo: Repo, **kwargs: Any) -> CIFeedback: # noqa: ARG002
def evaluate(self, evo: Repo, **kwargs: dict) -> CIFeedback:
try:
out = subprocess.check_output(
shlex.split(self.command), # noqa: S603
@@ -411,10 +411,12 @@ class MypyEvaluator(Evaluator):
class MultiEvaluator(Evaluator):
def __init__(self, *evaluators: Evaluator) -> None:
self.evaluators = evaluators
def evaluate(self, evo: Repo, **kwargs: Any) -> CIFeedback:
def evaluate(self, evo: Repo, **kwargs: dict) -> CIFeedback:
all_errors = defaultdict(list)
for evaluator in self.evaluators:
feedback: CIFeedback = evaluator.evaluate(evo, **kwargs)
@@ -433,9 +435,10 @@ class CIEvoStr(EvolvingStrategy):
self,
evo: Repo,
evolving_trace: list[EvoStep] | None = None,
knowledge_l: list[Knowledge] | None = None, # noqa: ARG002
**kwargs: Any, # noqa: ARG002
knowledge_l: list[Knowledge] | None = None,
**kwargs: dict,
) -> Repo:
@dataclass
class CodeFixGroup:
start_line: int
@@ -549,7 +552,7 @@ class CIEvoStr(EvolvingStrategy):
style="bright_blue",
align="left",
characters=".",
)
),
)
file = evo.files[evo.project_path / Path(file_path)]
@@ -630,12 +633,12 @@ class CIEvoStr(EvolvingStrategy):
for i in diff:
if i.startswith("+"):
table.add_row(
"", Text(str(diff_new_lineno), style="green bold"), Text(i, style="green")
"", Text(str(diff_new_lineno), style="green bold"), Text(i, style="green"),
)
diff_new_lineno += 1
elif i.startswith("-"):
table.add_row(
Text(str(diff_original_lineno), style="red bold"), "", Text(i, style="red")
Text(str(diff_original_lineno), style="red bold"), "", Text(i, style="red"),
)
diff_original_lineno += 1
elif i.startswith("?"):
@@ -655,7 +658,7 @@ class CIEvoStr(EvolvingStrategy):
operation = Prompt.ask(
"Input your operation [ [red]([bold]s[/bold])kip[/red] / "
"[green]([bold]a[/bold])pply[/green] / "
"[yellow]manual instruction[/yellow] ]"
"[yellow]manual instruction[/yellow] ]",
)
print()
if operation in ("s", "skip"):
@@ -688,6 +691,21 @@ class CIEvoStr(EvolvingStrategy):
return evo
class CIEvoAgent(EvoAgent):
def __init__(self, evolving_strategy: CIEvoStr) -> None:
super().__init__(max_loop=1, evolving_strategy=evolving_strategy)
self.evolving_trace = []
def multistep_evolve(self, evo: Repo, eva: Evaluator, **kwargs: Any) -> Repo:
evo = self.evolving_strategy.evolve(
evo=evo,
evolving_trace=self.evolving_trace,
)
self.evolving_trace.append(EvoStep(evo, feedback=eva.evaluate(evo)))
return evo
DIR = None
while DIR is None or not DIR.exists():
@@ -707,12 +725,11 @@ repo = Repo(DIR, excludes=excludes)
# evaluator = MultiEvaluator(MypyEvaluator(), RuffEvaluator())
evaluator = RuffEvaluator()
estr = CIEvoStr()
rag = None # RAG is not enable firstly.
ea = EvoAgent(estr, rag=rag)
ea.step_evolving(repo, evaluator)
ea = CIEvoAgent(estr)
ea.multistep_evolve(repo, evaluator)
while True:
print(Rule(f"Round {len(ea.evolving_trace)} repair", style="blue"))
repo: Repo = ea.step_evolving(repo, evaluator)
repo: Repo = ea.multistep_evolve(repo, evaluator)
fix_records = repo.fix_records
filename = f"{DIR.name}_{start_timestamp}_round_{len(ea.evolving_trace)}_fix_records.json"