"""CLI entry point for the Minimal Viable Agent — Stage 1.""" from __future__ import annotations import argparse import sys import uuid from pathlib import Path # Ensure the agent/ directory is on sys.path so imports work sys.path.insert(0, str(Path(__file__).parent)) from core.controller import run_agent from core.state import RunStatus, StepStatus WORKSPACE_ROOT = Path(__file__).parent / "workspace" def main() -> None: import os import sys parser = argparse.ArgumentParser( description="Minimal Viable Agent — Stage 1", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" examples: python main.py --goal "inspect project" python main.py --goal "create file hello.txt with text hello world" python main.py --goal "проверь что тут есть" """, ) parser.add_argument("--goal", required=True, help="Goal for the agent to accomplish") parser.add_argument("--run-id", default=None, help="Optional run ID (auto-generated if omitted)") parser.add_argument("--trace-id", default=None, help="Trace ID for cross-layer observability") args = parser.parse_args() run_id = args.run_id or str(uuid.uuid4())[:8] print(f"[agent] run_id : {run_id}") print(f"[agent] workspace: {WORKSPACE_ROOT / 'runs' / run_id}") print() # Safe printing with encoding fallback (defined early for logging) def safe_print(text: str, indent: int = 0) -> None: """Print text safely by replacing unencodable characters.""" try: print(f"{' ' * indent}{text}") except UnicodeEncodeError: # Replace characters that can't be encoded cleaned = text.encode(sys.stdout.encoding or 'utf-8', errors='replace').decode(sys.stdout.encoding or 'utf-8') print(f"{' ' * indent}{cleaned}") # === AGENT EXECUTION LOGGING START === safe_print("=== AGENT START ===") safe_print(f"GOAL: {args.goal}") print() state = run_agent(run_id=run_id, goal=args.goal, workspace_root=WORKSPACE_ROOT, trace_id=args.trace_id) # === AFTER PLANNER LOGGING === safe_print("=== AFTER PLANNER ===") try: print(f"Plan steps: {len(state.plan.steps)}") for step in state.plan.steps: print(f" - {step.step_id}: {step.kind} - {step.description}") except Exception as e: print(f"Error accessing plan: {e}") print() # === STEPS EXECUTION LOGGING === safe_print("=== STEPS EXECUTION ===") try: for step in state.plan.steps: step_result = next((r for r in state.history if r.step_id == step.step_id), None) if step_result: status = "DONE" if step_result.status == StepStatus.DONE else "FAILED" print(f" {step.step_id}: {step.kind} - {status}") else: print(f" {step.step_id}: {step.kind} - NOT EXECUTED") except Exception as e: print(f"Error accessing steps: {e}") print() # === AGENT EXECUTION LOGGING END === safe_print("=== AGENT END ===") print() # Print results total = len(state.plan.steps) done = sum(1 for s in state.plan.steps if s.status == StepStatus.DONE) failed = sum(1 for s in state.plan.steps if s.status == StepStatus.FAILED) print(f"[agent] status : {state.status.value.upper()}") print(f"[agent] steps : {done} done, {failed} failed, {total} total") print() for result in state.history: step = next((s for s in state.plan.steps if s.step_id == result.step_id), None) kind = step.kind if step else "?" icon = "[ok]" if result.status == StepStatus.DONE else "[!]" safe_print(f"{icon} {result.step_id} ({kind})") if result.output_text: for line in result.output_text.rstrip().splitlines(): safe_print(line, indent=6) if result.error: safe_print(f"ERROR: {result.error}", indent=6) print() sys.exit(0 if state.status == RunStatus.DONE else 1) if __name__ == "__main__": main()