052591281d
- Complete agent system with planning and execution - Bridge API with FastAPI server - WhatsApp-style mobile dashboard - Enhanced web search with query improvement - Security guards and policy checks - Comprehensive documentation
114 lines
4.0 KiB
Python
114 lines
4.0 KiB
Python
"""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()
|