""" 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