kin: KIN-016 Агенты должны уметь говорить 'не могу'. Если агент не может выполнить задачу (нет доступа, не понимает, выходит за компетенцию) — он должен вернуть status: blocked с причиной, а не пытаться угадывать. PM при получении blocked от агента — эскалирует к человеку через GUI (уведомление) и Telegram (когда будет).

This commit is contained in:
Gros Frumos 2026-03-16 09:13:34 +02:00
parent a605e9d110
commit d9172fc17c
35 changed files with 2375 additions and 23 deletions

View file

@ -96,6 +96,74 @@ def project_add(ctx, id, name, path, tech_stack, status, priority, language):
click.echo(f"Created project: {p['id']} ({p['name']})")
@cli.command("new-project")
@click.argument("description")
@click.option("--id", "project_id", required=True, help="Project ID")
@click.option("--name", required=True, help="Project name")
@click.option("--path", required=True, help="Project path")
@click.option("--roles", default="business,market,tech", show_default=True,
help="Comma-separated roles: business,market,legal,tech,ux,marketer")
@click.option("--tech-stack", default=None, help="Comma-separated tech stack")
@click.option("--priority", type=int, default=5, show_default=True)
@click.option("--language", default="ru", show_default=True)
@click.pass_context
def new_project(ctx, description, project_id, name, path, roles, tech_stack, priority, language):
"""Create a new project with a sequential research phase pipeline.
DESCRIPTION free-text project description for the agents.
Role aliases: business=business_analyst, market=market_researcher,
legal=legal_researcher, tech=tech_researcher, ux=ux_designer, marketer=marketer.
Architect is added automatically as the last phase.
"""
from core.phases import create_project_with_phases, validate_roles, ROLE_LABELS
_ALIASES = {
"business": "business_analyst",
"market": "market_researcher",
"legal": "legal_researcher",
"tech": "tech_researcher",
"ux": "ux_designer",
}
raw_roles = [r.strip().lower() for r in roles.split(",") if r.strip()]
expanded = [_ALIASES.get(r, r) for r in raw_roles]
clean_roles = validate_roles(expanded)
if not clean_roles:
click.echo("Error: no valid research roles specified.", err=True)
raise SystemExit(1)
ts = [s.strip() for s in tech_stack.split(",") if s.strip()] if tech_stack else None
conn = ctx.obj["conn"]
if models.get_project(conn, project_id):
click.echo(f"Error: project '{project_id}' already exists.", err=True)
raise SystemExit(1)
try:
result = create_project_with_phases(
conn, project_id, name, path,
description=description,
selected_roles=clean_roles,
tech_stack=ts,
priority=priority,
language=language,
)
except ValueError as e:
click.echo(f"Error: {e}", err=True)
raise SystemExit(1)
click.echo(f"Created project: {result['project']['id']} ({result['project']['name']})")
click.echo(f"Description: {description}")
click.echo("")
phases = result["phases"]
rows = [
[str(p["id"]), str(p["phase_order"] + 1), p["role"], p["status"], p.get("task_id") or ""]
for p in phases
]
click.echo(_table(["ID", "#", "Role", "Status", "Task"], rows))
@project.command("list")
@click.option("--status", default=None)
@click.pass_context