Files
agent1/cli.py
T
sylvain 305999d8bf Orchestration complète : planning, scheduling, CLI
- agent1.py : listener MQTT (agents/agent1/inbox), MAX_STEPS 10
- skills/plan.py : exécution séquentielle PLAN: avec contexte entre étapes
- skills/schedule_tasks.py : SCHEDULE: / PLAN_LIST: / PLAN_CANCEL: via APScheduler
- cli.py : interface CLI rich (MQTT, multi-agents, /plans, /agent)
- system_prompt.txt : mis à jour avec tous les nouveaux skills

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 13:13:42 +00:00

170 lines
6.0 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
CLI pour interagir avec les agents via MQTT.
Usage :
python3 cli.py # parle à agent1
python3 cli.py agent2_debian13 # parle directement à un agent
python3 cli.py --plans # voir les tâches planifiées
"""
import sys
import json
import time
import threading
import argparse
from pathlib import Path
import paho.mqtt.client as mqtt
from rich.console import Console
from rich.panel import Panel
from rich.prompt import Prompt
from rich.live import Live
from rich.spinner import Spinner
from rich.text import Text
from rich.rule import Rule
from rich import print as rprint
# ── CONFIG ──────────────────────────────────────────────────────────────
CONFIG_FILE = Path("/opt/agent/config/config.json")
REGISTRY_FILE = Path("/opt/agent/config/agents_registry.json")
cfg = json.loads(CONFIG_FILE.read_text())
MQTT_HOST = cfg.get("mqtt_host", "localhost")
MQTT_PORT = int(cfg.get("mqtt_port", 1883))
AGENT_INBOXES = {
"agent1": "agents/agent1/inbox",
}
try:
registry = json.loads(REGISTRY_FILE.read_text())
for name, info in registry.items():
AGENT_INBOXES[name] = info["mqtt_inbox"]
except Exception:
pass
CLI_OUTBOX = "agents/cli/outbox"
console = Console()
# ── MQTT ────────────────────────────────────────────────────────────────
response_event = threading.Event()
response_container = []
pub_client = None
sub_client = None
def on_message(client, userdata, msg):
response_container.clear()
response_container.append(msg.payload.decode(errors="replace"))
response_event.set()
def connect_mqtt():
global pub_client, sub_client
pub_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="cli_pub")
pub_client.connect(MQTT_HOST, MQTT_PORT)
pub_client.loop_start()
sub_client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="cli_sub")
sub_client.on_message = on_message
sub_client.connect(MQTT_HOST, MQTT_PORT)
sub_client.subscribe(CLI_OUTBOX)
sub_client.loop_start()
def send_and_wait(agent: str, message: str, timeout: int = 180) -> str:
inbox = AGENT_INBOXES.get(agent)
if not inbox:
return "[Erreur] Agent inconnu : {}. Disponibles : {}".format(
agent, ", ".join(AGENT_INBOXES.keys()))
payload = json.dumps({"task": message, "reply_to": CLI_OUTBOX, "from": "cli"})
response_event.clear()
pub_client.publish(inbox, payload)
received = response_event.wait(timeout=timeout)
if received and response_container:
return response_container[0]
return "[Timeout] Pas de réponse de {} après {}s.".format(agent, timeout)
# ── AFFICHAGE ────────────────────────────────────────────────────────────
def print_response(agent: str, response: str):
console.print(Panel(
response,
title="[bold cyan]{}[/bold cyan]".format(agent),
border_style="cyan",
padding=(1, 2)
))
def print_user(message: str):
console.print(Panel(
"[bold white]{}[/bold white]".format(message),
title="[bold green]vous[/bold green]",
border_style="green",
padding=(0, 2)
))
def show_plans():
"""Affiche les tâches planifiées via agent1."""
connect_mqtt()
with console.status("[bold yellow]Récupération des plans...[/bold yellow]"):
result = send_and_wait("agent1", "PLAN_LIST:", timeout=30)
print_response("agent1 / plans", result)
# ── BOUCLE PRINCIPALE ────────────────────────────────────────────────────
def main_loop(agent: str):
connect_mqtt()
console.print(Rule("[bold blue]Agent CLI[/bold blue]"))
console.print("[dim]Agent cible : [bold]{}[/bold] | /reset | /plans | /quit[/dim]\n".format(agent))
while True:
try:
user_input = Prompt.ask("[bold green]>[/bold green]").strip()
except (KeyboardInterrupt, EOFError):
console.print("\n[dim]Au revoir.[/dim]")
break
if not user_input:
continue
if user_input == "/quit":
console.print("[dim]Au revoir.[/dim]")
break
if user_input == "/reset":
send_and_wait(agent, "!reset", timeout=10)
console.print("[dim]Conversation réinitialisée.[/dim]")
continue
if user_input == "/plans":
with console.status("[bold yellow]Récupération...[/bold yellow]"):
result = send_and_wait("agent1", "PLAN_LIST:", timeout=30)
print_response("plans", result)
continue
if user_input.startswith("/agent "):
agent = user_input.split(" ", 1)[1].strip()
console.print("[dim]Agent changé : [bold]{}[/bold][/dim]".format(agent))
continue
print_user(user_input)
with console.status("[bold yellow]En attente de {}...[/bold yellow]".format(agent)):
response = send_and_wait(agent, user_input)
print_response(agent, response)
# ── MAIN ─────────────────────────────────────────────────────────────────
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="CLI agents MQTT")
parser.add_argument("agent", nargs="?", default="agent1",
help="Agent cible (défaut: agent1)")
parser.add_argument("--plans", action="store_true",
help="Afficher les tâches planifiées")
args = parser.parse_args()
if args.plans:
show_plans()
else:
main_loop(args.agent)