feat: issue-core task intake poll/claim/run (HARNESS-WP-0001-T03)

Add intake client mapping emissions to TaskSpec, CLI poll and
run --from-issue-core, keep --task-file for local dev. Completes
HARNESS-WP-0001 workplan.
This commit is contained in:
tegwick 2026-07-18 11:30:40 +02:00
parent 154e535695
commit 66ccd4fa01
7 changed files with 705 additions and 34 deletions

View file

@ -68,12 +68,123 @@ def _cmd_profiles(_args: argparse.Namespace) -> int:
return 0
def _cmd_poll(args: argparse.Namespace) -> int:
from agent_harness.intake import IntakeError, IssueCoreClient, poll_next
try:
client = IssueCoreClient()
result = poll_next(client, claim=not args.no_claim)
except IntakeError as exc:
print(f"intake error: {exc}", file=sys.stderr)
return 2
if result is None:
print(json.dumps({"queue": "empty"}, indent=2))
return 0
issue, spec = result
print(
json.dumps(
{
"issue_id": issue.issue_id,
"state": issue.state,
"title": issue.title,
"agent": spec.agent,
"target_repo": str(spec.target_repo),
"completion_event_type": spec.completion_event_type,
"labels": spec.labels,
"claimed": not args.no_claim,
},
indent=2,
)
)
return 0
def _cmd_run(args: argparse.Namespace) -> int:
from agent_harness.intake import IntakeError, IssueCoreClient, poll_next
issue_id: str | None = None
client: IssueCoreClient | None = None
if args.from_issue_core:
try:
client = IssueCoreClient()
polled = poll_next(client, claim=True)
except IntakeError as exc:
print(f"intake error: {exc}", file=sys.stderr)
return 2
if polled is None:
print(json.dumps({"ok": True, "queue": "empty"}, indent=2))
return 0
issue, spec = polled
issue_id = issue.issue_id
else:
if not args.task_file:
print(
"error: provide --task-file or --from-issue-core",
file=sys.stderr,
)
return 2
try:
spec = TaskSpec.from_file(args.task_file)
except (TaskSpecError, OSError, json.JSONDecodeError) as exc:
print(f"invalid task spec: {exc}", file=sys.stderr)
return 2
result = run_task(
spec,
report_to_hub=not args.no_hub,
write_metrics=not args.no_metrics,
)
closed = False
close_error = ""
if client is not None and issue_id:
try:
if result.ok:
client.close(issue_id)
closed = True
else:
client.reopen(issue_id)
except IntakeError as exc:
close_error = str(exc)
print(
json.dumps(
{
"ok": result.ok,
"committed": result.committed,
"head_after": result.head_after,
"persona_source": result.persona_source,
"tool_profile": result.tool_profile,
"budget_tokens": result.budget_tokens,
"tokens_spent": result.tokens_spent,
"execution_time_s": round(result.execution_time_s, 3),
"reason": result.reason,
"issue_id": issue_id,
"issue_closed": closed,
"issue_close_error": close_error,
},
indent=2,
)
)
return 0 if result.ok else 1
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(prog="agent-harness")
sub = parser.add_subparsers(dest="command", required=True)
run = sub.add_parser("run", help="Execute one task from a JSON spec file")
run.add_argument("--task-file", required=True)
run = sub.add_parser(
"run",
help="Execute one task from a JSON file or next issue-core emission",
)
run_src = run.add_mutually_exclusive_group(required=True)
run_src.add_argument("--task-file", help="Local JSON task-spec (dev path)")
run_src.add_argument(
"--from-issue-core",
action="store_true",
help="Poll issue-core for one open harness-labeled task, claim, run, close",
)
run.add_argument("--no-hub", action="store_true", help="Skip hub reporting")
run.add_argument(
"--no-metrics",
@ -127,6 +238,16 @@ def main(argv: list[str] | None = None) -> int:
smoke.add_argument("--no-hub", action="store_true", help="Skip hub reporting")
smoke.add_argument("--no-push", action="store_true", help="Skip git push after commit")
poll = sub.add_parser(
"poll",
help="Peek/claim next open issue-core task labeled for the harness (no execute)",
)
poll.add_argument(
"--no-claim",
action="store_true",
help="List/map only; do not set in_progress",
)
args = parser.parse_args(argv)
if args.command == "validate":
@ -135,6 +256,12 @@ def main(argv: list[str] | None = None) -> int:
if args.command == "profiles":
return _cmd_profiles(args)
if args.command == "poll":
return _cmd_poll(args)
if args.command == "run":
return _cmd_run(args)
if args.command == "smoke":
from agent_harness.smoke import ensure_sandbox_clone, run_smoke
@ -201,34 +328,8 @@ def main(argv: list[str] | None = None) -> int:
)
return 0 if result.ok else 1
try:
spec = TaskSpec.from_file(args.task_file)
except (TaskSpecError, OSError, json.JSONDecodeError) as exc:
print(f"invalid task spec: {exc}", file=sys.stderr)
return 2
result = run_task(
spec,
report_to_hub=not args.no_hub,
write_metrics=not args.no_metrics,
)
print(
json.dumps(
{
"ok": result.ok,
"committed": result.committed,
"head_after": result.head_after,
"persona_source": result.persona_source,
"tool_profile": result.tool_profile,
"budget_tokens": result.budget_tokens,
"tokens_spent": result.tokens_spent,
"execution_time_s": round(result.execution_time_s, 3),
"reason": result.reason,
},
indent=2,
)
)
return 0 if result.ok else 1
print(f"unknown command: {args.command}", file=sys.stderr)
return 2
if __name__ == "__main__":