diff --git a/repair_agent/agent/claude_service.py b/repair_agent/agent/claude_service.py index 753b253..ec9c0bc 100644 --- a/repair_agent/agent/claude_service.py +++ b/repair_agent/agent/claude_service.py @@ -197,6 +197,8 @@ class ClaudeService: ## 判断规则 +### 运行时错误(runtime) + 属于 **无法复现 / 不需要修复** 的情况(CANNOT_REPRODUCE): 1. JWT Token 过期、认证失败 — 正常认证流程,不是代码 Bug 2. HTTP 405 Method Not Allowed — 客户端请求了错误的方法 @@ -210,6 +212,19 @@ class ClaudeService: 2. 数据库约束错误(IntegrityError)由项目代码逻辑引起 3. TypeError / AttributeError 出现在项目视图或模型中 +### CI/CD 构建错误(CICDFailure) + +属于 **需要修复** 的情况(FIX): +1. Docker build 失败且日志中包含代码编译/语法错误(SyntaxError、ImportError、ModuleNotFoundError 等) +2. npm/pip install 成功但 build 阶段因代码问题失败 +3. Dockerfile 中 RUN 命令因项目代码问题报错 + +属于 **无法复现 / 不需要修复** 的情况(CANNOT_REPRODUCE): +1. Docker 镜像仓库认证失败、推送失败 — 基础设施问题 +2. kubectl 部署失败、K8s 资源不足 — 运维问题 +3. 网络超时、镜像拉取失败 — 瞬态错误 +4. 日志中没有具体代码错误,只有通用构建/部署失败信息 + 请先用 Grep/Read 查看相关源文件确认当前代码状态,然后给出判断。 **最后一行必须输出以下格式之一(只输出一个):** diff --git a/repair_agent/agent/task_manager.py b/repair_agent/agent/task_manager.py index 59f1f95..1fae198 100644 --- a/repair_agent/agent/task_manager.py +++ b/repair_agent/agent/task_manager.py @@ -28,9 +28,60 @@ class TaskManager: """ all_bugs: dict[int, Bug] = {} - for status in ("NEW", "PENDING_FIX"): + for source in ("runtime", "cicd", "deployment"): + for status in ("NEW", "PENDING_FIX"): + try: + params: dict[str, str] = {"status": status, "source": source} + if project_id: + params["project_id"] = project_id + + response = self.client.get( + f"{self.base_url}/api/v1/bugs", + params=params, + ) + response.raise_for_status() + + data = response.json() + for item in data.get("items", []): + bug_id = item["id"] + if bug_id in all_bugs: + continue + + stack_trace = item.get("stack_trace") + if isinstance(stack_trace, str): + stack_trace = stack_trace.split("\n") + + all_bugs[bug_id] = Bug( + id=bug_id, + project_id=item["project_id"], + environment=item.get("environment", "production"), + level=item.get("level", "ERROR"), + error={ + "type": item.get("error_type", "Unknown"), + "message": item.get("error_message", ""), + "file_path": item.get("file_path"), + "line_number": item.get("line_number"), + "stack_trace": stack_trace, + }, + context=item.get("context"), + status=BugStatus(item.get("status", "NEW")), + retry_count=item.get("retry_count", 0), + ) + except httpx.HTTPError as e: + logger.error(f"获取 {source}/{status} 状态 Bug 列表失败: {e}") + + bugs = list(all_bugs.values()) + logger.info(f"获取到 {len(bugs)} 个待修复 Bug(runtime + cicd + deployment)") + return bugs + + def fetch_failed_bugs(self, project_id: Optional[str] = None) -> list[Bug]: + """ + 获取修复失败的 Bug 列表(FIX_FAILED 状态,所有来源) + """ + all_bugs: dict[int, Bug] = {} + for source in ("runtime", "cicd", "deployment"): try: - params: dict[str, str] = {"status": status, "source": "runtime"} + params: dict[str, str] = {"status": "FIX_FAILED", "source": source} if project_id: params["project_id"] = project_id @@ -51,7 +102,7 @@ class TaskManager: stack_trace = stack_trace.split("\n") all_bugs[bug_id] = Bug( - id=bug_id, + id=item["id"], project_id=item["project_id"], environment=item.get("environment", "production"), level=item.get("level", "ERROR"), @@ -63,57 +114,13 @@ class TaskManager: "stack_trace": stack_trace, }, context=item.get("context"), - status=BugStatus(item.get("status", "NEW")), + status=BugStatus.FIX_FAILED, retry_count=item.get("retry_count", 0), ) except httpx.HTTPError as e: - logger.error(f"获取 {status} 状态 Bug 列表失败: {e}") + logger.error(f"获取 {source}/FIX_FAILED Bug 列表失败: {e}") bugs = list(all_bugs.values()) - logger.info(f"获取到 {len(bugs)} 个待修复 Bug(NEW + PENDING_FIX)") - return bugs - - def fetch_failed_bugs(self, project_id: Optional[str] = None) -> list[Bug]: - """ - 获取修复失败的 Bug 列表(FIX_FAILED 状态) - """ - bugs: list[Bug] = [] - try: - params: dict[str, str] = {"status": "FIX_FAILED", "source": "runtime"} - if project_id: - params["project_id"] = project_id - - response = self.client.get( - f"{self.base_url}/api/v1/bugs", - params=params, - ) - response.raise_for_status() - - data = response.json() - for item in data.get("items", []): - stack_trace = item.get("stack_trace") - if isinstance(stack_trace, str): - stack_trace = stack_trace.split("\n") - - bugs.append(Bug( - id=item["id"], - project_id=item["project_id"], - environment=item.get("environment", "production"), - level=item.get("level", "ERROR"), - error={ - "type": item.get("error_type", "Unknown"), - "message": item.get("error_message", ""), - "file_path": item.get("file_path"), - "line_number": item.get("line_number"), - "stack_trace": stack_trace, - }, - context=item.get("context"), - status=BugStatus.FIX_FAILED, - retry_count=item.get("retry_count", 0), - )) - except httpx.HTTPError as e: - logger.error(f"获取 FIX_FAILED Bug 列表失败: {e}") - logger.info(f"获取到 {len(bugs)} 个 FIX_FAILED Bug") return bugs