kin: auto-commit after pipeline
This commit is contained in:
parent
17d7806838
commit
eab9e951ab
12 changed files with 1696 additions and 5 deletions
138
agents/runner.py
138
agents/runner.py
|
|
@ -1058,6 +1058,17 @@ def _execute_department_head_step(
|
|||
# Blocked status from dept head
|
||||
if parsed.get("status") == "blocked":
|
||||
reason = parsed.get("blocked_reason", "Department head reported blocked")
|
||||
# KIN-084: log dept head blocked
|
||||
if parent_pipeline_id:
|
||||
try:
|
||||
models.write_log(
|
||||
conn, parent_pipeline_id,
|
||||
f"Dept {step['role']} blocked: {reason}",
|
||||
level="WARN",
|
||||
extra={"role": step["role"], "blocked_reason": reason},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
return {
|
||||
"success": False,
|
||||
"output": json.dumps(parsed, ensure_ascii=False),
|
||||
|
|
@ -1095,6 +1106,18 @@ def _execute_department_head_step(
|
|||
},
|
||||
}, ensure_ascii=False)
|
||||
|
||||
# KIN-084: log sub-pipeline start
|
||||
if parent_pipeline_id:
|
||||
try:
|
||||
sub_roles = [s.get("role", "") for s in sub_pipeline]
|
||||
models.write_log(
|
||||
conn, parent_pipeline_id,
|
||||
f"Sub-pipeline start: dept={dept_name}, steps={len(sub_pipeline)}",
|
||||
extra={"dept_name": dept_name, "sub_steps": len(sub_pipeline), "sub_roles": sub_roles},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Run the sub-pipeline (noninteractive=True — Opus already reviewed the plan)
|
||||
# pass parent_pipeline_id and department so run_pipeline creates the child
|
||||
# pipeline with correct attributes (route_type='dept_sub') — no double create
|
||||
|
|
@ -1108,6 +1131,19 @@ def _execute_department_head_step(
|
|||
department=dept_name,
|
||||
)
|
||||
|
||||
# KIN-084: log sub-pipeline done
|
||||
if parent_pipeline_id:
|
||||
try:
|
||||
sub_success = sub_result.get("success", False)
|
||||
models.write_log(
|
||||
conn, parent_pipeline_id,
|
||||
f"Sub-pipeline done: dept={dept_name}, success={sub_success}, steps={sub_result.get('steps_completed', 0)}",
|
||||
level="INFO" if sub_success else "ERROR",
|
||||
extra={"dept_name": dept_name, "success": sub_success, "steps_completed": sub_result.get("steps_completed", 0)},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Extract decisions from sub-pipeline results for handoff
|
||||
decisions_made = []
|
||||
sub_results = sub_result.get("results", [])
|
||||
|
|
@ -1268,6 +1304,15 @@ def run_pipeline(
|
|||
# Save PID so watchdog can detect dead subprocesses (KIN-099)
|
||||
pipeline = models.update_pipeline(conn, pipeline["id"], pid=os.getpid())
|
||||
models.update_task(conn, task_id, status="in_progress")
|
||||
# KIN-084: log pipeline start
|
||||
try:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Pipeline start: task={task_id}, steps={len(steps)}, route_type={effective_route_type}, mode={mode}",
|
||||
extra={"route_type": effective_route_type, "steps_count": len(steps), "mode": mode},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
results = []
|
||||
total_cost = 0.0
|
||||
|
|
@ -1281,6 +1326,19 @@ def run_pipeline(
|
|||
model = step.get("model", "sonnet")
|
||||
brief = step.get("brief")
|
||||
|
||||
# KIN-084: log step start
|
||||
try:
|
||||
if pipeline:
|
||||
brief_preview = (step.get("brief") or "")[:100]
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Step {i+1}/{len(steps)} start: role={role}, model={model}",
|
||||
level="INFO",
|
||||
extra={"role": role, "model": model, "brief_preview": brief_preview},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Check parent process is still alive (KIN-099 watchdog)
|
||||
if not dry_run and pipeline:
|
||||
if _check_parent_alive(conn, pipeline, task_id, project_id):
|
||||
|
|
@ -1335,6 +1393,16 @@ def run_pipeline(
|
|||
total_tokens=total_tokens,
|
||||
total_duration_seconds=total_duration,
|
||||
)
|
||||
# KIN-084: log step exception
|
||||
try:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Step {i+1}/{len(steps)} exception: {exc}",
|
||||
level="ERROR",
|
||||
extra={"role": role, "exc_type": type(exc).__name__},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
models.log_agent_run(
|
||||
conn,
|
||||
project_id=project_id,
|
||||
|
|
@ -1382,6 +1450,23 @@ def run_pipeline(
|
|||
total_tokens += result.get("tokens_used") or 0
|
||||
total_duration += result.get("duration_seconds") or 0
|
||||
|
||||
# KIN-084: log step done
|
||||
try:
|
||||
if pipeline:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Step {i+1}/{len(steps)} done: role={role}, success={result.get('success')}",
|
||||
level="INFO",
|
||||
extra={
|
||||
"role": role,
|
||||
"tokens_used": result.get("tokens_used") or 0,
|
||||
"cost_usd": result.get("cost_usd") or 0,
|
||||
"duration_seconds": result.get("duration_seconds") or 0,
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if not result["success"]:
|
||||
# Auto mode: retry once with allow_write on permission error
|
||||
if mode == "auto_complete" and not allow_write and _is_permission_error(result):
|
||||
|
|
@ -1433,6 +1518,17 @@ def run_pipeline(
|
|||
total_duration_seconds=total_duration,
|
||||
)
|
||||
agent_error = result.get("error") or ""
|
||||
# KIN-084: log step failed
|
||||
try:
|
||||
if pipeline:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Step {i+1}/{len(steps)} failed: {agent_error}",
|
||||
level="ERROR",
|
||||
extra={"role": role, "error": agent_error},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
error_msg = f"Step {i+1}/{len(steps)} ({role}) failed"
|
||||
if agent_error:
|
||||
error_msg += f": {agent_error}"
|
||||
|
|
@ -1499,6 +1595,16 @@ def run_pipeline(
|
|||
total_tokens=total_tokens,
|
||||
total_duration_seconds=total_duration,
|
||||
)
|
||||
# KIN-084: log step blocked
|
||||
try:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Step {i+1}/{len(steps)} blocked: {blocked_info['reason']}",
|
||||
level="WARN",
|
||||
extra={"role": role, "reason": blocked_info["reason"]},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
models.update_task(
|
||||
conn, task_id,
|
||||
status="blocked",
|
||||
|
|
@ -1746,6 +1852,20 @@ def run_pipeline(
|
|||
total_tokens=total_tokens,
|
||||
total_duration_seconds=total_duration,
|
||||
)
|
||||
# KIN-084: log pipeline completed
|
||||
try:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
f"Pipeline completed: {len(steps)} steps, cost=${total_cost:.4f}, tokens={total_tokens}, duration={total_duration}s",
|
||||
extra={
|
||||
"total_cost_usd": total_cost,
|
||||
"total_tokens": total_tokens,
|
||||
"total_duration_seconds": total_duration,
|
||||
"steps_count": len(steps),
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
task_modules = models.get_modules(conn, project_id)
|
||||
|
||||
|
|
@ -1771,6 +1891,15 @@ def run_pipeline(
|
|||
elif mode == "auto_complete" and auto_eligible:
|
||||
# Auto-complete mode: last step is tester/reviewer — skip review, approve immediately
|
||||
models.update_task(conn, task_id, status="done")
|
||||
# KIN-084: log task status
|
||||
try:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
"Task status: done",
|
||||
extra={"task_status": "done", "mode": mode},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
try:
|
||||
run_hooks(conn, project_id, task_id,
|
||||
event="task_auto_approved", task_modules=task_modules)
|
||||
|
|
@ -1800,6 +1929,15 @@ def run_pipeline(
|
|||
else:
|
||||
# Review mode: wait for manual approval
|
||||
models.update_task(conn, task_id, status="review", execution_mode="review")
|
||||
# KIN-084: log task status
|
||||
try:
|
||||
models.write_log(
|
||||
conn, pipeline["id"],
|
||||
"Task status: review",
|
||||
extra={"task_status": "review", "mode": mode},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Run post-pipeline hooks (failures don't affect pipeline status)
|
||||
try:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue