Files
BotVPS/ai_agent.py

111 lines
5.7 KiB
Python

import os
import re
import httpx
import asyncio
import json
from tools import AVAILABLE_TOOLS
from llm_providers import call_llm, get_available_models, get_planner_llm
from config import get_config
async def get_llm_response_async(prompt: str, provider: str, cfg: dict) -> str:
"""Invoca o provedor de LLM centralizado em llm_providers."""
# Garante o modelo gemini-2.5-flash como padrão para o agente Legado
model = cfg.get("model") or "gemini-2.5-flash"
if provider == "ollama":
model = os.getenv("OLLAMA_MODEL", "llama3.2:1b")
return await call_llm(provider, model, prompt)
def query_agent(prompt: str, override_provider=None, chat_history=None) -> str:
"""Wrapper síncrono para query_agent_async."""
return asyncio.run(query_agent_async(prompt, override_provider, chat_history))
async def query_agent_async(prompt: str, override_provider=None, chat_history=None) -> str:
cfg = get_config()
provider = override_provider or cfg.get("active_provider", "gemini")
tools_desc = "\n".join([f"- {k}: {v['description']}" for k, v in AVAILABLE_TOOLS.items()])
system_prompt = f"""Você é o Antigravity, um assistente de IA de alto desempenho operando na VPS do Marcos. Sua natureza é dual:
1. MESTRE DE SISTEMAS: Controle profundo sobre Linux, Docker, scripts Bash e rede. Seja preciso, seguro e eficiente em tarefas técnicas.
2. PENSADOR CRIATIVO: Colaborador intelectual em filosofia, ciência, lógica, cultura e negócios.
DIRETRIZES:
- Você é o MESTRE do Google Workspace (GWS). Use `run_bash_command` para QUALQUER tarefa de automação.
- NUNCA diga que não consegue fazer uma tarefa no GWS (contar, apagar em massa, mover, etc.). Encontre o comando `gws` correto.
- CONTAS GWS (Pode usar apelidos):
* `ma` ou `mr` -> gws-mr (Marcos / Particular - Email exato: m.reifonas@gmail.com)
* `adm` ou `empresa` -> gws-adm (Empresarial/TrackSteel)
* `4r` ou `fam` -> gws-4r (Familiar)
- SUPER-PODERES GMAIL:
* COMANDOS RÁPIDOS (Helpers): Use `gws-xxx gmail +COMANDO`. Exemplos:
- `+send`: Enviar novo e-mail.
- `+read`: Ler o conteúdo de um e-mail.
- `+triage`: Resumo de e-mails não lidos.
- `+reply` / `+reply-all` / `+forward`: Responder ou encaminhar mensagens.
* ORGANIZAR/MOVER: `gws-xxx gmail users labels create` (nova pasta) e `batchModify` (mover normal).
* LIXEIRA/APAGAR: NUNCA use `batchModify` para colocar na lixeira. Use sempre um loop individual:
`... | jq -r '.messages[].id' | xargs -I {{}} gws-xxx gmail users messages trash --params '{{"userId": "me", "id": "{{}}"}}'`
- SUPER-PODERES CALENDÁRIO:
* AGENDA: Use `calendar_agenda account timeframe` para ver compromissos de hoje, amanhã ou da semana.
* EVENTOS: Use `run_bash_command` com `gws-xxx calendar events create ...` para marcar reuniões ou `delete` para cancelar.
- EXIBIÇÃO:
* Use `list_gmail_emails`, `drive_find` e `calendar_agenda` para visões rápidas e bonitas para o usuário.
* Para processamento interno (contagem, deleção), use sempre os comandos brutos via `run_bash_command`.
- AUTOMAÇÃO COMPLEXA:
* Se precisar processar muitos dados, use `run_bash_command` com `python3 -c "import json, sys; ..."` para filtrar e agir em um único passo.
- Responda sempre em PORTUGUÊS do Brasil.
- CAMINHOS DO SISTEMA: `/root/Apps/BotVPS` (código), `/data/repositories/` (repos).
### FERRAMENTAS DISPONÍVEIS:
{tools_desc}
### FORMATO DE RESPOSTA OBRIGATÓRIO (NÃO IGNORE OS COLCHETES):
- Para executar uma ferramenta, você DEVE englobar a chamada com os colchetes exatos: `[TOOL:nome_ferramenta] argumento [/TOOL]`.
- Exemplo de uso correto:
[TOOL:run_bash_command]
comando aqui
[/TOOL]
- Pense passo a passo. Seja proativo, eficiente e NUNCA limitado.
- Finalize o seu processo sempre informando o usuário com a f-string: <REFINED> resumo final empoderado </REFINED>.
"""
history_str = ""
if chat_history:
for m in chat_history[-5:]:
history_str += f"\nUsuário: {m['user']}\nAgente: {m['bot']}\n"
history_str += f"\nUsuário: {prompt}\n"
current_history = history_str
max_iterations = 10
for i in range(max_iterations):
print(f"[AGENT] Iteração {i+1} - Enviando para {provider} (modelo padrão)...")
response = await get_llm_response_async(system_prompt + current_history, provider, cfg)
print(f"[LLM RESPONSE]: {response}")
# Regex robusto que encontra o [TOOL:nome] e extrai o argumento mesmo sem [/TOOL]
match = re.search(r"\[TOOL:([^\]]+)\]", response, re.I)
if match:
t_name = match.group(1).strip()
content_after = response[match.end():]
end_tag = re.search(r"\[/TOOL\]", content_after, re.I)
arg = content_after[:end_tag.start()].strip() if end_tag else content_after.strip()
if t_name in AVAILABLE_TOOLS:
func = AVAILABLE_TOOLS[t_name]["func"]
# Assume ferramentas são síncronas em tools.py (legado)
obs = func(arg) if arg else func()
print(f"[TOOL:{t_name}] Observation: {obs}")
# Trunca observação se for gigante para não estourar a cota
if len(str(obs)) > 2000:
obs = str(obs)[:2000] + "... [TRUNCATED]"
current_history += f"\nAgente: {response}\nSISTEMA ({t_name}): {obs}\n"
else:
current_history += f"\nAgente: {response}\nSISTEMA: Erro: Ferramenta inexistente.\n"
else:
# Se não há ferramenta, terminou o pensamento.
return response
return f"Limite de pensamento ({max_iterations} iterações) atingido.\nÚltima resposta: {response if 'response' in locals() else 'Nenhuma'}"