jade-code-api / tools.py
Madras1's picture
Upload 5 files
43986ce verified
"""
Jade Code IDE - Agentic Tools
Ferramentas que o LLM pode usar para explorar o projeto
"""
from typing import Dict, List, Any, Optional
# === Tool Definitions (OpenAI format) ===
AGENT_TOOLS = [
{
"type": "function",
"function": {
"name": "list_files",
"description": "Lista todos os arquivos do projeto do usuário. Use para entender a estrutura do projeto.",
"parameters": {
"type": "object",
"properties": {},
"required": []
}
}
},
{
"type": "function",
"function": {
"name": "read_file",
"description": "Lê o conteúdo de um arquivo específico do projeto.",
"parameters": {
"type": "object",
"properties": {
"filename": {
"type": "string",
"description": "Nome do arquivo para ler (ex: 'utils.py', 'README.md')"
}
},
"required": ["filename"]
}
}
},
{
"type": "function",
"function": {
"name": "search_code",
"description": "Busca um texto em todos os arquivos do projeto.",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Texto ou padrão para buscar nos arquivos"
}
},
"required": ["query"]
}
}
}
]
class ToolExecutor:
"""Executa ferramentas do agente usando os arquivos fornecidos pelo frontend."""
def __init__(self, files: Dict[str, str]):
"""
Args:
files: Dicionário {filename: content} com os arquivos do projeto
"""
self.files = files or {}
def execute(self, tool_name: str, args: Dict[str, Any]) -> str:
"""Executa uma ferramenta e retorna o resultado como string."""
if tool_name == "list_files":
return self._list_files()
elif tool_name == "read_file":
return self._read_file(args.get("filename", ""))
elif tool_name == "search_code":
return self._search_code(args.get("query", ""))
else:
return f"❌ Ferramenta desconhecida: {tool_name}"
def _list_files(self) -> str:
"""Lista arquivos do projeto."""
if not self.files:
return "📁 Nenhum arquivo no projeto."
file_list = []
for name, content in self.files.items():
lines = content.count('\n') + 1 if content else 0
size = len(content)
file_list.append(f" 📄 {name} ({lines} linhas, {size} bytes)")
return f"📁 Arquivos do projeto ({len(self.files)}):\n" + "\n".join(file_list)
def _read_file(self, filename: str) -> str:
"""Lê conteúdo de um arquivo."""
if not filename:
return "❌ Nome do arquivo não especificado."
content = self.files.get(filename)
if content is None:
available = ", ".join(self.files.keys()) if self.files else "nenhum"
return f"❌ Arquivo '{filename}' não encontrado. Disponíveis: {available}"
# Limita tamanho pra não estourar contexto
if len(content) > 5000:
content = content[:5000] + f"\n\n... [truncado, {len(content)} bytes total]"
return f"📄 Conteúdo de '{filename}':\n```\n{content}\n```"
def _search_code(self, query: str) -> str:
"""Busca texto nos arquivos."""
if not query:
return "❌ Query de busca não especificada."
query_lower = query.lower()
results = []
for filename, content in self.files.items():
lines = content.split('\n')
for i, line in enumerate(lines, 1):
if query_lower in line.lower():
# Mostra contexto
snippet = line.strip()[:100]
results.append(f" {filename}:{i}{snippet}")
if not results:
return f"🔍 Nenhum resultado para '{query}'."
return f"🔍 Resultados para '{query}' ({len(results)} encontrados):\n" + "\n".join(results[:20])
def parse_tool_calls(response: Dict) -> List[Dict]:
"""Extrai tool calls da resposta do LLM."""
choices = response.get("choices", [])
if not choices:
return []
message = choices[0].get("message", {})
tool_calls = message.get("tool_calls", [])
parsed = []
for tc in tool_calls:
try:
import json
parsed.append({
"id": tc.get("id"),
"name": tc.get("function", {}).get("name"),
"args": json.loads(tc.get("function", {}).get("arguments", "{}"))
})
except:
pass
return parsed
def get_response_content(response: Dict) -> Optional[str]:
"""Extrai o conteúdo de texto da resposta."""
choices = response.get("choices", [])
if not choices:
return None
message = choices[0].get("message", {})
return message.get("content")
def has_tool_calls(response: Dict) -> bool:
"""Verifica se a resposta contém tool calls."""
choices = response.get("choices", [])
if not choices:
return False
message = choices[0].get("message", {})
tool_calls = message.get("tool_calls", [])
return len(tool_calls) > 0