diff --git a/pipeline_service/agent_loop.py b/pipeline_service/agent_loop.py index 48d2e87..05d896f 100644 --- a/pipeline_service/agent_loop.py +++ b/pipeline_service/agent_loop.py @@ -624,6 +624,16 @@ async def _create_next_task(sor, project_id, task, next_role, pm_comment=''): return new_task_id, new_title +def _task_iteration_name(task): + """提取任务的迭代名(params.iteration_id,存的是迭代名称非 id)。""" + params_str = getattr(task, 'params', '{}') or '{}' + try: + params = json.loads(params_str) if isinstance(params_str, str) else params_str + return (params.get('iteration_id') or '').strip() + except (json.JSONDecodeError, TypeError): + return '' + + # ── Agent 工具执行 ── def _parse_agent_action(raw): @@ -1166,6 +1176,17 @@ async def pm_review_run(project_id, agent_id=None, model_name=None): await approve_task(task_id, project_id, who="agent.pm", agent_id=agent_id, comment=comment) next_role = await _get_next_role(task_role, project_id) if next_role: + # 迭代边界:任务若归属老迭代(非当前迭代=该项目最新创建的迭代), + # 链到此终止,不再自动触发下一角色任务——「新迭代创建后老迭代不再产生新任务」。 + task_iter = _task_iteration_name(task) + if task_iter: + cur = await sor.sqlExe( + "SELECT iteration_name FROM sd_iterations WHERE project_id=${pid}$ ORDER BY created_at DESC LIMIT 1", + {"pid": project_id}) + cur_name = getattr(cur[0], 'iteration_name', '') if cur else '' + if cur_name and task_iter != cur_name: + logger.info(f"迭代边界:任务 {task_id} 归属老迭代「{task_iter}」(当前「{cur_name}」),链终止") + return {"status": "completed", "task_id": task_id, "comment": comment or "迭代已结束,链终止"} next_tid, next_title = await _create_next_task(sor, project_id, task, next_role, comment) return {"status": "approved", "task_id": task_id, "next_task_id": next_tid, "next_role": next_role, "comment": comment} else: