114 lines
4.1 KiB
Python
114 lines
4.1 KiB
Python
|
|
"""CLI entry point: python -m argus [options]"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
import asyncio
|
||
|
|
import json
|
||
|
|
import logging
|
||
|
|
import sys
|
||
|
|
|
||
|
|
from argus.config import CAPTURE_INTERVAL_S
|
||
|
|
from argus.loop import run_loop
|
||
|
|
from argus.vlm import StepInfo, TaskContext
|
||
|
|
|
||
|
|
|
||
|
|
def _parse_args() -> argparse.Namespace:
|
||
|
|
p = argparse.ArgumentParser(
|
||
|
|
prog="argus",
|
||
|
|
description="Argus VLM — proactive focus assistant screen analyzer",
|
||
|
|
)
|
||
|
|
p.add_argument("--session-id", default="00000000-0000-0000-0000-000000000000")
|
||
|
|
p.add_argument("--task-title", default="(no task)")
|
||
|
|
p.add_argument("--task-goal", default="")
|
||
|
|
p.add_argument(
|
||
|
|
"--steps-json",
|
||
|
|
default=None,
|
||
|
|
help='JSON array of steps: [{"id":"...", "sort_order":1, "title":"...", "status":"pending"}]',
|
||
|
|
)
|
||
|
|
p.add_argument("--window-title", default="")
|
||
|
|
p.add_argument("--vlm", choices=["ollama", "gemini"], default=None, help="VLM backend (default: ollama)")
|
||
|
|
p.add_argument("--gemini-key", default=None, help="Override GEMINI_API_KEY env var")
|
||
|
|
p.add_argument("--jwt", default=None, help="Override BACKEND_JWT env var")
|
||
|
|
p.add_argument("--backend-url", default=None, help="Override BACKEND_BASE_URL env var")
|
||
|
|
p.add_argument("--dry-run", action="store_true", help="Print JSON instead of POSTing")
|
||
|
|
p.add_argument("--execute", action="store_true", help="Enable notification + executor flow")
|
||
|
|
p.add_argument("--mock-sessions", default=None, help='JSON array of mock sessions: [{"task_title":"...", "status":"interrupted", "last_app":"VS Code", "last_file":"solution.cpp", "checkpoint_note":"stuck on impl"}]')
|
||
|
|
p.add_argument("--iterations", type=int, default=None, help="Stop after N iterations")
|
||
|
|
p.add_argument("-v", "--verbose", action="store_true")
|
||
|
|
return p.parse_args()
|
||
|
|
|
||
|
|
|
||
|
|
def main() -> None:
|
||
|
|
args = _parse_args()
|
||
|
|
|
||
|
|
logging.basicConfig(
|
||
|
|
level=logging.DEBUG if args.verbose else logging.INFO,
|
||
|
|
format="%(asctime)s %(levelname)-5s %(name)s %(message)s",
|
||
|
|
datefmt="%H:%M:%S",
|
||
|
|
)
|
||
|
|
# httpx logs every request/response at INFO — suppress to WARNING to avoid noisy 404s
|
||
|
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||
|
|
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
||
|
|
|
||
|
|
steps: list[StepInfo] = []
|
||
|
|
if args.steps_json:
|
||
|
|
for s in json.loads(args.steps_json):
|
||
|
|
steps.append(
|
||
|
|
StepInfo(
|
||
|
|
id=s["id"],
|
||
|
|
sort_order=s["sort_order"],
|
||
|
|
title=s["title"],
|
||
|
|
status=s.get("status", "pending"),
|
||
|
|
checkpoint_note=s.get("checkpoint_note"),
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
ctx = TaskContext(
|
||
|
|
task_title=args.task_title,
|
||
|
|
task_goal=args.task_goal,
|
||
|
|
steps=steps,
|
||
|
|
window_title=args.window_title,
|
||
|
|
session_id=args.session_id,
|
||
|
|
)
|
||
|
|
|
||
|
|
# Parse mock sessions if provided
|
||
|
|
mock_sessions = None
|
||
|
|
if args.mock_sessions:
|
||
|
|
from argus.session import SessionInfo
|
||
|
|
mock_sessions = []
|
||
|
|
for i, s in enumerate(json.loads(args.mock_sessions)):
|
||
|
|
mock_sessions.append(
|
||
|
|
SessionInfo(
|
||
|
|
session_id=s.get("session_id", f"mock-{i}"),
|
||
|
|
task_id=s.get("task_id"),
|
||
|
|
task_title=s.get("task_title", ""),
|
||
|
|
task_goal=s.get("task_goal", ""),
|
||
|
|
status=s.get("status", "interrupted"),
|
||
|
|
last_app=s.get("last_app", ""),
|
||
|
|
last_file=s.get("last_file", ""),
|
||
|
|
checkpoint_note=s.get("checkpoint_note", ""),
|
||
|
|
started_at=s.get("started_at", ""),
|
||
|
|
ended_at=s.get("ended_at"),
|
||
|
|
minutes_ago=s.get("minutes_ago", 30),
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
asyncio.run(
|
||
|
|
run_loop(
|
||
|
|
ctx,
|
||
|
|
api_key=args.gemini_key,
|
||
|
|
vlm_backend=args.vlm,
|
||
|
|
jwt=args.jwt,
|
||
|
|
base_url=args.backend_url,
|
||
|
|
dry_run=args.dry_run,
|
||
|
|
max_iterations=args.iterations,
|
||
|
|
auto_execute=args.execute,
|
||
|
|
mock_sessions=mock_sessions,
|
||
|
|
)
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|