Spaces:
Sleeping
Sleeping
| """ | |
| 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 | |