mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-05 07:41:39 +00:00
feat(kanban): add initial-status for human-ops cards
Salvages #27526 by @shunsuke-hikiyama. Adds an --initial-status flag (running|blocked, default running) to 'kanban create', threaded through kanban_db.create_task() and the kanban_create tool schema. 'blocked' parks the task directly in the blocked column for R3 human-ops review, skipping the brief running-to-blocked transition. Dropped the unrelated 'add' alias, WIFEXITED Windows compat, and slash-handler error formatting changes that were bundled in the original PR — those should ship as their own focused changes if still wanted.
This commit is contained in:
parent
e8ce7b83fa
commit
fb96208892
3 changed files with 40 additions and 8 deletions
|
|
@ -305,6 +305,12 @@ def build_parser(parent_subparsers: argparse._SubParsersAction) -> argparse.Argu
|
|||
"two retries. Omit to use the dispatcher's "
|
||||
"kanban.failure_limit config "
|
||||
f"(default {kb.DEFAULT_FAILURE_LIMIT}).")
|
||||
p_create.add_argument("--initial-status",
|
||||
choices=sorted(kb.VALID_INITIAL_STATUSES),
|
||||
default="running",
|
||||
help="Initial card status. Use 'blocked' for cards "
|
||||
"that require immediate human ops (R3 gate) "
|
||||
"to skip the brief running-to-blocked transition.")
|
||||
p_create.add_argument("--json", action="store_true", help="Emit JSON output")
|
||||
|
||||
# --- list ---
|
||||
|
|
@ -1173,6 +1179,7 @@ def _cmd_create(args: argparse.Namespace) -> int:
|
|||
max_runtime_seconds=max_runtime,
|
||||
skills=getattr(args, "skills", None) or None,
|
||||
max_retries=max_retries,
|
||||
initial_status=getattr(args, "initial_status", "running"),
|
||||
)
|
||||
task = kb.get_task(conn, task_id)
|
||||
if getattr(args, "json", False):
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@ from toolsets import get_toolset_names
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
VALID_STATUSES = {"triage", "todo", "scheduled", "ready", "running", "blocked", "done", "archived"}
|
||||
VALID_INITIAL_STATUSES = {"running", "blocked"}
|
||||
VALID_WORKSPACE_KINDS = {"scratch", "worktree", "dir"}
|
||||
KNOWN_TOOLSET_NAMES = frozenset(name.casefold() for name in get_toolset_names())
|
||||
_IS_WINDOWS = sys.platform == "win32"
|
||||
|
|
@ -1307,6 +1308,7 @@ def create_task(
|
|||
max_runtime_seconds: Optional[int] = None,
|
||||
skills: Optional[Iterable[str]] = None,
|
||||
max_retries: Optional[int] = None,
|
||||
initial_status: str = "running",
|
||||
board: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Create a new task and optionally link it under parent tasks.
|
||||
|
|
@ -1336,6 +1338,10 @@ def create_task(
|
|||
assignee = _canonical_assignee(assignee)
|
||||
if not title or not title.strip():
|
||||
raise ValueError("title is required")
|
||||
if initial_status not in VALID_INITIAL_STATUSES:
|
||||
raise ValueError(
|
||||
f"initial_status must be one of {sorted(VALID_INITIAL_STATUSES)}"
|
||||
)
|
||||
if workspace_kind not in VALID_WORKSPACE_KINDS:
|
||||
raise ValueError(
|
||||
f"workspace_kind must be one of {sorted(VALID_WORKSPACE_KINDS)}, "
|
||||
|
|
@ -1419,12 +1425,19 @@ def create_task(
|
|||
task_id = _new_task_id()
|
||||
try:
|
||||
with write_txn(conn):
|
||||
# Determine initial status from parent status, unless the
|
||||
# caller is parking this task in triage for a specifier.
|
||||
if triage:
|
||||
initial_status = "triage"
|
||||
# Determine task status from parent status, unless the caller
|
||||
# parks it directly in blocked for human-ops review or in
|
||||
# triage for a specifier.
|
||||
if initial_status == "blocked":
|
||||
task_status = "blocked"
|
||||
if parents:
|
||||
missing = _find_missing_parents(conn, parents)
|
||||
if missing:
|
||||
raise ValueError(f"unknown parent task(s): {', '.join(missing)}")
|
||||
elif triage:
|
||||
task_status = "triage"
|
||||
else:
|
||||
initial_status = "ready"
|
||||
task_status = "ready"
|
||||
if parents:
|
||||
missing = _find_missing_parents(conn, parents)
|
||||
if missing:
|
||||
|
|
@ -1436,7 +1449,7 @@ def create_task(
|
|||
parents,
|
||||
).fetchall()
|
||||
if any(r["status"] != "done" for r in rows):
|
||||
initial_status = "todo"
|
||||
task_status = "todo"
|
||||
# Even in triage mode we still need to validate parent ids
|
||||
# so the eventual link rows don't dangle.
|
||||
if triage and parents:
|
||||
|
|
@ -1458,7 +1471,7 @@ def create_task(
|
|||
title.strip(),
|
||||
body,
|
||||
assignee,
|
||||
initial_status,
|
||||
task_status,
|
||||
priority,
|
||||
created_by,
|
||||
now,
|
||||
|
|
@ -1482,7 +1495,7 @@ def create_task(
|
|||
"created",
|
||||
{
|
||||
"assignee": assignee,
|
||||
"status": initial_status,
|
||||
"status": task_status,
|
||||
"parents": list(parents),
|
||||
"tenant": tenant,
|
||||
"skills": list(skills_list) if skills_list else None,
|
||||
|
|
|
|||
|
|
@ -632,6 +632,7 @@ def _handle_create(args: dict, **kw) -> str:
|
|||
return tool_error(bool_error)
|
||||
idempotency_key = args.get("idempotency_key")
|
||||
max_runtime_seconds = args.get("max_runtime_seconds")
|
||||
initial_status = args.get("initial_status") or "running"
|
||||
skills = args.get("skills")
|
||||
if isinstance(skills, str):
|
||||
# Accept a single skill name as a string for convenience.
|
||||
|
|
@ -666,6 +667,7 @@ def _handle_create(args: dict, **kw) -> str:
|
|||
if max_runtime_seconds is not None else None
|
||||
),
|
||||
skills=skills,
|
||||
initial_status=str(initial_status),
|
||||
created_by=os.environ.get("HERMES_PROFILE") or "worker",
|
||||
)
|
||||
new_task = kb.get_task(conn, new_tid)
|
||||
|
|
@ -1077,6 +1079,16 @@ KANBAN_CREATE_SCHEMA = {
|
|||
"task with outcome='timed_out'."
|
||||
),
|
||||
},
|
||||
"initial_status": {
|
||||
"type": "string",
|
||||
"enum": ["running", "blocked"],
|
||||
"description": (
|
||||
"Initial card status. Use 'blocked' for tasks that "
|
||||
"require immediate human ops (R3 gate) to skip the "
|
||||
"brief running-to-blocked transition. Defaults to "
|
||||
"'running', which preserves the usual dispatch path."
|
||||
),
|
||||
},
|
||||
"skills": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue