"""One-task run orchestration. Flow: lock target repo → resolve tool profile / budget from instance manifest → snapshot HEAD → persona bundle → prompt → agentic session → verify a new commit exists → kaizen metrics + hub progress event (+ task close). The run *fails* if the session pushed anywhere or left the repo dirty in a way it should not — the worker never pushes; publishing is a separate, explicitly-granted lane. """ from __future__ import annotations import subprocess import time from dataclasses import dataclass from pathlib import Path from agent_harness import hub, metrics from agent_harness.manifest import resolve_run_policy from agent_harness.persona import load_persona_bundle from agent_harness.profiles import UnknownToolProfileError, get_profile from agent_harness.taskspec import TaskSpec PROMPT_TEMPLATE = """\ You are an unattended executor session (agent persona below, if any). Operating rules, non-negotiable: - Work ONLY inside the current repository working directory. - Green/Blue lane: file edits and local git add/commit only. Never push, never touch the network, never run destructive commands. - Tool profile for this run: {tool_profile} (lane={lane}). - Bounded effort: complete the single task below, commit with a clear message, then stop. If the task cannot be completed, commit nothing and say why in your final output. {persona} ## Task: {title} {description} """ @dataclass class RunResult: ok: bool committed: bool head_before: str head_after: str persona_source: str session_output: str reason: str = "" tool_profile: str = "" budget_tokens: int | None = None tokens_spent: int | None = None execution_time_s: float = 0.0 def _git(repo: Path, *args: str) -> str: result = subprocess.run( ["git", "-C", str(repo), *args], capture_output=True, text=True, timeout=60, ) if result.returncode != 0: raise RuntimeError(f"git {' '.join(args)} failed: {result.stderr.strip()}") return result.stdout.strip() def run_task( spec: TaskSpec, adapter=None, report_to_hub: bool = True, write_metrics: bool = True, ) -> RunResult: try: profile_name, budget_tokens, lane, blueprint = resolve_run_policy( spec.target_repo, spec.agent ) profile = get_profile(profile_name) except UnknownToolProfileError as exc: return RunResult( ok=False, committed=False, head_before="", head_after="", persona_source="none", session_output="", reason=f"refused: {exc}", tool_profile="", budget_tokens=None, ) except Exception as exc: return RunResult( ok=False, committed=False, head_before="", head_after="", persona_source="none", session_output="", reason=f"manifest resolution failed: {exc}", tool_profile="", budget_tokens=None, ) if adapter is None: from agent_harness.adapter import AgenticClaudeCodeAdapter adapter = AgenticClaudeCodeAdapter( workdir=spec.target_repo, tool_profile=profile, ) head_before = _git(spec.target_repo, "rev-parse", "HEAD") persona, persona_source = load_persona_bundle(blueprint, spec.target_repo) prompt = PROMPT_TEMPLATE.format( persona=persona or "(no persona bundle available for this run)", title=spec.title, description=spec.description, tool_profile=profile.name, lane=lane or profile.lane, ) from llm_connect.models import BudgetTracker, RunConfig budget_tracker = BudgetTracker(total=budget_tokens) if budget_tokens else None config = RunConfig( timeout_seconds=spec.timeout_seconds, skip_if_exists=False, budget_tracker=budget_tracker, ) started = time.monotonic() try: response = adapter.execute_prompt(prompt, config) session_output = response.content session_ok = True reason = "" except Exception as exc: # adapter / budget failures must still be reported session_output = "" session_ok = False reason = f"session failed: {exc}" execution_time_s = time.monotonic() - started head_after = _git(spec.target_repo, "rev-parse", "HEAD") committed = head_after != head_before ok = session_ok and committed if session_ok and not committed: reason = "session completed without committing" tokens_spent = budget_tracker.spent if budget_tracker is not None else None result = RunResult( ok=ok, committed=committed, head_before=head_before, head_after=head_after, persona_source=persona_source, session_output=session_output, reason=reason, tool_profile=profile.name, budget_tokens=budget_tokens, tokens_spent=tokens_spent, execution_time_s=execution_time_s, ) if write_metrics: try: metrics.record_execution( spec.target_repo, spec.agent, success=ok, execution_time_s=execution_time_s, tokens=tokens_spent, committed=committed, head_after=head_after, reason=reason or None, metadata={ "task_title": spec.title, "tool_profile": profile.name, "labels": list(spec.labels), "completion_event_type": spec.completion_event_type, }, ) except OSError: pass # metrics must not block run completion reporting if report_to_hub: detail = { "repo": spec.target_repo.name, "task_title": spec.title, "agent": spec.agent, "labels": spec.labels, "persona_source": persona_source, "committed": committed, "head_after": head_after, "ok": ok, "reason": reason, "tool_profile": profile.name, "budget_tokens": budget_tokens, "tokens_spent": tokens_spent, "execution_time_s": round(execution_time_s, 3), } hub.post_progress_event( summary=f"executor run: {spec.title} ({'ok' if ok else 'failed'})", event_type=spec.completion_event_type, detail=detail, task_id=spec.hub_task_id, ) if tokens_spent is not None or budget_tokens is not None: hub.post_token_event( repo=spec.target_repo.name, tokens=tokens_spent or 0, budget=budget_tokens, agent=spec.agent, ok=ok, detail={"task_title": spec.title, "tool_profile": profile.name}, ) if ok and spec.hub_task_id: hub.close_task(spec.hub_task_id) return result