Add permission-aware follow-up flow with interactive resolution
When follow-up agent detects permission-blocked items ("ручное
применение", "permission denied", etc.), they become pending_actions
instead of auto-created tasks. User chooses per item:
1. Rerun with --dangerously-skip-permissions
2. Create manual task
3. Skip
core/followup.py:
_is_permission_blocked() — regex detection of 9 permission patterns
generate_followups() returns {created, pending_actions}
resolve_pending_action() — handles rerun/manual_task/skip
agents/runner.py:
_run_claude(allow_write=True) adds --dangerously-skip-permissions
run_agent/run_pipeline pass allow_write through
CLI: kin approve --followup — interactive 1/2/3 prompt per blocked item
API: POST /approve returns {needs_decision, pending_actions}
POST /resolve resolves individual actions
Frontend: pending actions shown as cards with 3 buttons in approve modal
136 tests, all passing. Frontend builds clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9264415776
commit
ab693d3c4d
7 changed files with 356 additions and 73 deletions
29
web/api.py
29
web/api.py
|
|
@ -203,16 +203,43 @@ def approve_task(task_id: str, body: TaskApprove | None = None):
|
|||
task_id=task_id,
|
||||
)
|
||||
followup_tasks = []
|
||||
pending_actions = []
|
||||
if body and body.create_followups:
|
||||
followup_tasks = generate_followups(conn, task_id)
|
||||
result = generate_followups(conn, task_id)
|
||||
followup_tasks = result["created"]
|
||||
pending_actions = result["pending_actions"]
|
||||
conn.close()
|
||||
return {
|
||||
"status": "done",
|
||||
"decision": decision,
|
||||
"followup_tasks": followup_tasks,
|
||||
"needs_decision": len(pending_actions) > 0,
|
||||
"pending_actions": pending_actions,
|
||||
}
|
||||
|
||||
|
||||
class ResolveAction(BaseModel):
|
||||
action: dict
|
||||
choice: str # "rerun" | "manual_task" | "skip"
|
||||
|
||||
|
||||
@app.post("/api/tasks/{task_id}/resolve")
|
||||
def resolve_action(task_id: str, body: ResolveAction):
|
||||
"""Resolve a pending permission action from follow-up generation."""
|
||||
from core.followup import resolve_pending_action
|
||||
|
||||
if body.choice not in ("rerun", "manual_task", "skip"):
|
||||
raise HTTPException(400, f"Invalid choice: {body.choice}")
|
||||
conn = get_conn()
|
||||
t = models.get_task(conn, task_id)
|
||||
if not t:
|
||||
conn.close()
|
||||
raise HTTPException(404, f"Task '{task_id}' not found")
|
||||
result = resolve_pending_action(conn, task_id, body.action, body.choice)
|
||||
conn.close()
|
||||
return {"choice": body.choice, "result": result}
|
||||
|
||||
|
||||
class TaskReject(BaseModel):
|
||||
reason: str
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue