feat: Auto-detect repository paths for any app
- Add detect_git_repo_path() function to find repos in /data/repositories - Add detect_app_in_docker() to find containers by name - Planner now receives detected context automatically - Supports BotVPS, TrackSteel, and any repo in /data/repositories - Uses 'docker compose' (space) syntax Example: 'faz deploy do tracksteel' will detect TrackSteel repo path automatically
This commit is contained in:
108
orchestrator.py
108
orchestrator.py
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import re
|
import re
|
||||||
|
import os
|
||||||
from typing import Dict, List, Optional
|
from typing import Dict, List, Optional
|
||||||
from llm_providers import (
|
from llm_providers import (
|
||||||
call_planner, call_executor, get_planner_llm, get_executor_llm,
|
call_planner, call_executor, get_planner_llm, get_executor_llm,
|
||||||
@@ -20,24 +21,22 @@ from credential_manager import sync_credentials, get_services_status
|
|||||||
PLANNER_SYSTEM_PROMPT = """Você é o PLANNER AGENT do BotVPS.
|
PLANNER_SYSTEM_PROMPT = """Você é o PLANNER AGENT do BotVPS.
|
||||||
Seu trabalho é decompor tarefas em passos executáveis CORRETOS.
|
Seu trabalho é decompor tarefas em passos executáveis CORRETOS.
|
||||||
|
|
||||||
### CAMINHO DO REPOSITÓRIO:
|
### REPOSITORIOS CONHECIDOS:
|
||||||
O repositório BotVPS está em: /data/applications/bw1erd9ww5121i1fsh420bcj
|
- BotVPS: /data/applications/bw1erd9ww5121i1fsh420bcj
|
||||||
O repositório Git está em: /data/repositories/0/5/5adtracksteel/AdmTrackSteel
|
- TrackSteel: /data/repositories/0/5/5adtracksteel/AdmTrackSteel
|
||||||
|
|
||||||
|
{CONTEXT_INFO}
|
||||||
|
|
||||||
### REGRAS CRÍTICAS DE COMANDOS:
|
### REGRAS CRÍTICAS DE COMANDOS:
|
||||||
1. USE SEMPRE "docker compose" (COM ESPAÇO), NUNCA "docker-compose" (COM HÍFEN)
|
1. USE SEMPRE "docker compose" (COM ESPAÇO), NUNCA "docker-compose" (COM HÍFEN)
|
||||||
2. Para git, use o caminho ABSOLUTO completo do repositório
|
2. Para git, use o caminho ABSOLUTO completo do repositório
|
||||||
3. Para docker compose, use "cd /caminho && docker compose up -d"
|
3. Para docker compose, use "cd /caminho && docker compose up -d"
|
||||||
|
4. Se não souber o caminho, use: find /data/repositories -name '*.git' -type d
|
||||||
|
|
||||||
### EXEMPLOS DE COMANDOS CORRETOS:
|
### EXEMPLOS DE COMANDOS CORRETOS:
|
||||||
✅ CORRETO: cd /data/applications/bw1erd9ww5121i1fsh420bcj && git pull origin master
|
✅ CORRETO: cd /repo/path && git pull origin master
|
||||||
❌ ERRADO: git -C /BotVPS pull
|
✅ CORRETO: cd /repo/path && docker compose up -d --build
|
||||||
|
✅ CORRETO: docker restart nome-do-container
|
||||||
✅ CORRETO: cd /data/applications/bw1erd9ww5121i1fsh420bcj && docker compose up -d --build
|
|
||||||
❌ ERRADO: docker-compose up -d
|
|
||||||
|
|
||||||
✅ CORRETO: cd /data/applications/bw1erd9ww5121i1fsh420bcj && docker compose down
|
|
||||||
❌ ERRADO: docker-compose down
|
|
||||||
|
|
||||||
### NÍVEIS DE PERIGO:
|
### NÍVEIS DE PERIGO:
|
||||||
- SAFE: listar, ver status, ler logs
|
- SAFE: listar, ver status, ler logs
|
||||||
@@ -104,6 +103,78 @@ def _format_tools_for_prompt() -> str:
|
|||||||
lines.append(f"- {name}: {info['desc']} [{info['danger']}]")
|
lines.append(f"- {name}: {info['desc']} [{info['danger']}]")
|
||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def detect_git_repo_path(task: str) -> str:
|
||||||
|
"""
|
||||||
|
Detecta automaticamente o caminho do repositório Git baseado na tarefa.
|
||||||
|
Retorna o caminho do repositório mais provável.
|
||||||
|
"""
|
||||||
|
from tools_v2 import run_bash
|
||||||
|
|
||||||
|
# Normaliza o texto da tarefa
|
||||||
|
task_lower = task.lower()
|
||||||
|
|
||||||
|
# Lista de repositórios conhecidos no host
|
||||||
|
known_repos = [
|
||||||
|
"/data/repositories/0/5/5adtracksteel/AdmTrackSteel",
|
||||||
|
"/data/repositories/0/5/5adtracksteel/BotVPS",
|
||||||
|
"/data/applications/bw1erd9ww5121i1fsh420bcj",
|
||||||
|
"/data/coolify",
|
||||||
|
"/root",
|
||||||
|
"/app"
|
||||||
|
]
|
||||||
|
|
||||||
|
# Tenta detectar pelo nome mencionado na tarefa
|
||||||
|
if "tracksteel" in task_lower or "tracksteel" in task_lower:
|
||||||
|
return "/data/repositories/0/5/5adtracksteel/AdmTrackSteel"
|
||||||
|
if "botvps" in task_lower or "bot vps" in task_lower:
|
||||||
|
return "/data/applications/bw1erd9ww5121i1fsh420bcj"
|
||||||
|
if "coolify" in task_lower:
|
||||||
|
return "/data/coolify"
|
||||||
|
|
||||||
|
# Tenta encontrar repositório git válido
|
||||||
|
for repo_path in known_repos:
|
||||||
|
result = run_bash(f"test -d {repo_path}/.git && echo 'FOUND:{repo_path}' || true")
|
||||||
|
if result.get("success") and "FOUND:" in result.get("output", ""):
|
||||||
|
return result["output"].split("FOUND:")[1].strip()
|
||||||
|
|
||||||
|
# Procura em /data/repositories por repositórios git
|
||||||
|
result = run_bash("find /data/repositories -name '*.git' -type d 2>/dev/null | head -10")
|
||||||
|
if result.get("success") and result.get("output"):
|
||||||
|
# Retorna o primeiro repositório encontrado
|
||||||
|
first_repo = result["output"].split("\n")[0].replace("/.git", "")
|
||||||
|
return first_repo
|
||||||
|
|
||||||
|
# Fallback: retorna /app se existir
|
||||||
|
if os.path.exists("/app/.git"):
|
||||||
|
return "/app"
|
||||||
|
|
||||||
|
return "/"
|
||||||
|
|
||||||
|
def detect_app_in_docker(task: str) -> str:
|
||||||
|
"""
|
||||||
|
Detecta qual container/app o usuário quer interagir baseado na tarefa.
|
||||||
|
"""
|
||||||
|
from tools_v2 import run_bash
|
||||||
|
|
||||||
|
task_lower = task.lower()
|
||||||
|
|
||||||
|
# Lista containers e tenta match
|
||||||
|
result = run_bash("docker ps --format '{{.Names}}' 2>/dev/null")
|
||||||
|
if result.get("success"):
|
||||||
|
containers = result["output"].lower()
|
||||||
|
|
||||||
|
if "tracksteel" in task_lower:
|
||||||
|
if "tracksteel" in containers:
|
||||||
|
return "tracksteel"
|
||||||
|
if "botvps" in task_lower or "antigravity" in task_lower:
|
||||||
|
if "vps" in containers:
|
||||||
|
return "vps-ai-agent"
|
||||||
|
if "coolify" in task_lower:
|
||||||
|
if "coolify" in containers:
|
||||||
|
return "coolify"
|
||||||
|
|
||||||
|
return ""
|
||||||
|
|
||||||
def _parse_json_response(text: str) -> Optional[Dict]:
|
def _parse_json_response(text: str) -> Optional[Dict]:
|
||||||
"""Extrai JSON da resposta do LLM."""
|
"""Extrai JSON da resposta do LLM."""
|
||||||
# Tenta encontrar JSON no texto
|
# Tenta encontrar JSON no texto
|
||||||
@@ -152,7 +223,22 @@ def plan_task(task: str) -> Dict:
|
|||||||
provider, model = get_planner_llm()
|
provider, model = get_planner_llm()
|
||||||
print(f"[PLANNER] Using: {provider}/{model}")
|
print(f"[PLANNER] Using: {provider}/{model}")
|
||||||
|
|
||||||
|
# Detecta automaticamente informações do contexto
|
||||||
|
detected_repo = detect_git_repo_path(task)
|
||||||
|
detected_app = detect_app_in_docker(task)
|
||||||
|
|
||||||
|
print(f"[CONTEXT] Repo: {detected_repo}, App: {detected_app}")
|
||||||
|
|
||||||
|
# Contexto adicional para o planner
|
||||||
|
context_info = f"""
|
||||||
|
### CONTEXTO DETECTADO:
|
||||||
|
- Repositório mais provável: {detected_repo}
|
||||||
|
- Aplicação mais provável: {detected_app}
|
||||||
|
- Para descobrir o repositório correto, use: find /data/repositories -name '*.git' -type d 2>/dev/null
|
||||||
|
"""
|
||||||
|
|
||||||
system_prompt = PLANNER_SYSTEM_PROMPT.replace("{TOOLS_LIST}", _format_tools_for_prompt())
|
system_prompt = PLANNER_SYSTEM_PROMPT.replace("{TOOLS_LIST}", _format_tools_for_prompt())
|
||||||
|
system_prompt = system_prompt.replace("{CONTEXT_INFO}", context_info)
|
||||||
|
|
||||||
response = call_planner(task, system_prompt)
|
response = call_planner(task, system_prompt)
|
||||||
print(f"[RESPONSE] Planner response:\n{response[:500]}...")
|
print(f"[RESPONSE] Planner response:\n{response[:500]}...")
|
||||||
|
|||||||
Reference in New Issue
Block a user