mirror of
https://github.com/val1813/kwcode.git
synced 2026-09-11 02:21:21 +08:00
feat: GapDetector AST存根扫描 + Generator whole_file 4096 tokens + Reviewer阈值0.7
- GapDetector._scan_stubs_in_files(): 纯AST扫描pass/raise存根,输出完整target_functions - Generator: scope=whole_file时base_tokens提升到4096 - Reviewer闭环:confidence>=0.7时返回None重入retry,强制重新定位 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -165,6 +165,10 @@ class GapDetector:
|
||||
def _build_not_implemented_gap(self, output: str, project_root: str) -> Gap:
|
||||
files = self._extract_error_files(output)
|
||||
functions = self._extract_function_names(output)
|
||||
# AST存根扫描:找到所有pass函数,提供完整target_functions
|
||||
stub_functions = self._scan_stubs_in_files(files, project_root)
|
||||
if stub_functions:
|
||||
functions = stub_functions
|
||||
return Gap(
|
||||
GapType.NOT_IMPLEMENTED, 0.9,
|
||||
files, functions, output[:200],
|
||||
@@ -174,6 +178,10 @@ class GapDetector:
|
||||
def _build_stub_none_gap(self, output: str, project_root: str) -> Gap:
|
||||
files = self._extract_error_files(output)
|
||||
functions = self._extract_function_names(output)
|
||||
# AST存根扫描
|
||||
stub_functions = self._scan_stubs_in_files(files, project_root)
|
||||
if stub_functions:
|
||||
functions = stub_functions
|
||||
return Gap(
|
||||
GapType.STUB_RETURNS_NONE, 0.85,
|
||||
files, functions, output[:200],
|
||||
@@ -235,3 +243,55 @@ class GapDetector:
|
||||
'run', 'main', '__init__', 'execute'}
|
||||
result = [f for f in functions if f not in skip and not f.startswith('test_')]
|
||||
return list(set(result))[:5]
|
||||
|
||||
def _scan_stubs_in_files(self, files: list[str], project_root: str) -> list[str]:
|
||||
"""AST扫描文件中的pass/raise NotImplementedError存根函数。"""
|
||||
import ast as _ast
|
||||
stub_functions = []
|
||||
for fpath in files[:3]:
|
||||
# 构建绝对路径
|
||||
if not os.path.isabs(fpath):
|
||||
fpath = os.path.join(project_root, fpath)
|
||||
if not os.path.exists(fpath) or not fpath.endswith('.py'):
|
||||
continue
|
||||
try:
|
||||
with open(fpath, encoding='utf-8', errors='ignore') as f:
|
||||
source = f.read()
|
||||
tree = _ast.parse(source)
|
||||
except Exception:
|
||||
continue
|
||||
for node in _ast.walk(tree):
|
||||
if not isinstance(node, (_ast.FunctionDef, _ast.AsyncFunctionDef)):
|
||||
continue
|
||||
if node.name.startswith('__') and node.name.endswith('__'):
|
||||
continue
|
||||
if self._is_stub_body(node.body):
|
||||
stub_functions.append(node.name)
|
||||
return stub_functions
|
||||
|
||||
@staticmethod
|
||||
def _is_stub_body(body: list) -> bool:
|
||||
"""判断函数体是否是存根。"""
|
||||
import ast as _ast
|
||||
if not body:
|
||||
return True
|
||||
# 跳过docstring
|
||||
real_body = body
|
||||
if (len(body) >= 1 and isinstance(body[0], _ast.Expr) and
|
||||
isinstance(body[0].value, _ast.Constant) and
|
||||
isinstance(body[0].value.value, str)):
|
||||
real_body = body[1:]
|
||||
if not real_body:
|
||||
return True
|
||||
if len(real_body) == 1:
|
||||
stmt = real_body[0]
|
||||
if isinstance(stmt, _ast.Pass):
|
||||
return True
|
||||
if isinstance(stmt, _ast.Raise):
|
||||
return True
|
||||
if isinstance(stmt, _ast.Expr) and isinstance(stmt.value, _ast.Constant):
|
||||
if stmt.value.value is ...:
|
||||
return True
|
||||
if isinstance(stmt, _ast.Return) and stmt.value is None:
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -676,11 +676,11 @@ class PipelineOrchestrator:
|
||||
"""Record success: memory, registry, trajectory, AB, value, milestone, reflection."""
|
||||
# Reviewer: 需求对齐审查 — 不对齐返回None让调用方重试
|
||||
review_result = self._do_review(ctx, on_status)
|
||||
if review_result and not review_result.get("aligned") and review_result.get("confidence", 0) >= 0.6:
|
||||
if review_result and not review_result.get("aligned") and review_result.get("confidence", 0) >= 0.7:
|
||||
gap = review_result.get("gap", "")
|
||||
self._emit(on_status, "review_reject", f"审查不通过:{gap}")
|
||||
# 把gap作为retry_hint注入,让Generator下次修正
|
||||
ctx.retry_hint = f"上次修改审查不通过:{gap}。请重新修改确保满足用户需求。"
|
||||
ctx.retry_hint = f"改错了:{gap}"
|
||||
ctx.locator_output = None # 强制重新定位修复
|
||||
return None # 返回None信号给retry loop
|
||||
|
||||
checkpoint.discard() # 审查通过才清理快照
|
||||
|
||||
@@ -393,6 +393,11 @@ class GeneratorExpert:
|
||||
|
||||
# AdaptThink: 根据think_config调整max_tokens
|
||||
base_tokens = 2048
|
||||
# scope=whole_file时提升token预算(需要实现多个函数)
|
||||
if ctx.gap and hasattr(ctx.gap, 'gap_type'):
|
||||
from kaiwu.core.gap_detector import GapType
|
||||
if ctx.gap.gap_type in (GapType.NOT_IMPLEMENTED, GapType.STUB_RETURNS_NONE):
|
||||
base_tokens = 4096
|
||||
think_cfg = getattr(ctx, 'think_config', {})
|
||||
if think_cfg.get("think") and self.llm._is_reasoning:
|
||||
base_tokens += think_cfg.get("budget", 0)
|
||||
|
||||
Reference in New Issue
Block a user